mcp-scraper 0.3.40 → 0.3.44

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.
@@ -5489,7 +5489,7 @@ async function fetchWithKernel(url) {
5489
5489
  });
5490
5490
  await client2.browsers.deleteByID(kb.session_id).catch(() => {
5491
5491
  });
5492
- void recordKernelSession({ kernelSessionId: kb.session_id, source: "kernel_fetch", stealth: typeof kb.stealth === "boolean" ? kb.stealth : null, headlessSent: useHeadless ? true : null, proxyUsed: typeof kb.proxy_id === "string" ? Boolean(kb.proxy_id) : null, fallback: true, openedAtMs, closedAtMs: Date.now() });
5492
+ void recordKernelSession({ kernelSessionId: kb.session_id, source: "kernel_fetch", stealth: typeof kb.stealth === "boolean" ? kb.stealth : null, headlessSent: useHeadless, proxyUsed: typeof kb.proxy_id === "string" ? Boolean(kb.proxy_id) : null, fallback: true, openedAtMs, closedAtMs: Date.now() });
5493
5493
  }
5494
5494
  }
5495
5495
  var import_sdk, import_playwright;
@@ -10060,7 +10060,7 @@ function insufficientBalanceResponse(balanceMc, requiredMc) {
10060
10060
  topup_url: topupUrl
10061
10061
  };
10062
10062
  }
10063
- var MC_COSTS, MC_PER_BROWSER_MS, BROWSER_OPEN_MIN_BALANCE_MC, MC_PER_CREDIT, CREDIT_COST_CATALOG, CONCURRENCY_PRICE_ID, SUBSCRIPTION_TIERS, SUBSCRIPTION_TIER_BY_KEY, CONCURRENCY_SLOT_PRICE_USD, CONCURRENCY_SLOT_PRICE_CURRENCY, CONCURRENCY_SLOT_PRICE_INTERVAL, CONCURRENCY_SLOT_PRICE_LABEL, CONCURRENCY_SLOT_TERMINAL_COMMAND, FREE_SIGNUP_MC, MEMORY_FREE_QUOTA_BYTES, MEMORY_PLANS, MEMORY_PLAN_QUOTA, MEMORY_MARGIN_MULTIPLE, MEMORY_PRO_COST_BUDGET_USD, SCHEDULING_PLANS, LedgerOperation;
10063
+ var MC_COSTS, MC_PER_BROWSER_MS, BROWSER_OPEN_MIN_BALANCE_MC, MC_PER_CREDIT, CREDIT_COST_CATALOG, CONCURRENCY_PRICE_ID, SUBSCRIPTION_TIERS, SUBSCRIPTION_TIER_BY_KEY, CONCURRENCY_SLOT_PRICE_USD, CONCURRENCY_SLOT_PRICE_CURRENCY, CONCURRENCY_SLOT_PRICE_INTERVAL, CONCURRENCY_SLOT_PRICE_LABEL, CONCURRENCY_SLOT_TERMINAL_COMMAND, FREE_SIGNUP_MC, MEMORY_FREE_QUOTA_BYTES, MEMORY_PLANS, MEMORY_PLAN_QUOTA, MEMORY_MARGIN_MULTIPLE, MEMORY_PRO_COST_BUDGET_USD, SCHEDULING_PLANS, LedgerOperation, MEMORY_AI_MARGIN_MULTIPLE, MC_PER_USD;
10064
10064
  var init_rates = __esm({
10065
10065
  "src/api/rates.ts"() {
10066
10066
  "use strict";
@@ -10085,7 +10085,8 @@ var init_rates = __esm({
10085
10085
  instagram_media: 400,
10086
10086
  instagram_transcribe: 50,
10087
10087
  browser_minute: 12e3,
10088
- reddit_thread: 2e3
10088
+ reddit_thread: 2e3,
10089
+ video_analysis: 666667
10089
10090
  };
10090
10091
  MC_PER_BROWSER_MS = MC_COSTS.browser_minute / 6e4;
10091
10092
  BROWSER_OPEN_MIN_BALANCE_MC = 1e3;
@@ -10248,6 +10249,14 @@ var init_rates = __esm({
10248
10249
  credits: mcToCredits(MC_COSTS.reddit_thread),
10249
10250
  unit: "per thread",
10250
10251
  notes: "Captures a Reddit post and its comment tree. Charged on success; refunded if the thread cannot be retrieved."
10252
+ },
10253
+ {
10254
+ key: "video_analysis",
10255
+ label: "Video breakdown (frame-by-frame + transcript)",
10256
+ aliases: ["video_frame_analysis", "video breakdown", "video analysis", "analyze video"],
10257
+ credits: mcToCredits(MC_COSTS.video_analysis),
10258
+ unit: "per video",
10259
+ notes: "Full multi-lens video breakdown: samples up to 120 frames across a video (to 30 min), analyzes each with vision AI, transcribes the audio, then produces summary, pacing/energy, words-per-minute, topic outline, key points, hook analysis, visual style, and a how-to-replicate recipe with a quality-control pass. Flat $1 per video; refunded if the run fails."
10251
10260
  }
10252
10261
  ];
10253
10262
  CONCURRENCY_PRICE_ID = "price_1Ta1NRS8aAcsk3TGwsRnYbix";
@@ -10265,7 +10274,7 @@ var init_rates = __esm({
10265
10274
  CONCURRENCY_SLOT_PRICE_LABEL = "$5/month";
10266
10275
  CONCURRENCY_SLOT_TERMINAL_COMMAND = "npx -y -p mcp-scraper@latest mcp-scraper-cli billing concurrency checkout";
10267
10276
  FREE_SIGNUP_MC = 1e5;
10268
- MEMORY_FREE_QUOTA_BYTES = 1e8 * 1;
10277
+ MEMORY_FREE_QUOTA_BYTES = 1e7 * 1;
10269
10278
  MEMORY_PLANS = {
10270
10279
  "price_1TnMSTS8aAcsk3TGBgiwuvqL": { plan: "pro", label: "Pro", price_id: "price_1TnMSTS8aAcsk3TGBgiwuvqL", interval: "month", monthly_usd: 19, quota_bytes: 5e9 },
10271
10280
  "price_1TnMSTS8aAcsk3TGWBVU2agY": { plan: "pro", label: "Pro", price_id: "price_1TnMSTS8aAcsk3TGWBVU2agY", interval: "year", monthly_usd: 19, quota_bytes: 5e9 }
@@ -10320,8 +10329,14 @@ var init_rates = __esm({
10320
10329
  INSTAGRAM_TRANSCRIBE_REFUND: "instagram_transcribe_refund",
10321
10330
  BROWSER_SESSION: "browser_session",
10322
10331
  REDDIT_THREAD: "reddit_thread",
10323
- REDDIT_THREAD_REFUND: "reddit_thread_refund"
10332
+ REDDIT_THREAD_REFUND: "reddit_thread_refund",
10333
+ VIDEO_ANALYSIS: "video_analysis",
10334
+ VIDEO_ANALYSIS_REFUND: "video_analysis_refund",
10335
+ MEMORY_AI: "memory_ai",
10336
+ MEMORY_AI_REFUND: "memory_ai_refund"
10324
10337
  };
10338
+ MEMORY_AI_MARGIN_MULTIPLE = 3;
10339
+ MC_PER_USD = SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].credits_mc / SUBSCRIPTION_TIERS["price_1TmiHRS8aAcsk3TGwmSNfNIa"].monthly_usd;
10325
10340
  }
10326
10341
  });
10327
10342
 
@@ -11188,6 +11203,34 @@ var init_site_audit_routes = __esm({
11188
11203
  }
11189
11204
  });
11190
11205
 
11206
+ // src/api/internal-memory-routes.ts
11207
+ var import_hono2, internalMemoryApp;
11208
+ var init_internal_memory_routes = __esm({
11209
+ "src/api/internal-memory-routes.ts"() {
11210
+ "use strict";
11211
+ import_hono2 = require("hono");
11212
+ init_db();
11213
+ init_rates();
11214
+ internalMemoryApp = new import_hono2.Hono();
11215
+ internalMemoryApp.post("/ai-debit", async (c) => {
11216
+ const secret2 = c.req.header("x-internal-secret");
11217
+ if (!secret2 || secret2 !== process.env.INTERNAL_MEMORY_DEBIT_SECRET) {
11218
+ return c.json({ error: "unauthorized" }, 401);
11219
+ }
11220
+ const body = await c.req.json().catch(() => ({}));
11221
+ if (!body.identity || typeof body.costUsd !== "number" || body.costUsd < 0) {
11222
+ return c.json({ error: "invalid_request" }, 400);
11223
+ }
11224
+ const user = await getUserByEmail(body.identity.trim().toLowerCase());
11225
+ if (!user) return c.json({ ok: false, reason: "no_user" }, 200);
11226
+ const mc = Math.round(body.costUsd * MEMORY_AI_MARGIN_MULTIPLE * MC_PER_USD);
11227
+ if (mc <= 0) return c.json({ ok: true, mc: 0, balance_mc: null }, 200);
11228
+ const { ok, balance_mc } = await debitMc(user.id, mc, LedgerOperation.MEMORY_AI, `${body.source ?? "ai"}:${body.op ?? ""}`);
11229
+ return c.json({ ok, mc, balance_mc, insufficient: !ok }, 200);
11230
+ });
11231
+ }
11232
+ });
11233
+
11191
11234
  // src/youtube/schemas.ts
11192
11235
  var import_zod12, YouTubeHarvestOptionsSchema;
11193
11236
  var init_schemas2 = __esm({
@@ -13012,11 +13055,11 @@ ${chunks}` : ""}
13012
13055
  function fmtTs(secs) {
13013
13056
  return `${Math.floor(secs / 60)}:${String(Math.floor(secs % 60)).padStart(2, "0")}`;
13014
13057
  }
13015
- var import_hono2, youtubeApp;
13058
+ var import_hono3, youtubeApp;
13016
13059
  var init_youtube_routes = __esm({
13017
13060
  "src/api/youtube-routes.ts"() {
13018
13061
  "use strict";
13019
- import_hono2 = require("hono");
13062
+ import_hono3 = require("hono");
13020
13063
  init_db();
13021
13064
  init_rates();
13022
13065
  init_youtube_harvest();
@@ -13027,7 +13070,7 @@ var init_youtube_routes = __esm({
13027
13070
  init_api_auth();
13028
13071
  init_server_schemas();
13029
13072
  init_concurrency_gates();
13030
- youtubeApp = new import_hono2.Hono();
13073
+ youtubeApp = new import_hono3.Hono();
13031
13074
  youtubeApp.post("/harvest", createApiKeyAuth(), async (c) => {
13032
13075
  const raw = await c.req.json().catch(() => ({}));
13033
13076
  const parsed = YoutubeHarvestBodySchema.safeParse(raw);
@@ -13140,11 +13183,11 @@ var init_youtube_routes = __esm({
13140
13183
  });
13141
13184
 
13142
13185
  // src/api/screenshot-routes.ts
13143
- var import_hono3, import_zod14, ScreenshotBodySchema, screenshotApp;
13186
+ var import_hono4, import_zod14, ScreenshotBodySchema, screenshotApp;
13144
13187
  var init_screenshot_routes = __esm({
13145
13188
  "src/api/screenshot-routes.ts"() {
13146
13189
  "use strict";
13147
- import_hono3 = require("hono");
13190
+ import_hono4 = require("hono");
13148
13191
  init_browser_service_env();
13149
13192
  import_zod14 = require("zod");
13150
13193
  init_screenshot();
@@ -13158,7 +13201,7 @@ var init_screenshot_routes = __esm({
13158
13201
  device: import_zod14.z.string().trim().optional(),
13159
13202
  allowLocal: import_zod14.z.boolean().optional()
13160
13203
  });
13161
- screenshotApp = new import_hono3.Hono();
13204
+ screenshotApp = new import_hono4.Hono();
13162
13205
  screenshotApp.use("*", createApiKeyAuth());
13163
13206
  screenshotApp.post("/", async (c) => {
13164
13207
  const raw = await c.req.json().catch(() => ({}));
@@ -14865,11 +14908,11 @@ async function kernelLaunchOptsResidential() {
14865
14908
  }
14866
14909
  return { headless: true, kernelApiKey: browserServiceApiKey(), kernelProxyId: proxyId, viewport: { width: 1280, height: 900 }, locale: "en-US" };
14867
14910
  }
14868
- var import_hono4, import_zod16, import_client5, FacebookAdBodySchema, FacebookPageIntelBodySchema, FacebookTranscribeBodySchema, FacebookVideoTranscribeBodySchema, FacebookSearchBodySchema, FacebookMediaBodySchema, facebookAdApp, ALLOWED_MEDIA_HOSTS;
14911
+ var import_hono5, import_zod16, import_client5, FacebookAdBodySchema, FacebookPageIntelBodySchema, FacebookTranscribeBodySchema, FacebookVideoTranscribeBodySchema, FacebookSearchBodySchema, FacebookMediaBodySchema, facebookAdApp, ALLOWED_MEDIA_HOSTS;
14869
14912
  var init_facebook_ad_routes = __esm({
14870
14913
  "src/api/facebook-ad-routes.ts"() {
14871
14914
  "use strict";
14872
- import_hono4 = require("hono");
14915
+ import_hono5 = require("hono");
14873
14916
  init_browser_service_env();
14874
14917
  import_zod16 = require("zod");
14875
14918
  init_db();
@@ -14915,7 +14958,7 @@ var init_facebook_ad_routes = __esm({
14915
14958
  url: import_zod16.z.string().trim().min(1, "url is required"),
14916
14959
  filename: import_zod16.z.string().trim().optional()
14917
14960
  });
14918
- facebookAdApp = new import_hono4.Hono();
14961
+ facebookAdApp = new import_hono5.Hono();
14919
14962
  facebookAdApp.post("/ad", createApiKeyAuth(), async (c) => {
14920
14963
  const raw = await c.req.json().catch(() => ({}));
14921
14964
  const parsed = FacebookAdBodySchema.safeParse(raw);
@@ -15446,11 +15489,11 @@ async function kernelLaunchOptsResidential2() {
15446
15489
  function isBlockedMessage(msg) {
15447
15490
  return msg.toLowerCase().includes("blocked") || msg.toLowerCase().includes("captcha");
15448
15491
  }
15449
- var import_hono5, import_zod17, import_client6, GoogleAdsSearchBodySchema, GoogleAdsPageIntelBodySchema, GoogleAdsTranscribeBodySchema, googleAdsApp;
15492
+ var import_hono6, import_zod17, import_client6, GoogleAdsSearchBodySchema, GoogleAdsPageIntelBodySchema, GoogleAdsTranscribeBodySchema, googleAdsApp;
15450
15493
  var init_google_ads_routes = __esm({
15451
15494
  "src/api/google-ads-routes.ts"() {
15452
15495
  "use strict";
15453
- import_hono5 = require("hono");
15496
+ import_hono6 = require("hono");
15454
15497
  import_zod17 = require("zod");
15455
15498
  init_browser_service_env();
15456
15499
  init_db();
@@ -15478,7 +15521,7 @@ var init_google_ads_routes = __esm({
15478
15521
  GoogleAdsTranscribeBodySchema = import_zod17.z.object({
15479
15522
  videoUrl: import_zod17.z.string().trim().min(1, "videoUrl is required")
15480
15523
  });
15481
- googleAdsApp = new import_hono5.Hono();
15524
+ googleAdsApp = new import_hono6.Hono();
15482
15525
  googleAdsApp.post("/search", createApiKeyAuth(), async (c) => {
15483
15526
  const raw = await c.req.json().catch(() => ({}));
15484
15527
  const parsed = GoogleAdsSearchBodySchema.safeParse(raw);
@@ -16053,11 +16096,11 @@ function trackFilename(track, index, shortcode) {
16053
16096
  const bitrate = track.bitrate ? `-${track.bitrate}` : "";
16054
16097
  return `${label}-${type}-${index}${bitrate}.mp4`;
16055
16098
  }
16056
- var import_hono6, import_zod18, import_node_fs4, import_node_os4, import_node_path6, import_node_stream2, import_promises4, import_node_child_process2, InstagramProfileContentBodySchema, InstagramMediaTypeSchema, InstagramMediaDownloadBodySchema, instagramApp;
16099
+ var import_hono7, import_zod18, import_node_fs4, import_node_os4, import_node_path6, import_node_stream2, import_promises4, import_node_child_process2, InstagramProfileContentBodySchema, InstagramMediaTypeSchema, InstagramMediaDownloadBodySchema, instagramApp;
16057
16100
  var init_instagram_routes = __esm({
16058
16101
  "src/api/instagram-routes.ts"() {
16059
16102
  "use strict";
16060
- import_hono6 = require("hono");
16103
+ import_hono7 = require("hono");
16061
16104
  import_zod18 = require("zod");
16062
16105
  import_node_fs4 = require("fs");
16063
16106
  import_node_os4 = require("os");
@@ -16099,7 +16142,7 @@ var init_instagram_routes = __esm({
16099
16142
  includeTranscript: import_zod18.z.boolean().default(false),
16100
16143
  mux: import_zod18.z.boolean().default(true)
16101
16144
  });
16102
- instagramApp = new import_hono6.Hono();
16145
+ instagramApp = new import_hono7.Hono();
16103
16146
  instagramApp.post("/profile-content", createApiKeyAuth(), async (c) => {
16104
16147
  const raw = await c.req.json().catch(() => ({}));
16105
16148
  const parsed = InstagramProfileContentBodySchema.safeParse(raw);
@@ -16304,11 +16347,11 @@ async function residentialProxyId(attemptIndex) {
16304
16347
  return void 0;
16305
16348
  }
16306
16349
  }
16307
- var import_hono7, import_zod19, RedditThreadBodySchema, PARSE_REDDIT, redditApp;
16350
+ var import_hono8, import_zod19, RedditThreadBodySchema, PARSE_REDDIT, redditApp;
16308
16351
  var init_reddit_routes = __esm({
16309
16352
  "src/api/reddit-routes.ts"() {
16310
16353
  "use strict";
16311
- import_hono7 = require("hono");
16354
+ import_hono8 = require("hono");
16312
16355
  import_zod19 = require("zod");
16313
16356
  init_BrowserDriver();
16314
16357
  init_kernel_proxy_resolver();
@@ -16346,7 +16389,7 @@ var init_reddit_routes = __esm({
16346
16389
  });
16347
16390
  return { title: title, author: author, score: score, postBody: postBody, blocked: blocked, numComments: comments.length, comments: comments };
16348
16391
  })()`;
16349
- redditApp = new import_hono7.Hono();
16392
+ redditApp = new import_hono8.Hono();
16350
16393
  redditApp.post("/thread", createApiKeyAuth(), async (c) => {
16351
16394
  const raw = await c.req.json().catch(() => ({}));
16352
16395
  const parsed = RedditThreadBodySchema.safeParse(raw);
@@ -16380,11 +16423,11 @@ var init_reddit_routes = __esm({
16380
16423
  locale: "en-US"
16381
16424
  });
16382
16425
  const page = driver.getPage();
16383
- await page.goto(oldUrl, { waitUntil: "domcontentloaded", timeout: 45e3 });
16426
+ await page.goto(oldUrl, { waitUntil: "domcontentloaded", timeout: attempt === 0 ? 3e4 : 45e3 });
16384
16427
  await page.waitForTimeout(2500);
16385
16428
  const data = await page.evaluate(PARSE_REDDIT);
16386
16429
  if (!data.blocked && (data.postBody || data.comments.length > 0)) {
16387
- result = { ...data, sourceUrl: body.url, oldRedditUrl: oldUrl, attempts: attempt + 1 };
16430
+ result = { ...data, sourceUrl: body.url, oldRedditUrl: oldUrl, attempts: attempt + 1, proxied: Boolean(proxyId) };
16388
16431
  }
16389
16432
  } catch {
16390
16433
  } finally {
@@ -16415,6 +16458,249 @@ var init_reddit_routes = __esm({
16415
16458
  }
16416
16459
  });
16417
16460
 
16461
+ // src/api/session.ts
16462
+ function getSessionSecret() {
16463
+ const configured = process.env.SESSION_SECRET?.trim();
16464
+ if (configured) return configured;
16465
+ if (isProduction()) throw new Error("SESSION_SECRET is not set \u2014 add it to your Vercel env vars (see src/api/env.ts)");
16466
+ return "dev-secret-change-me";
16467
+ }
16468
+ function safeEqualHex(a, b) {
16469
+ if (a.length !== b.length) return false;
16470
+ try {
16471
+ return (0, import_node_crypto5.timingSafeEqual)(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
16472
+ } catch {
16473
+ return false;
16474
+ }
16475
+ }
16476
+ function signSession(userId) {
16477
+ const payload = String(userId);
16478
+ const sig = (0, import_node_crypto5.createHmac)("sha256", secret()).update(payload).digest("hex");
16479
+ return `${payload}.${sig}`;
16480
+ }
16481
+ function verifySession(token) {
16482
+ const dot = token.lastIndexOf(".");
16483
+ if (dot === -1) return null;
16484
+ const payload = token.slice(0, dot);
16485
+ const sig = token.slice(dot + 1);
16486
+ const expected = (0, import_node_crypto5.createHmac)("sha256", secret()).update(payload).digest("hex");
16487
+ if (!safeEqualHex(sig, expected)) return null;
16488
+ const id = parseInt(payload);
16489
+ return isNaN(id) ? null : id;
16490
+ }
16491
+ var import_node_crypto5, isProduction, secret;
16492
+ var init_session = __esm({
16493
+ "src/api/session.ts"() {
16494
+ "use strict";
16495
+ import_node_crypto5 = require("crypto");
16496
+ isProduction = () => process.env.NODE_ENV === "production" || process.env.VERCEL === "1";
16497
+ secret = () => getSessionSecret();
16498
+ }
16499
+ });
16500
+
16501
+ // src/api/memory.ts
16502
+ function isMemoryOperator(email) {
16503
+ if (!email) return false;
16504
+ const ops = (process.env.MEMORY_OPERATOR_IDENTITIES ?? "").split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
16505
+ return ops.includes(email.trim().toLowerCase());
16506
+ }
16507
+ function encKey() {
16508
+ return (0, import_node_crypto6.scryptSync)(getSessionSecret(), "mcp-memory-key-v1", 32);
16509
+ }
16510
+ function encryptMemoryKey(secret2) {
16511
+ const iv = (0, import_node_crypto6.randomBytes)(12);
16512
+ const cipher = (0, import_node_crypto6.createCipheriv)("aes-256-gcm", encKey(), iv);
16513
+ const enc = Buffer.concat([cipher.update(secret2, "utf8"), cipher.final()]);
16514
+ const tag = cipher.getAuthTag();
16515
+ return `${iv.toString("base64")}:${tag.toString("base64")}:${enc.toString("base64")}`;
16516
+ }
16517
+ function decryptMemoryKey(stored) {
16518
+ try {
16519
+ const [ivB, tagB, dataB] = stored.split(":");
16520
+ const decipher = (0, import_node_crypto6.createDecipheriv)("aes-256-gcm", encKey(), Buffer.from(ivB, "base64"));
16521
+ decipher.setAuthTag(Buffer.from(tagB, "base64"));
16522
+ return Buffer.concat([decipher.update(Buffer.from(dataB, "base64")), decipher.final()]).toString("utf8");
16523
+ } catch {
16524
+ return null;
16525
+ }
16526
+ }
16527
+ async function memoryCall(toolName, args, userMemoryKey) {
16528
+ try {
16529
+ const res = await fetch(`${MEMORY_BASE_URL()}/api/mcp/memoryServer/tools/${toolName}/execute`, {
16530
+ method: "POST",
16531
+ headers: { "content-type": "application/json" },
16532
+ body: JSON.stringify({ data: { ...args, apiKey: userMemoryKey } })
16533
+ });
16534
+ const body = await res.json().catch(() => null);
16535
+ if (!res.ok) return { ok: false, error: body?.error ?? `memory ${toolName} failed (${res.status})` };
16536
+ if (body?.result) return body.result;
16537
+ return { ok: false, error: body?.error ?? `memory ${toolName} returned no result` };
16538
+ } catch (err) {
16539
+ return { ok: false, error: err?.message ?? "memory call failed" };
16540
+ }
16541
+ }
16542
+ function personalVault(user) {
16543
+ return `mcp-${user.id}`;
16544
+ }
16545
+ function memoryIdentity(user) {
16546
+ return user.email;
16547
+ }
16548
+ function resolveMemoryIdentity(user) {
16549
+ return memoryIdentity(user);
16550
+ }
16551
+ function memoryPlanForReads(user) {
16552
+ if (isMemoryOperator(user.email)) return "unlimited";
16553
+ if (user.memory_plan === "pro" || user.memory_plan === "team") return user.memory_plan;
16554
+ return "free";
16555
+ }
16556
+ async function provisionMemoryForUser(user) {
16557
+ try {
16558
+ const { key } = await getOrCreateUserMemoryKey(user);
16559
+ if (key) await setMemoryProvisioned(user.id, true);
16560
+ } catch {
16561
+ }
16562
+ }
16563
+ async function getOrCreateUserMemoryKey(user) {
16564
+ const creds = await getUserMemoryCreds(user.id);
16565
+ if (creds.memory_key) {
16566
+ const decrypted = decryptMemoryKey(creds.memory_key);
16567
+ if (decrypted) return { key: decrypted };
16568
+ }
16569
+ const admin = ADMIN_KEY();
16570
+ if (!admin) return { key: null, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
16571
+ const identity = memoryIdentity(user);
16572
+ const plan = isMemoryOperator(user.email) ? "unlimited" : (await getMemoryPlan(user.id)).plan;
16573
+ const provisioned = await memoryCall(
16574
+ "provisionDefaultsTool",
16575
+ { granteeIdentity: identity, issueKey: true, plan },
16576
+ admin
16577
+ );
16578
+ if (!provisioned.ok || !provisioned.secret) {
16579
+ return { key: null, error: provisioned.error ?? "failed to provision default vaults" };
16580
+ }
16581
+ await setUserMemoryCreds(user.id, encryptMemoryKey(provisioned.secret), identity);
16582
+ return { key: provisioned.secret };
16583
+ }
16584
+ async function syncMemoryKeyPlan(user, plan) {
16585
+ const effectivePlan = isMemoryOperator(user.email) ? "unlimited" : plan;
16586
+ const { key, error } = await getOrCreateUserMemoryKey(user);
16587
+ if (!key) return { ok: false, error: error ?? "memory unavailable" };
16588
+ const listed = await memoryCall(
16589
+ "listKeysTool",
16590
+ {},
16591
+ key
16592
+ );
16593
+ if (!listed.ok || !listed.keys?.length) return { ok: false, error: listed.error ?? "no memory keys found" };
16594
+ const target = listed.keys[0];
16595
+ if (target.plan === effectivePlan) return { ok: true };
16596
+ const res = await memoryCall("setScopeTool", { keyId: target.keyId, plan: effectivePlan }, key);
16597
+ return { ok: res.ok, error: res.error };
16598
+ }
16599
+ async function syncScheduleEntitlement(user, enabled, quotaPerPeriod) {
16600
+ const admin = ADMIN_KEY();
16601
+ if (!admin) return { ok: false, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
16602
+ const identity = resolveMemoryIdentity(user);
16603
+ const res = await memoryCall("setScheduleEntitlementTool", {
16604
+ granteeIdentity: identity,
16605
+ enabled,
16606
+ quotaPerPeriod,
16607
+ mcpScraperApiKey: user.api_key
16608
+ }, admin);
16609
+ return { ok: res.ok, error: res.error };
16610
+ }
16611
+ var import_node_crypto6, MEMORY_BASE_URL, ADMIN_KEY;
16612
+ var init_memory = __esm({
16613
+ "src/api/memory.ts"() {
16614
+ "use strict";
16615
+ import_node_crypto6 = require("crypto");
16616
+ init_session();
16617
+ init_db();
16618
+ MEMORY_BASE_URL = () => (process.env.MCP_MEMORY_BASE_URL ?? "https://mcp-memory-omega.vercel.app").replace(/\/$/, "");
16619
+ ADMIN_KEY = () => process.env.MCP_MEMORY_ADMIN_KEY?.trim() ?? "";
16620
+ }
16621
+ });
16622
+
16623
+ // src/api/video-routes.ts
16624
+ function invalidRequest5(message) {
16625
+ return { error_code: "invalid_request", message };
16626
+ }
16627
+ var import_hono9, import_zod20, videoApp, AnalyzeBodySchema;
16628
+ var init_video_routes = __esm({
16629
+ "src/api/video-routes.ts"() {
16630
+ "use strict";
16631
+ import_hono9 = require("hono");
16632
+ import_zod20 = require("zod");
16633
+ init_db();
16634
+ init_rates();
16635
+ init_api_auth();
16636
+ init_memory();
16637
+ videoApp = new import_hono9.Hono();
16638
+ AnalyzeBodySchema = import_zod20.z.object({
16639
+ sourceUrl: import_zod20.z.string().trim().url("sourceUrl must be a direct video file URL"),
16640
+ intervalS: import_zod20.z.number().min(1).max(30).optional(),
16641
+ maxFrames: import_zod20.z.number().int().min(1).max(120).optional(),
16642
+ detail: import_zod20.z.enum(["fast", "standard", "deep"]).optional(),
16643
+ vault: import_zod20.z.string().trim().min(1).optional()
16644
+ });
16645
+ videoApp.post("/analyze", createApiKeyAuth(), async (c) => {
16646
+ const parsed = AnalyzeBodySchema.safeParse(await c.req.json().catch(() => ({})));
16647
+ if (!parsed.success) return c.json(invalidRequest5(parsed.error.issues[0]?.message ?? "invalid request"), 400);
16648
+ const body = parsed.data;
16649
+ const user = c.get("user");
16650
+ const { key: memKey, error: memErr } = await getOrCreateUserMemoryKey(user);
16651
+ if (!memKey) return c.json({ error_code: "memory_unavailable", message: memErr ?? "memory unavailable" }, 502);
16652
+ const { ok, balance_mc } = await debitMc(user.id, MC_COSTS.video_analysis, LedgerOperation.VIDEO_ANALYSIS, body.sourceUrl);
16653
+ if (!ok) return c.json(insufficientBalanceResponse(balance_mc, MC_COSTS.video_analysis), 402);
16654
+ const started = await memoryCall(
16655
+ "videoAnalyzeStartTool",
16656
+ {
16657
+ sourceUrl: body.sourceUrl,
16658
+ intervalS: body.intervalS ?? 2,
16659
+ maxFrames: body.maxFrames ?? 120,
16660
+ detail: body.detail ?? "standard",
16661
+ vault: body.vault ?? "Library"
16662
+ },
16663
+ memKey
16664
+ );
16665
+ if (!started.ok || !started.runId) {
16666
+ await creditMc(user.id, MC_COSTS.video_analysis, LedgerOperation.VIDEO_ANALYSIS_REFUND, `start-failed:${body.sourceUrl}`);
16667
+ return c.json({ error_code: "video_start_failed", message: started.error ?? "could not start analysis" }, 502);
16668
+ }
16669
+ return c.json({
16670
+ ok: true,
16671
+ runId: started.runId,
16672
+ status: "queued",
16673
+ message: 'Analysis started. Poll GET /video/status?runId=... every few seconds until status is "done".'
16674
+ });
16675
+ });
16676
+ videoApp.post("/status", createApiKeyAuth(), async (c) => {
16677
+ const rawBody = await c.req.json().catch(() => ({}));
16678
+ const runId = rawBody.runId?.trim();
16679
+ if (!runId) return c.json(invalidRequest5("runId is required"), 400);
16680
+ const user = c.get("user");
16681
+ const { key: memKey, error: memErr } = await getOrCreateUserMemoryKey(user);
16682
+ if (!memKey) return c.json({ error_code: "memory_unavailable", message: memErr ?? "memory unavailable" }, 502);
16683
+ const st = await memoryCall("videoAnalyzeStatusTool", { runId }, memKey);
16684
+ if (!st.ok) return c.json({ error_code: "not_found", message: st.error ?? "run not found" }, 404);
16685
+ if (st.status === "failed") {
16686
+ const refundOp = `${LedgerOperation.VIDEO_ANALYSIS_REFUND}:${runId}`;
16687
+ if (!await ledgerExistsForOperation(user.id, refundOp)) {
16688
+ await creditMc(user.id, MC_COSTS.video_analysis, refundOp, `run-failed:${runId}`);
16689
+ }
16690
+ }
16691
+ return c.json({
16692
+ ok: true,
16693
+ runId,
16694
+ status: st.status ?? "unknown",
16695
+ progress: st.progress ?? null,
16696
+ frameCount: st.frameCount ?? null,
16697
+ ...st.status === "done" ? { artifactPath: st.artifactPath ?? null, report: st.report ?? null } : {},
16698
+ ...st.error ? { error: st.error } : {}
16699
+ });
16700
+ });
16701
+ }
16702
+ });
16703
+
16418
16704
  // src/extractor/MapsNavigator.ts
16419
16705
  var MapsNavigator;
16420
16706
  var init_MapsNavigator = __esm({
@@ -16602,7 +16888,7 @@ var init_MapsReviewCollector = __esm({
16602
16888
  });
16603
16889
 
16604
16890
  // src/extractor/MapsExtractor.ts
16605
- var import_zod20, MapsExtractor;
16891
+ var import_zod21, MapsExtractor;
16606
16892
  var init_MapsExtractor = __esm({
16607
16893
  "src/extractor/MapsExtractor.ts"() {
16608
16894
  "use strict";
@@ -16610,7 +16896,7 @@ var init_MapsExtractor = __esm({
16610
16896
  init_selectors();
16611
16897
  init_MapsNavigator();
16612
16898
  init_MapsReviewCollector();
16613
- import_zod20 = require("zod");
16899
+ import_zod21 = require("zod");
16614
16900
  MapsExtractor = class {
16615
16901
  constructor(driver) {
16616
16902
  this.driver = driver;
@@ -16796,7 +17082,7 @@ var init_MapsExtractor = __esm({
16796
17082
  });
16797
17083
  return rows;
16798
17084
  }, { hoursTable: MapsSelectors.hoursTable, hoursTableAlt: MapsSelectors.hoursTableAlt });
16799
- const result = import_zod20.z.array(RawMapsHoursRowSchema).safeParse(raw);
17085
+ const result = import_zod21.z.array(RawMapsHoursRowSchema).safeParse(raw);
16800
17086
  if (!result.success) {
16801
17087
  console.warn("[MapsExtractor] hours parse failed", result.error.flatten());
16802
17088
  return [];
@@ -16860,7 +17146,7 @@ var init_MapsExtractor = __esm({
16860
17146
  });
16861
17147
  return results;
16862
17148
  });
16863
- const result = import_zod20.z.array(RawMapsAboutAttributeSchema).safeParse(raw);
17149
+ const result = import_zod21.z.array(RawMapsAboutAttributeSchema).safeParse(raw);
16864
17150
  if (!result.success) {
16865
17151
  console.warn("[MapsExtractor] about parse failed", result.error.flatten());
16866
17152
  return [];
@@ -17256,11 +17542,11 @@ function mapsErrorResponse(c, err, errorCode) {
17256
17542
  attempts: rotationError?.attempts ?? void 0
17257
17543
  }, retryable ? 503 : 500);
17258
17544
  }
17259
- var import_hono8, mapsApp;
17545
+ var import_hono10, mapsApp;
17260
17546
  var init_maps_routes = __esm({
17261
17547
  "src/api/maps-routes.ts"() {
17262
17548
  "use strict";
17263
- import_hono8 = require("hono");
17549
+ import_hono10 = require("hono");
17264
17550
  init_db();
17265
17551
  init_rates();
17266
17552
  init_MapsExtractor();
@@ -17271,7 +17557,7 @@ var init_maps_routes = __esm({
17271
17557
  init_browser_service_env();
17272
17558
  init_maps_search_rotation();
17273
17559
  init_concurrency_gates();
17274
- mapsApp = new import_hono8.Hono();
17560
+ mapsApp = new import_hono10.Hono();
17275
17561
  mapsApp.post("/search", createApiKeyAuth(), async (c) => {
17276
17562
  const user = c.get("user");
17277
17563
  const body = await c.req.json().catch(() => ({}));
@@ -20081,47 +20367,47 @@ async function runDirectoryWorkflowFromPlan(options, plan) {
20081
20367
  const csvPath = options.saveCsv ? await saveDirectoryCsv(base) : null;
20082
20368
  return { ...base, csvPath };
20083
20369
  }
20084
- var import_promises6, import_node_path8, import_zod21, DirectoryWorkflowOptionsSchema;
20370
+ var import_promises6, import_node_path8, import_zod22, DirectoryWorkflowOptionsSchema;
20085
20371
  var init_directory_workflow = __esm({
20086
20372
  "src/directory/directory-workflow.ts"() {
20087
20373
  "use strict";
20088
20374
  import_promises6 = require("fs/promises");
20089
20375
  import_node_path8 = require("path");
20090
- import_zod21 = require("zod");
20376
+ import_zod22 = require("zod");
20091
20377
  init_mcp_response_formatter();
20092
20378
  init_browser_service_env();
20093
20379
  init_maps_search_rotation();
20094
20380
  init_schemas3();
20095
20381
  init_csv();
20096
20382
  init_location_db();
20097
- DirectoryWorkflowOptionsSchema = import_zod21.z.object({
20098
- query: import_zod21.z.string().min(1),
20099
- state: import_zod21.z.string().min(2).default("TN"),
20100
- minPopulation: import_zod21.z.number().int().min(0).default(1e5),
20101
- populationYear: import_zod21.z.union(POPULATION_YEARS.map((year) => import_zod21.z.literal(year))).default(2025),
20102
- maxCities: import_zod21.z.number().int().min(1).max(100).default(25),
20103
- maxResultsPerCity: import_zod21.z.number().int().min(1).max(50).default(50),
20104
- concurrency: import_zod21.z.number().int().min(1).max(5).default(5),
20105
- includeZipGroups: import_zod21.z.boolean().default(true),
20106
- usZipsCsvPath: import_zod21.z.string().optional(),
20107
- saveCsv: import_zod21.z.boolean().default(true),
20108
- gl: import_zod21.z.string().length(2).default("us"),
20109
- hl: import_zod21.z.string().length(2).default("en"),
20110
- proxyMode: import_zod21.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
20111
- proxyZip: import_zod21.z.string().regex(/^\d{5}$/).optional(),
20112
- debug: import_zod21.z.boolean().default(false),
20113
- headless: import_zod21.z.boolean().default(true),
20114
- kernelApiKey: import_zod21.z.string().optional()
20383
+ DirectoryWorkflowOptionsSchema = import_zod22.z.object({
20384
+ query: import_zod22.z.string().min(1),
20385
+ state: import_zod22.z.string().min(2).default("TN"),
20386
+ minPopulation: import_zod22.z.number().int().min(0).default(1e5),
20387
+ populationYear: import_zod22.z.union(POPULATION_YEARS.map((year) => import_zod22.z.literal(year))).default(2025),
20388
+ maxCities: import_zod22.z.number().int().min(1).max(100).default(25),
20389
+ maxResultsPerCity: import_zod22.z.number().int().min(1).max(50).default(50),
20390
+ concurrency: import_zod22.z.number().int().min(1).max(5).default(5),
20391
+ includeZipGroups: import_zod22.z.boolean().default(true),
20392
+ usZipsCsvPath: import_zod22.z.string().optional(),
20393
+ saveCsv: import_zod22.z.boolean().default(true),
20394
+ gl: import_zod22.z.string().length(2).default("us"),
20395
+ hl: import_zod22.z.string().length(2).default("en"),
20396
+ proxyMode: import_zod22.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
20397
+ proxyZip: import_zod22.z.string().regex(/^\d{5}$/).optional(),
20398
+ debug: import_zod22.z.boolean().default(false),
20399
+ headless: import_zod22.z.boolean().default(true),
20400
+ kernelApiKey: import_zod22.z.string().optional()
20115
20401
  });
20116
20402
  }
20117
20403
  });
20118
20404
 
20119
20405
  // src/api/directory-routes.ts
20120
- var import_hono9, directoryApp;
20406
+ var import_hono11, directoryApp;
20121
20407
  var init_directory_routes = __esm({
20122
20408
  "src/api/directory-routes.ts"() {
20123
20409
  "use strict";
20124
- import_hono9 = require("hono");
20410
+ import_hono11 = require("hono");
20125
20411
  init_api_auth();
20126
20412
  init_db();
20127
20413
  init_rates();
@@ -20129,7 +20415,7 @@ var init_directory_routes = __esm({
20129
20415
  init_location_db();
20130
20416
  init_browser_service_env();
20131
20417
  init_concurrency_gates();
20132
- directoryApp = new import_hono9.Hono();
20418
+ directoryApp = new import_hono11.Hono();
20133
20419
  directoryApp.post("/run", createApiKeyAuth(), async (c) => {
20134
20420
  const user = c.get("user");
20135
20421
  const body = await c.req.json().catch(() => ({}));
@@ -20537,21 +20823,21 @@ function competitorRows(rows, targetDomain) {
20537
20823
  source_url_count: entry.urls.size
20538
20824
  })).sort((a, b) => Number(a.organic_best_position || 999) - Number(b.organic_best_position || 999));
20539
20825
  }
20540
- var import_zod22, AgentPacketInputSchema, agentPacketWorkflowDefinition;
20826
+ var import_zod23, AgentPacketInputSchema, agentPacketWorkflowDefinition;
20541
20827
  var init_agent_packet = __esm({
20542
20828
  "src/workflows/workflows/agent-packet.ts"() {
20543
20829
  "use strict";
20544
- import_zod22 = require("zod");
20830
+ import_zod23 = require("zod");
20545
20831
  init_report_renderer();
20546
- AgentPacketInputSchema = import_zod22.z.object({
20547
- keyword: import_zod22.z.string().min(1),
20548
- domain: import_zod22.z.string().optional(),
20549
- location: import_zod22.z.string().optional(),
20550
- maxQuestions: import_zod22.z.number().int().min(1).max(200).default(40),
20551
- includeSerp: import_zod22.z.boolean().default(true),
20552
- includePaa: import_zod22.z.boolean().default(true),
20553
- includeAiOverview: import_zod22.z.boolean().default(true),
20554
- returnPartial: import_zod22.z.boolean().default(true)
20832
+ AgentPacketInputSchema = import_zod23.z.object({
20833
+ keyword: import_zod23.z.string().min(1),
20834
+ domain: import_zod23.z.string().optional(),
20835
+ location: import_zod23.z.string().optional(),
20836
+ maxQuestions: import_zod23.z.number().int().min(1).max(200).default(40),
20837
+ includeSerp: import_zod23.z.boolean().default(true),
20838
+ includePaa: import_zod23.z.boolean().default(true),
20839
+ includeAiOverview: import_zod23.z.boolean().default(true),
20840
+ returnPartial: import_zod23.z.boolean().default(true)
20555
20841
  });
20556
20842
  agentPacketWorkflowDefinition = {
20557
20843
  id: "agent-packet",
@@ -20749,22 +21035,22 @@ function directoryRows(result) {
20749
21035
  }
20750
21036
  return rows;
20751
21037
  }
20752
- var import_zod23, DirectoryWorkflowCliInputSchema, DIRECTORY_CSV_HEADERS, directoryWorkflowDefinition;
21038
+ var import_zod24, DirectoryWorkflowCliInputSchema, DIRECTORY_CSV_HEADERS, directoryWorkflowDefinition;
20753
21039
  var init_directory = __esm({
20754
21040
  "src/workflows/workflows/directory.ts"() {
20755
21041
  "use strict";
20756
- import_zod23 = require("zod");
21042
+ import_zod24 = require("zod");
20757
21043
  init_report_renderer();
20758
21044
  init_schemas3();
20759
- DirectoryWorkflowCliInputSchema = import_zod23.z.object({
20760
- query: import_zod23.z.string().min(1),
20761
- state: import_zod23.z.string().min(2).default("TN"),
20762
- minPopulation: import_zod23.z.number().int().min(0).default(1e5),
20763
- maxCities: import_zod23.z.number().int().min(1).max(100).default(25),
20764
- maxResultsPerCity: import_zod23.z.number().int().min(1).max(50).default(20),
20765
- concurrency: import_zod23.z.number().int().min(1).max(5).default(5),
20766
- proxyMode: import_zod23.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
20767
- saveCsv: import_zod23.z.boolean().default(true)
21045
+ DirectoryWorkflowCliInputSchema = import_zod24.z.object({
21046
+ query: import_zod24.z.string().min(1),
21047
+ state: import_zod24.z.string().min(2).default("TN"),
21048
+ minPopulation: import_zod24.z.number().int().min(0).default(1e5),
21049
+ maxCities: import_zod24.z.number().int().min(1).max(100).default(25),
21050
+ maxResultsPerCity: import_zod24.z.number().int().min(1).max(50).default(20),
21051
+ concurrency: import_zod24.z.number().int().min(1).max(5).default(5),
21052
+ proxyMode: import_zod24.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
21053
+ saveCsv: import_zod24.z.boolean().default(true)
20768
21054
  });
20769
21055
  DIRECTORY_CSV_HEADERS = [
20770
21056
  "source_query",
@@ -20904,21 +21190,21 @@ function buildAttemptUrls(website) {
20904
21190
  }
20905
21191
  return [...urls].slice(0, 3);
20906
21192
  }
20907
- var import_zod24, GetLeadsInputSchema, LEADS_CSV_HEADERS, EMAIL_RE, MAILTO_RE, SOCIAL_RE, EMAIL_BAD, EMAIL_PREFIX, SOCIAL_SKIP, getLeadsWorkflowDefinition;
21193
+ var import_zod25, GetLeadsInputSchema, LEADS_CSV_HEADERS, EMAIL_RE, MAILTO_RE, SOCIAL_RE, EMAIL_BAD, EMAIL_PREFIX, SOCIAL_SKIP, getLeadsWorkflowDefinition;
20908
21194
  var init_get_leads = __esm({
20909
21195
  "src/workflows/workflows/get-leads.ts"() {
20910
21196
  "use strict";
20911
- import_zod24 = require("zod");
21197
+ import_zod25 = require("zod");
20912
21198
  init_report_renderer();
20913
21199
  init_schemas3();
20914
- GetLeadsInputSchema = import_zod24.z.object({
20915
- query: import_zod24.z.string().min(1).describe('Business category, niche, or keyword to search on Google Maps, e.g. "roofers", "med spas", "dentists". Do not include the city here.'),
20916
- location: import_zod24.z.string().min(1).describe('City / market to search, e.g. "Houston, TX" or "Austin, Texas".'),
20917
- maxResults: import_zod24.z.number().int().min(1).max(50).default(25).describe("How many Maps businesses to collect for the market. Maximum 50."),
20918
- enrichWebsites: import_zod24.z.boolean().default(true).describe("Visit each business website (home + contact pages) to harvest email and social links. Uses the proxy/browser-backed extractor so blocked sites still resolve."),
20919
- hydrateReviewCounts: import_zod24.z.boolean().default(true).describe("Deep-dive each profile to confirm the review count and booking URL that the Maps search list omits."),
20920
- concurrency: import_zod24.z.number().int().min(1).max(4).default(3).describe("How many businesses to enrich in parallel. Keep low to respect per-account concurrency limits."),
20921
- proxyMode: import_zod24.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting for the Maps search. location targets the market; none is for local debugging.")
21200
+ GetLeadsInputSchema = import_zod25.z.object({
21201
+ query: import_zod25.z.string().min(1).describe('Business category, niche, or keyword to search on Google Maps, e.g. "roofers", "med spas", "dentists". Do not include the city here.'),
21202
+ location: import_zod25.z.string().min(1).describe('City / market to search, e.g. "Houston, TX" or "Austin, Texas".'),
21203
+ maxResults: import_zod25.z.number().int().min(1).max(50).default(25).describe("How many Maps businesses to collect for the market. Maximum 50."),
21204
+ enrichWebsites: import_zod25.z.boolean().default(true).describe("Visit each business website (home + contact pages) to harvest email and social links. Uses the proxy/browser-backed extractor so blocked sites still resolve."),
21205
+ hydrateReviewCounts: import_zod25.z.boolean().default(true).describe("Deep-dive each profile to confirm the review count and booking URL that the Maps search list omits."),
21206
+ concurrency: import_zod25.z.number().int().min(1).max(4).default(3).describe("How many businesses to enrich in parallel. Keep low to respect per-account concurrency limits."),
21207
+ proxyMode: import_zod25.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting for the Maps search. location targets the market; none is for local debugging.")
20922
21208
  });
20923
21209
  LEADS_CSV_HEADERS = [
20924
21210
  "position",
@@ -21120,25 +21406,25 @@ function termsFrom(texts) {
21120
21406
  }
21121
21407
  return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8).map(([term, count]) => `${term} (${count})`).join("; ");
21122
21408
  }
21123
- var import_zod25, LocalCompetitiveAuditInputSchema, localCompetitiveAuditWorkflowDefinition;
21409
+ var import_zod26, LocalCompetitiveAuditInputSchema, localCompetitiveAuditWorkflowDefinition;
21124
21410
  var init_local_competitive_audit = __esm({
21125
21411
  "src/workflows/workflows/local-competitive-audit.ts"() {
21126
21412
  "use strict";
21127
- import_zod25 = require("zod");
21413
+ import_zod26 = require("zod");
21128
21414
  init_report_renderer();
21129
21415
  init_directory();
21130
21416
  init_schemas3();
21131
- LocalCompetitiveAuditInputSchema = import_zod25.z.object({
21132
- query: import_zod25.z.string().min(1),
21133
- state: import_zod25.z.string().min(2).default("TN"),
21134
- minPopulation: import_zod25.z.number().int().min(0).default(1e5),
21135
- maxCities: import_zod25.z.number().int().min(1).max(100).default(25),
21136
- maxResultsPerCity: import_zod25.z.number().int().min(1).max(50).default(20),
21137
- hydrateTop: import_zod25.z.number().int().min(0).max(10).default(5),
21138
- maxReviews: import_zod25.z.number().int().min(0).max(500).default(50),
21139
- concurrency: import_zod25.z.number().int().min(1).max(5).default(5),
21140
- proxyMode: import_zod25.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
21141
- returnPartial: import_zod25.z.boolean().default(true)
21417
+ LocalCompetitiveAuditInputSchema = import_zod26.z.object({
21418
+ query: import_zod26.z.string().min(1),
21419
+ state: import_zod26.z.string().min(2).default("TN"),
21420
+ minPopulation: import_zod26.z.number().int().min(0).default(1e5),
21421
+ maxCities: import_zod26.z.number().int().min(1).max(100).default(25),
21422
+ maxResultsPerCity: import_zod26.z.number().int().min(1).max(50).default(20),
21423
+ hydrateTop: import_zod26.z.number().int().min(0).max(10).default(5),
21424
+ maxReviews: import_zod26.z.number().int().min(0).max(500).default(50),
21425
+ concurrency: import_zod26.z.number().int().min(1).max(5).default(5),
21426
+ proxyMode: import_zod26.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
21427
+ returnPartial: import_zod26.z.boolean().default(true)
21142
21428
  });
21143
21429
  localCompetitiveAuditWorkflowDefinition = {
21144
21430
  id: "local-competitive-audit",
@@ -21581,58 +21867,58 @@ async function extractPages(ctx, sources, warnings, labelPrefix) {
21581
21867
  }
21582
21868
  }).then((items) => items.filter((item) => item !== null));
21583
21869
  }
21584
- var import_zod26, ProxyModeSchema, MapComparisonInputSchema, SerpComparisonInputSchema, PaaExpansionBriefInputSchema, AiOverviewLanguageInputSchema, mapComparisonWorkflowDefinition, serpComparisonWorkflowDefinition, paaExpansionBriefWorkflowDefinition, aiOverviewLanguageWorkflowDefinition;
21870
+ var import_zod27, ProxyModeSchema, MapComparisonInputSchema, SerpComparisonInputSchema, PaaExpansionBriefInputSchema, AiOverviewLanguageInputSchema, mapComparisonWorkflowDefinition, serpComparisonWorkflowDefinition, paaExpansionBriefWorkflowDefinition, aiOverviewLanguageWorkflowDefinition;
21585
21871
  var init_comparison_briefs = __esm({
21586
21872
  "src/workflows/workflows/comparison-briefs.ts"() {
21587
21873
  "use strict";
21588
- import_zod26 = require("zod");
21874
+ import_zod27 = require("zod");
21589
21875
  init_report_renderer();
21590
21876
  init_directory();
21591
21877
  init_seo_workflow_utils();
21592
21878
  init_schemas3();
21593
- ProxyModeSchema = import_zod26.z.enum(["location", "configured", "none"]);
21594
- MapComparisonInputSchema = import_zod26.z.object({
21595
- query: import_zod26.z.string().min(1),
21596
- location: import_zod26.z.string().optional(),
21597
- state: import_zod26.z.string().optional(),
21598
- minPopulation: import_zod26.z.number().int().min(0).default(1e5),
21599
- maxCities: import_zod26.z.number().int().min(1).max(100).default(5),
21600
- maxResultsPerCity: import_zod26.z.number().int().min(1).max(50).default(20),
21601
- hydrateTop: import_zod26.z.number().int().min(0).max(10).default(5),
21602
- maxReviews: import_zod26.z.number().int().min(0).max(500).default(25),
21603
- concurrency: import_zod26.z.number().int().min(1).max(5).default(5),
21879
+ ProxyModeSchema = import_zod27.z.enum(["location", "configured", "none"]);
21880
+ MapComparisonInputSchema = import_zod27.z.object({
21881
+ query: import_zod27.z.string().min(1),
21882
+ location: import_zod27.z.string().optional(),
21883
+ state: import_zod27.z.string().optional(),
21884
+ minPopulation: import_zod27.z.number().int().min(0).default(1e5),
21885
+ maxCities: import_zod27.z.number().int().min(1).max(100).default(5),
21886
+ maxResultsPerCity: import_zod27.z.number().int().min(1).max(50).default(20),
21887
+ hydrateTop: import_zod27.z.number().int().min(0).max(10).default(5),
21888
+ maxReviews: import_zod27.z.number().int().min(0).max(500).default(25),
21889
+ concurrency: import_zod27.z.number().int().min(1).max(5).default(5),
21604
21890
  proxyMode: ProxyModeSchema.default(DEFAULT_MAPS_PROXY_MODE),
21605
- returnPartial: import_zod26.z.boolean().default(true)
21891
+ returnPartial: import_zod27.z.boolean().default(true)
21606
21892
  }).refine((input) => input.location || input.state, {
21607
21893
  message: "Either location or state is required for map-comparison"
21608
21894
  });
21609
- SerpComparisonInputSchema = import_zod26.z.object({
21610
- keyword: import_zod26.z.string().min(1),
21611
- domain: import_zod26.z.string().optional(),
21612
- url: import_zod26.z.string().url().optional(),
21613
- location: import_zod26.z.string().optional(),
21614
- maxResults: import_zod26.z.number().int().min(1).max(20).default(10),
21615
- maxQuestions: import_zod26.z.number().int().min(1).max(200).default(40),
21616
- extractTop: import_zod26.z.number().int().min(0).max(10).default(5),
21617
- includePaa: import_zod26.z.boolean().default(true),
21618
- includeAiOverview: import_zod26.z.boolean().default(true),
21619
- returnPartial: import_zod26.z.boolean().default(true)
21620
- });
21621
- PaaExpansionBriefInputSchema = import_zod26.z.object({
21622
- keyword: import_zod26.z.string().min(1),
21623
- location: import_zod26.z.string().optional(),
21624
- maxQuestions: import_zod26.z.number().int().min(1).max(300).default(80),
21625
- depth: import_zod26.z.number().int().min(1).max(6).default(3),
21626
- returnPartial: import_zod26.z.boolean().default(true)
21627
- });
21628
- AiOverviewLanguageInputSchema = import_zod26.z.object({
21629
- keyword: import_zod26.z.string().min(1),
21630
- domain: import_zod26.z.string().optional(),
21631
- url: import_zod26.z.string().url().optional(),
21632
- location: import_zod26.z.string().optional(),
21633
- maxQuestions: import_zod26.z.number().int().min(1).max(200).default(40),
21634
- extractTop: import_zod26.z.number().int().min(0).max(8).default(3),
21635
- returnPartial: import_zod26.z.boolean().default(true)
21895
+ SerpComparisonInputSchema = import_zod27.z.object({
21896
+ keyword: import_zod27.z.string().min(1),
21897
+ domain: import_zod27.z.string().optional(),
21898
+ url: import_zod27.z.string().url().optional(),
21899
+ location: import_zod27.z.string().optional(),
21900
+ maxResults: import_zod27.z.number().int().min(1).max(20).default(10),
21901
+ maxQuestions: import_zod27.z.number().int().min(1).max(200).default(40),
21902
+ extractTop: import_zod27.z.number().int().min(0).max(10).default(5),
21903
+ includePaa: import_zod27.z.boolean().default(true),
21904
+ includeAiOverview: import_zod27.z.boolean().default(true),
21905
+ returnPartial: import_zod27.z.boolean().default(true)
21906
+ });
21907
+ PaaExpansionBriefInputSchema = import_zod27.z.object({
21908
+ keyword: import_zod27.z.string().min(1),
21909
+ location: import_zod27.z.string().optional(),
21910
+ maxQuestions: import_zod27.z.number().int().min(1).max(300).default(80),
21911
+ depth: import_zod27.z.number().int().min(1).max(6).default(3),
21912
+ returnPartial: import_zod27.z.boolean().default(true)
21913
+ });
21914
+ AiOverviewLanguageInputSchema = import_zod27.z.object({
21915
+ keyword: import_zod27.z.string().min(1),
21916
+ domain: import_zod27.z.string().optional(),
21917
+ url: import_zod27.z.string().url().optional(),
21918
+ location: import_zod27.z.string().optional(),
21919
+ maxQuestions: import_zod27.z.number().int().min(1).max(200).default(40),
21920
+ extractTop: import_zod27.z.number().int().min(0).max(8).default(3),
21921
+ returnPartial: import_zod27.z.boolean().default(true)
21636
21922
  });
21637
21923
  mapComparisonWorkflowDefinition = {
21638
21924
  id: "map-comparison",
@@ -22102,12 +22388,12 @@ async function runWorkflowStep(id, rawInput, opts) {
22102
22388
  artifacts: writtenArtifacts
22103
22389
  };
22104
22390
  }
22105
- var import_promises8, import_zod27, DEFINITIONS;
22391
+ var import_promises8, import_zod28, DEFINITIONS;
22106
22392
  var init_registry2 = __esm({
22107
22393
  "src/workflows/registry.ts"() {
22108
22394
  "use strict";
22109
22395
  import_promises8 = require("fs/promises");
22110
- import_zod27 = require("zod");
22396
+ import_zod28 = require("zod");
22111
22397
  init_artifact_writer();
22112
22398
  init_http_client2();
22113
22399
  init_agent_packet();
@@ -22185,7 +22471,7 @@ async function readManifestFromSummary(summary) {
22185
22471
  function webhookSignature(body, timestamp2) {
22186
22472
  const secret2 = process.env.MCP_SCRAPER_WEBHOOK_SECRET?.trim();
22187
22473
  if (!secret2) return null;
22188
- return (0, import_node_crypto5.createHmac)("sha256", secret2).update(`${timestamp2}.${body}`).digest("hex");
22474
+ return (0, import_node_crypto7.createHmac)("sha256", secret2).update(`${timestamp2}.${body}`).digest("hex");
22189
22475
  }
22190
22476
  async function deliverWorkflowWebhook(input) {
22191
22477
  if (!input.webhookUrl) return;
@@ -22392,47 +22678,47 @@ async function dispatchDueWorkflowSchedules(apiUrl, limit = 3) {
22392
22678
  }
22393
22679
  return { dispatched: results.length, results };
22394
22680
  }
22395
- var import_node_crypto5, import_promises9, import_hono10, import_zod28, workflowApp, WorkflowInputSchema, WorkflowIdSchema, CadenceSchema, ScheduleStatusSchema, RunBodySchema, ScheduleCreateSchema, SchedulePatchSchema, TERMINAL_RUN_STATUSES;
22681
+ var import_node_crypto7, import_promises9, import_hono12, import_zod29, workflowApp, WorkflowInputSchema, WorkflowIdSchema, CadenceSchema, ScheduleStatusSchema, RunBodySchema, ScheduleCreateSchema, SchedulePatchSchema, TERMINAL_RUN_STATUSES;
22396
22682
  var init_workflow_routes = __esm({
22397
22683
  "src/api/workflow-routes.ts"() {
22398
22684
  "use strict";
22399
- import_node_crypto5 = require("crypto");
22685
+ import_node_crypto7 = require("crypto");
22400
22686
  import_promises9 = require("fs/promises");
22401
- import_hono10 = require("hono");
22402
- import_zod28 = require("zod");
22687
+ import_hono12 = require("hono");
22688
+ import_zod29 = require("zod");
22403
22689
  init_artifact_writer();
22404
22690
  init_registry2();
22405
22691
  init_api_auth();
22406
22692
  init_db();
22407
22693
  init_url_utils();
22408
22694
  init_concurrency_gates();
22409
- workflowApp = new import_hono10.Hono();
22410
- WorkflowInputSchema = import_zod28.z.record(import_zod28.z.unknown()).default({});
22411
- WorkflowIdSchema = import_zod28.z.string().min(1);
22412
- CadenceSchema = import_zod28.z.enum(["daily", "weekly", "monthly"]);
22413
- ScheduleStatusSchema = import_zod28.z.enum(["active", "paused"]);
22414
- RunBodySchema = import_zod28.z.object({
22695
+ workflowApp = new import_hono12.Hono();
22696
+ WorkflowInputSchema = import_zod29.z.record(import_zod29.z.unknown()).default({});
22697
+ WorkflowIdSchema = import_zod29.z.string().min(1);
22698
+ CadenceSchema = import_zod29.z.enum(["daily", "weekly", "monthly"]);
22699
+ ScheduleStatusSchema = import_zod29.z.enum(["active", "paused"]);
22700
+ RunBodySchema = import_zod29.z.object({
22415
22701
  workflowId: WorkflowIdSchema,
22416
22702
  input: WorkflowInputSchema,
22417
- webhookUrl: import_zod28.z.string().url().optional()
22703
+ webhookUrl: import_zod29.z.string().url().optional()
22418
22704
  });
22419
- ScheduleCreateSchema = import_zod28.z.object({
22705
+ ScheduleCreateSchema = import_zod29.z.object({
22420
22706
  workflowId: WorkflowIdSchema,
22421
- name: import_zod28.z.string().min(1).max(120).optional(),
22707
+ name: import_zod29.z.string().min(1).max(120).optional(),
22422
22708
  input: WorkflowInputSchema,
22423
22709
  cadence: CadenceSchema.default("weekly"),
22424
- timezone: import_zod28.z.string().min(1).max(64).default("UTC"),
22425
- webhookUrl: import_zod28.z.string().url().optional(),
22426
- nextRunAt: import_zod28.z.string().datetime().optional()
22710
+ timezone: import_zod29.z.string().min(1).max(64).default("UTC"),
22711
+ webhookUrl: import_zod29.z.string().url().optional(),
22712
+ nextRunAt: import_zod29.z.string().datetime().optional()
22427
22713
  });
22428
- SchedulePatchSchema = import_zod28.z.object({
22429
- name: import_zod28.z.string().min(1).max(120).optional(),
22714
+ SchedulePatchSchema = import_zod29.z.object({
22715
+ name: import_zod29.z.string().min(1).max(120).optional(),
22430
22716
  status: ScheduleStatusSchema.optional(),
22431
22717
  input: WorkflowInputSchema.optional(),
22432
22718
  cadence: CadenceSchema.optional(),
22433
- timezone: import_zod28.z.string().min(1).max(64).optional(),
22434
- webhookUrl: import_zod28.z.string().url().nullable().optional(),
22435
- nextRunAt: import_zod28.z.string().datetime().nullable().optional()
22719
+ timezone: import_zod29.z.string().min(1).max(64).optional(),
22720
+ webhookUrl: import_zod29.z.string().url().nullable().optional(),
22721
+ nextRunAt: import_zod29.z.string().datetime().nullable().optional()
22436
22722
  });
22437
22723
  workflowApp.get("/definitions", createApiKeyAuth(), (c) => {
22438
22724
  return c.json({ workflows: listWorkflowDefinitions() });
@@ -22677,7 +22963,7 @@ var init_workflow_routes = __esm({
22677
22963
  // src/serp-intelligence/page-snapshot-extractor.ts
22678
22964
  function sha256(value) {
22679
22965
  if (!value) return null;
22680
- return (0, import_node_crypto6.createHash)("sha256").update(value).digest("hex");
22966
+ return (0, import_node_crypto8.createHash)("sha256").update(value).digest("hex");
22681
22967
  }
22682
22968
  function countWords(markdown) {
22683
22969
  const matches = markdown.trim().match(/\b[\p{L}\p{N}][\p{L}\p{N}'-]*\b/gu);
@@ -22977,11 +23263,11 @@ async function capturePageSnapshots(targets, options = {}) {
22977
23263
  }
22978
23264
  };
22979
23265
  }
22980
- var import_node_crypto6, import_p_limit3, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
23266
+ var import_node_crypto8, import_p_limit3, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_CONTENT_CHARS;
22981
23267
  var init_page_snapshot_extractor = __esm({
22982
23268
  "src/serp-intelligence/page-snapshot-extractor.ts"() {
22983
23269
  "use strict";
22984
- import_node_crypto6 = require("crypto");
23270
+ import_node_crypto8 = require("crypto");
22985
23271
  import_p_limit3 = __toESM(require("p-limit"), 1);
22986
23272
  init_kpo_extractor();
22987
23273
  init_url_utils();
@@ -24981,11 +25267,11 @@ function isPublicHttpUrl(value) {
24981
25267
  return false;
24982
25268
  }
24983
25269
  }
24984
- var import_zod29, SerpIntelligenceDeviceValues, SerpIntelligenceProxyModeValues, SerpIntelligenceAttemptOutcomeValues, SerpIntelligenceLocalizationStatusValues, SerpPageSnapshotSourceKindValues, SerpPageFetchStatusValues, SerpPageFetchedViaValues, HostnameSuffixPattern, Ipv4Pattern, SerpIntelligencePublicHttpUrlSchema, SerpIntelligenceCaptureBodySchema, SerpIntelligencePageSnapshotRequestSchema, SerpIntelligencePageSnapshotsBodySchema, SerpIntelligenceAICitationSchema, SerpIntelligenceOrganicResultSchema, SerpIntelligenceLocationEvidenceSchema, SerpIntelligenceHarvestResultSchema, SerpIntelligenceCaptureAttemptSchema, SerpPageSnapshotCaptureSchema, SerpIntelligenceCaptureResponseSchema, SerpIntelligencePageSnapshotsResponseSchema;
25270
+ var import_zod30, SerpIntelligenceDeviceValues, SerpIntelligenceProxyModeValues, SerpIntelligenceAttemptOutcomeValues, SerpIntelligenceLocalizationStatusValues, SerpPageSnapshotSourceKindValues, SerpPageFetchStatusValues, SerpPageFetchedViaValues, HostnameSuffixPattern, Ipv4Pattern, SerpIntelligencePublicHttpUrlSchema, SerpIntelligenceCaptureBodySchema, SerpIntelligencePageSnapshotRequestSchema, SerpIntelligencePageSnapshotsBodySchema, SerpIntelligenceAICitationSchema, SerpIntelligenceOrganicResultSchema, SerpIntelligenceLocationEvidenceSchema, SerpIntelligenceHarvestResultSchema, SerpIntelligenceCaptureAttemptSchema, SerpPageSnapshotCaptureSchema, SerpIntelligenceCaptureResponseSchema, SerpIntelligencePageSnapshotsResponseSchema;
24985
25271
  var init_schemas4 = __esm({
24986
25272
  "src/serp-intelligence/schemas.ts"() {
24987
25273
  "use strict";
24988
- import_zod29 = require("zod");
25274
+ import_zod30 = require("zod");
24989
25275
  init_schemas3();
24990
25276
  SerpIntelligenceDeviceValues = ["desktop", "mobile"];
24991
25277
  SerpIntelligenceProxyModeValues = ["location", "configured", "none"];
@@ -25020,171 +25306,171 @@ var init_schemas4 = __esm({
25020
25306
  SerpPageFetchedViaValues = ["fetch", "headless", "browser", "mcp"];
25021
25307
  HostnameSuffixPattern = /(^|\.)localhost$/i;
25022
25308
  Ipv4Pattern = /^\d{1,3}(?:\.\d{1,3}){3}$/;
25023
- SerpIntelligencePublicHttpUrlSchema = import_zod29.z.string().url().refine(isPublicHttpUrl, "url must be a public HTTP or HTTPS URL");
25024
- SerpIntelligenceCaptureBodySchema = import_zod29.z.object({
25025
- query: import_zod29.z.string().trim().min(1, "query is required"),
25026
- location: import_zod29.z.string().trim().min(1).optional(),
25027
- gl: import_zod29.z.string().trim().length(2).default("us"),
25028
- hl: import_zod29.z.string().trim().length(2).default("en"),
25029
- device: import_zod29.z.enum(SerpIntelligenceDeviceValues).default("desktop"),
25030
- proxyMode: import_zod29.z.enum(SerpIntelligenceProxyModeValues).default(DEFAULT_PROXY_MODE),
25031
- proxyZip: import_zod29.z.string().regex(/^\d{5}$/).optional(),
25032
- pages: import_zod29.z.number().int().min(1).max(2).default(1),
25033
- debug: import_zod29.z.boolean().default(false),
25034
- includePageSnapshots: import_zod29.z.boolean().default(false),
25035
- pageSnapshotLimit: import_zod29.z.number().int().min(0).max(10).default(0)
25309
+ SerpIntelligencePublicHttpUrlSchema = import_zod30.z.string().url().refine(isPublicHttpUrl, "url must be a public HTTP or HTTPS URL");
25310
+ SerpIntelligenceCaptureBodySchema = import_zod30.z.object({
25311
+ query: import_zod30.z.string().trim().min(1, "query is required"),
25312
+ location: import_zod30.z.string().trim().min(1).optional(),
25313
+ gl: import_zod30.z.string().trim().length(2).default("us"),
25314
+ hl: import_zod30.z.string().trim().length(2).default("en"),
25315
+ device: import_zod30.z.enum(SerpIntelligenceDeviceValues).default("desktop"),
25316
+ proxyMode: import_zod30.z.enum(SerpIntelligenceProxyModeValues).default(DEFAULT_PROXY_MODE),
25317
+ proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional(),
25318
+ pages: import_zod30.z.number().int().min(1).max(2).default(1),
25319
+ debug: import_zod30.z.boolean().default(false),
25320
+ includePageSnapshots: import_zod30.z.boolean().default(false),
25321
+ pageSnapshotLimit: import_zod30.z.number().int().min(0).max(10).default(0)
25036
25322
  }).strict();
25037
- SerpIntelligencePageSnapshotRequestSchema = import_zod29.z.object({
25323
+ SerpIntelligencePageSnapshotRequestSchema = import_zod30.z.object({
25038
25324
  url: SerpIntelligencePublicHttpUrlSchema,
25039
- sourceKind: import_zod29.z.enum(SerpPageSnapshotSourceKindValues).default("configured_target"),
25040
- sourcePosition: import_zod29.z.number().int().min(1).optional()
25325
+ sourceKind: import_zod30.z.enum(SerpPageSnapshotSourceKindValues).default("configured_target"),
25326
+ sourcePosition: import_zod30.z.number().int().min(1).optional()
25041
25327
  }).strict();
25042
- SerpIntelligencePageSnapshotsBodySchema = import_zod29.z.object({
25043
- urls: import_zod29.z.array(SerpIntelligencePublicHttpUrlSchema).min(1).max(25),
25044
- targets: import_zod29.z.array(SerpIntelligencePageSnapshotRequestSchema).min(1).max(25).optional(),
25045
- maxConcurrency: import_zod29.z.number().int().min(1).max(5).default(2),
25046
- timeoutMs: import_zod29.z.number().int().min(1e3).max(6e4).default(15e3),
25047
- debug: import_zod29.z.boolean().default(false)
25328
+ SerpIntelligencePageSnapshotsBodySchema = import_zod30.z.object({
25329
+ urls: import_zod30.z.array(SerpIntelligencePublicHttpUrlSchema).min(1).max(25),
25330
+ targets: import_zod30.z.array(SerpIntelligencePageSnapshotRequestSchema).min(1).max(25).optional(),
25331
+ maxConcurrency: import_zod30.z.number().int().min(1).max(5).default(2),
25332
+ timeoutMs: import_zod30.z.number().int().min(1e3).max(6e4).default(15e3),
25333
+ debug: import_zod30.z.boolean().default(false)
25048
25334
  }).strict();
25049
- SerpIntelligenceAICitationSchema = import_zod29.z.object({
25050
- text: import_zod29.z.string(),
25051
- href: import_zod29.z.string()
25335
+ SerpIntelligenceAICitationSchema = import_zod30.z.object({
25336
+ text: import_zod30.z.string(),
25337
+ href: import_zod30.z.string()
25052
25338
  }).strict();
25053
- SerpIntelligenceOrganicResultSchema = import_zod29.z.object({
25054
- position: import_zod29.z.number().int().min(1),
25055
- title: import_zod29.z.string(),
25056
- url: import_zod29.z.string(),
25057
- domain: import_zod29.z.string(),
25058
- cite: import_zod29.z.string().nullable(),
25059
- snippet: import_zod29.z.string().nullable(),
25060
- isRedditStyle: import_zod29.z.boolean(),
25061
- inlineRating: import_zod29.z.object({
25062
- value: import_zod29.z.string(),
25063
- count: import_zod29.z.string()
25064
- }).strict().nullable()
25339
+ SerpIntelligenceOrganicResultSchema = import_zod30.z.object({
25340
+ position: import_zod30.z.number().int().min(1),
25341
+ title: import_zod30.z.string(),
25342
+ url: import_zod30.z.string(),
25343
+ domain: import_zod30.z.string(),
25344
+ cite: import_zod30.z.string().nullable(),
25345
+ snippet: import_zod30.z.string().nullable(),
25346
+ isRedditStyle: import_zod30.z.boolean(),
25347
+ inlineRating: import_zod30.z.object({
25348
+ value: import_zod30.z.string(),
25349
+ count: import_zod30.z.string()
25350
+ }).strict().nullable()
25065
25351
  }).strict();
25066
- SerpIntelligenceLocationEvidenceSchema = import_zod29.z.object({
25067
- status: import_zod29.z.enum(SerpIntelligenceLocalizationStatusValues),
25068
- expected: import_zod29.z.object({
25069
- city: import_zod29.z.string(),
25070
- regionCode: import_zod29.z.string().nullable(),
25071
- canonicalLocation: import_zod29.z.string()
25352
+ SerpIntelligenceLocationEvidenceSchema = import_zod30.z.object({
25353
+ status: import_zod30.z.enum(SerpIntelligenceLocalizationStatusValues),
25354
+ expected: import_zod30.z.object({
25355
+ city: import_zod30.z.string(),
25356
+ regionCode: import_zod30.z.string().nullable(),
25357
+ canonicalLocation: import_zod30.z.string()
25072
25358
  }).strict().nullable(),
25073
- candidates: import_zod29.z.array(import_zod29.z.object({
25074
- city: import_zod29.z.string(),
25075
- regionCode: import_zod29.z.string(),
25076
- count: import_zod29.z.number().int().min(0),
25077
- examples: import_zod29.z.array(import_zod29.z.string())
25359
+ candidates: import_zod30.z.array(import_zod30.z.object({
25360
+ city: import_zod30.z.string(),
25361
+ regionCode: import_zod30.z.string(),
25362
+ count: import_zod30.z.number().int().min(0),
25363
+ examples: import_zod30.z.array(import_zod30.z.string())
25078
25364
  }).strict())
25079
25365
  }).strict();
25080
- SerpIntelligenceHarvestResultSchema = import_zod29.z.object({
25081
- seed: import_zod29.z.string(),
25082
- location: import_zod29.z.string().nullable(),
25083
- extractedAt: import_zod29.z.string(),
25084
- totalQuestions: import_zod29.z.number().int().min(0),
25085
- surface: import_zod29.z.enum(["web", "aim", "unknown"]),
25086
- aiOverview: import_zod29.z.object({
25087
- detected: import_zod29.z.boolean(),
25088
- text: import_zod29.z.string().nullable(),
25089
- citations: import_zod29.z.array(SerpIntelligenceAICitationSchema),
25090
- expanded: import_zod29.z.boolean().optional(),
25091
- fullyExpanded: import_zod29.z.boolean().optional(),
25092
- sections: import_zod29.z.array(import_zod29.z.string()).optional()
25366
+ SerpIntelligenceHarvestResultSchema = import_zod30.z.object({
25367
+ seed: import_zod30.z.string(),
25368
+ location: import_zod30.z.string().nullable(),
25369
+ extractedAt: import_zod30.z.string(),
25370
+ totalQuestions: import_zod30.z.number().int().min(0),
25371
+ surface: import_zod30.z.enum(["web", "aim", "unknown"]),
25372
+ aiOverview: import_zod30.z.object({
25373
+ detected: import_zod30.z.boolean(),
25374
+ text: import_zod30.z.string().nullable(),
25375
+ citations: import_zod30.z.array(SerpIntelligenceAICitationSchema),
25376
+ expanded: import_zod30.z.boolean().optional(),
25377
+ fullyExpanded: import_zod30.z.boolean().optional(),
25378
+ sections: import_zod30.z.array(import_zod30.z.string()).optional()
25093
25379
  }).strict(),
25094
- aiMode: import_zod29.z.object({
25095
- detected: import_zod29.z.boolean(),
25096
- text: import_zod29.z.string().nullable(),
25097
- citations: import_zod29.z.array(SerpIntelligenceAICitationSchema)
25380
+ aiMode: import_zod30.z.object({
25381
+ detected: import_zod30.z.boolean(),
25382
+ text: import_zod30.z.string().nullable(),
25383
+ citations: import_zod30.z.array(SerpIntelligenceAICitationSchema)
25098
25384
  }).strict(),
25099
- tree: import_zod29.z.array(import_zod29.z.unknown()),
25100
- flat: import_zod29.z.array(import_zod29.z.unknown()),
25101
- videos: import_zod29.z.array(import_zod29.z.unknown()),
25102
- forums: import_zod29.z.array(import_zod29.z.unknown()),
25103
- organicResults: import_zod29.z.array(SerpIntelligenceOrganicResultSchema),
25104
- localPack: import_zod29.z.array(import_zod29.z.unknown()),
25105
- entityIds: import_zod29.z.object({
25106
- entities: import_zod29.z.array(import_zod29.z.object({
25107
- name: import_zod29.z.string(),
25108
- kgId: import_zod29.z.string().nullable(),
25109
- cid: import_zod29.z.string().nullable(),
25110
- gcid: import_zod29.z.string().nullable()
25385
+ tree: import_zod30.z.array(import_zod30.z.unknown()),
25386
+ flat: import_zod30.z.array(import_zod30.z.unknown()),
25387
+ videos: import_zod30.z.array(import_zod30.z.unknown()),
25388
+ forums: import_zod30.z.array(import_zod30.z.unknown()),
25389
+ organicResults: import_zod30.z.array(SerpIntelligenceOrganicResultSchema),
25390
+ localPack: import_zod30.z.array(import_zod30.z.unknown()),
25391
+ entityIds: import_zod30.z.object({
25392
+ entities: import_zod30.z.array(import_zod30.z.object({
25393
+ name: import_zod30.z.string(),
25394
+ kgId: import_zod30.z.string().nullable(),
25395
+ cid: import_zod30.z.string().nullable(),
25396
+ gcid: import_zod30.z.string().nullable()
25111
25397
  }).strict()),
25112
- kgIds: import_zod29.z.array(import_zod29.z.string()),
25113
- cids: import_zod29.z.array(import_zod29.z.string()),
25114
- gcids: import_zod29.z.array(import_zod29.z.string())
25398
+ kgIds: import_zod30.z.array(import_zod30.z.string()),
25399
+ cids: import_zod30.z.array(import_zod30.z.string()),
25400
+ gcids: import_zod30.z.array(import_zod30.z.string())
25115
25401
  }).strict(),
25116
- stats: import_zod29.z.object({
25117
- seed: import_zod29.z.string(),
25118
- totalQuestions: import_zod29.z.number().int().min(0),
25119
- maxDepthReached: import_zod29.z.number().int().min(0),
25120
- durationMs: import_zod29.z.number().min(0),
25121
- errorCount: import_zod29.z.number().int().min(0)
25402
+ stats: import_zod30.z.object({
25403
+ seed: import_zod30.z.string(),
25404
+ totalQuestions: import_zod30.z.number().int().min(0),
25405
+ maxDepthReached: import_zod30.z.number().int().min(0),
25406
+ durationMs: import_zod30.z.number().min(0),
25407
+ errorCount: import_zod30.z.number().int().min(0)
25122
25408
  }).strict(),
25123
- diagnostics: import_zod29.z.object({
25124
- completionStatus: import_zod29.z.enum(["paa_found", "no_paa", "serp_only"]),
25125
- problem: import_zod29.z.null(),
25126
- warnings: import_zod29.z.array(import_zod29.z.unknown()).optional(),
25127
- debug: import_zod29.z.object({
25409
+ diagnostics: import_zod30.z.object({
25410
+ completionStatus: import_zod30.z.enum(["paa_found", "no_paa", "serp_only"]),
25411
+ problem: import_zod30.z.null(),
25412
+ warnings: import_zod30.z.array(import_zod30.z.unknown()).optional(),
25413
+ debug: import_zod30.z.object({
25128
25414
  locationEvidence: SerpIntelligenceLocationEvidenceSchema.optional()
25129
25415
  }).passthrough().optional()
25130
25416
  }).passthrough(),
25131
- whatPeopleSaying: import_zod29.z.array(import_zod29.z.unknown())
25417
+ whatPeopleSaying: import_zod30.z.array(import_zod30.z.unknown())
25132
25418
  }).strict();
25133
- SerpIntelligenceCaptureAttemptSchema = import_zod29.z.object({
25134
- attemptNumber: import_zod29.z.number().int().min(1),
25135
- outcome: import_zod29.z.enum(SerpIntelligenceAttemptOutcomeValues),
25136
- startedAt: import_zod29.z.string().optional(),
25137
- completedAt: import_zod29.z.string().optional(),
25138
- durationMs: import_zod29.z.number().min(0).optional(),
25139
- problemCode: import_zod29.z.string().optional(),
25140
- message: import_zod29.z.string().optional(),
25141
- kernelSessionId: import_zod29.z.string().nullable().optional(),
25142
- cleanupSucceeded: import_zod29.z.boolean().nullable().optional()
25419
+ SerpIntelligenceCaptureAttemptSchema = import_zod30.z.object({
25420
+ attemptNumber: import_zod30.z.number().int().min(1),
25421
+ outcome: import_zod30.z.enum(SerpIntelligenceAttemptOutcomeValues),
25422
+ startedAt: import_zod30.z.string().optional(),
25423
+ completedAt: import_zod30.z.string().optional(),
25424
+ durationMs: import_zod30.z.number().min(0).optional(),
25425
+ problemCode: import_zod30.z.string().optional(),
25426
+ message: import_zod30.z.string().optional(),
25427
+ kernelSessionId: import_zod30.z.string().nullable().optional(),
25428
+ cleanupSucceeded: import_zod30.z.boolean().nullable().optional()
25143
25429
  }).strict();
25144
- SerpPageSnapshotCaptureSchema = import_zod29.z.object({
25430
+ SerpPageSnapshotCaptureSchema = import_zod30.z.object({
25145
25431
  url: SerpIntelligencePublicHttpUrlSchema,
25146
25432
  requestedUrl: SerpIntelligencePublicHttpUrlSchema,
25147
25433
  finalUrl: SerpIntelligencePublicHttpUrlSchema.nullable(),
25148
- sourceKind: import_zod29.z.enum(SerpPageSnapshotSourceKindValues),
25149
- sourcePosition: import_zod29.z.number().int().min(1).nullable(),
25150
- status: import_zod29.z.enum(SerpPageFetchStatusValues),
25151
- fetchedVia: import_zod29.z.enum(SerpPageFetchedViaValues).nullable(),
25152
- httpStatus: import_zod29.z.number().int().min(100).max(599).nullable(),
25153
- contentType: import_zod29.z.string().nullable(),
25154
- title: import_zod29.z.string().nullable(),
25434
+ sourceKind: import_zod30.z.enum(SerpPageSnapshotSourceKindValues),
25435
+ sourcePosition: import_zod30.z.number().int().min(1).nullable(),
25436
+ status: import_zod30.z.enum(SerpPageFetchStatusValues),
25437
+ fetchedVia: import_zod30.z.enum(SerpPageFetchedViaValues).nullable(),
25438
+ httpStatus: import_zod30.z.number().int().min(100).max(599).nullable(),
25439
+ contentType: import_zod30.z.string().nullable(),
25440
+ title: import_zod30.z.string().nullable(),
25155
25441
  canonicalUrl: SerpIntelligencePublicHttpUrlSchema.nullable(),
25156
- metaDescription: import_zod29.z.string().nullable(),
25157
- headings: import_zod29.z.array(import_zod29.z.object({
25158
- level: import_zod29.z.number().int().min(1).max(6),
25159
- text: import_zod29.z.string()
25442
+ metaDescription: import_zod30.z.string().nullable(),
25443
+ headings: import_zod30.z.array(import_zod30.z.object({
25444
+ level: import_zod30.z.number().int().min(1).max(6),
25445
+ text: import_zod30.z.string()
25160
25446
  }).strict()).default([]),
25161
- artifact: import_zod29.z.object({
25162
- htmlBlobUrl: import_zod29.z.string().url().nullable(),
25163
- textBlobUrl: import_zod29.z.string().url().nullable(),
25164
- markdownBlobUrl: import_zod29.z.string().url().nullable(),
25165
- screenshotBlobUrl: import_zod29.z.string().url().nullable(),
25166
- contentSha256: import_zod29.z.string().nullable(),
25167
- capturedAt: import_zod29.z.string().nullable()
25447
+ artifact: import_zod30.z.object({
25448
+ htmlBlobUrl: import_zod30.z.string().url().nullable(),
25449
+ textBlobUrl: import_zod30.z.string().url().nullable(),
25450
+ markdownBlobUrl: import_zod30.z.string().url().nullable(),
25451
+ screenshotBlobUrl: import_zod30.z.string().url().nullable(),
25452
+ contentSha256: import_zod30.z.string().nullable(),
25453
+ capturedAt: import_zod30.z.string().nullable()
25168
25454
  }).strict(),
25169
- error: import_zod29.z.object({
25170
- code: import_zod29.z.string(),
25171
- message: import_zod29.z.string()
25455
+ error: import_zod30.z.object({
25456
+ code: import_zod30.z.string(),
25457
+ message: import_zod30.z.string()
25172
25458
  }).strict().nullable()
25173
25459
  }).strict();
25174
- SerpIntelligenceCaptureResponseSchema = import_zod29.z.object({
25460
+ SerpIntelligenceCaptureResponseSchema = import_zod30.z.object({
25175
25461
  harvestResult: SerpIntelligenceHarvestResultSchema,
25176
- attempts: import_zod29.z.array(SerpIntelligenceCaptureAttemptSchema),
25462
+ attempts: import_zod30.z.array(SerpIntelligenceCaptureAttemptSchema),
25177
25463
  locationEvidence: SerpIntelligenceLocationEvidenceSchema.nullable(),
25178
- pageSnapshotArtifacts: import_zod29.z.array(SerpPageSnapshotCaptureSchema),
25179
- billing: import_zod29.z.object({
25180
- creditsUsed: import_zod29.z.number().min(0).optional(),
25181
- requestId: import_zod29.z.string().optional(),
25182
- jobId: import_zod29.z.string().optional()
25464
+ pageSnapshotArtifacts: import_zod30.z.array(SerpPageSnapshotCaptureSchema),
25465
+ billing: import_zod30.z.object({
25466
+ creditsUsed: import_zod30.z.number().min(0).optional(),
25467
+ requestId: import_zod30.z.string().optional(),
25468
+ jobId: import_zod30.z.string().optional()
25183
25469
  }).strict().optional()
25184
25470
  }).strict();
25185
- SerpIntelligencePageSnapshotsResponseSchema = import_zod29.z.object({
25186
- pageSnapshotArtifacts: import_zod29.z.array(SerpPageSnapshotCaptureSchema),
25187
- attempts: import_zod29.z.array(SerpIntelligenceCaptureAttemptSchema).default([])
25471
+ SerpIntelligencePageSnapshotsResponseSchema = import_zod30.z.object({
25472
+ pageSnapshotArtifacts: import_zod30.z.array(SerpPageSnapshotCaptureSchema),
25473
+ attempts: import_zod30.z.array(SerpIntelligenceCaptureAttemptSchema).default([])
25188
25474
  }).strict();
25189
25475
  }
25190
25476
  });
@@ -25408,11 +25694,11 @@ function pageSnapshotTargetsFromBody(body) {
25408
25694
  sourcePosition: null
25409
25695
  }));
25410
25696
  }
25411
- var import_hono11, SERP_INTELLIGENCE_RATE_LIMIT, SERP_INTELLIGENCE_RATE_WINDOW_SECONDS, POST_CAPTURE_ROUTE_LABEL, POST_PAGE_SNAPSHOTS_ROUTE_LABEL, serpIntelligenceApp;
25697
+ var import_hono13, SERP_INTELLIGENCE_RATE_LIMIT, SERP_INTELLIGENCE_RATE_WINDOW_SECONDS, POST_CAPTURE_ROUTE_LABEL, POST_PAGE_SNAPSHOTS_ROUTE_LABEL, serpIntelligenceApp;
25412
25698
  var init_serp_intelligence_routes = __esm({
25413
25699
  "src/api/serp-intelligence-routes.ts"() {
25414
25700
  "use strict";
25415
- import_hono11 = require("hono");
25701
+ import_hono13 = require("hono");
25416
25702
  init_browser_service_env();
25417
25703
  init_page_snapshot_extractor();
25418
25704
  init_serp_capture_service();
@@ -25425,7 +25711,7 @@ var init_serp_intelligence_routes = __esm({
25425
25711
  SERP_INTELLIGENCE_RATE_WINDOW_SECONDS = 60;
25426
25712
  POST_CAPTURE_ROUTE_LABEL = "POST /capture";
25427
25713
  POST_PAGE_SNAPSHOTS_ROUTE_LABEL = "POST /page-snapshots";
25428
- serpIntelligenceApp = new import_hono11.Hono();
25714
+ serpIntelligenceApp = new import_hono13.Hono();
25429
25715
  serpIntelligenceApp.use("*", createApiKeyAuth());
25430
25716
  serpIntelligenceApp.post("/capture", async (c) => {
25431
25717
  void POST_CAPTURE_ROUTE_LABEL;
@@ -25557,7 +25843,7 @@ var PACKAGE_VERSION;
25557
25843
  var init_version = __esm({
25558
25844
  "src/version.ts"() {
25559
25845
  "use strict";
25560
- PACKAGE_VERSION = "0.3.40";
25846
+ PACKAGE_VERSION = "0.3.44";
25561
25847
  }
25562
25848
  });
25563
25849
 
@@ -25646,183 +25932,193 @@ Multi-step orchestrations \u2014 prefer these over hand-chaining primitives when
25646
25932
  });
25647
25933
 
25648
25934
  // src/mcp/mcp-tool-schemas.ts
25649
- var import_zod30, HarvestPaaInputSchema, ExtractUrlInputSchema, MapSiteUrlsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryWorkflowOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, MapsPlaceIntelOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, RedditThreadOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema;
25935
+ var import_zod31, HarvestPaaInputSchema, ExtractUrlInputSchema, MapSiteUrlsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryWorkflowOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, MapsPlaceIntelOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema;
25650
25936
  var init_mcp_tool_schemas = __esm({
25651
25937
  "src/mcp/mcp-tool-schemas.ts"() {
25652
25938
  "use strict";
25653
- import_zod30 = require("zod");
25939
+ import_zod31 = require("zod");
25654
25940
  init_schemas3();
25655
25941
  HarvestPaaInputSchema = {
25656
- query: import_zod30.z.string().min(1).describe('Core search topic only. If the user says "best hvac company in Denver CO", use query="best hvac company" and location="Denver, CO". Do not include the location in query when it can be separated.'),
25657
- location: import_zod30.z.string().optional().describe('City, region, or country for geo-targeted results, inferred from the user request when present, e.g. "Denver, CO", "Tokyo, Japan", "London, UK".'),
25658
- maxQuestions: import_zod30.z.number().int().min(1).max(200).default(30).describe("Number of PAA questions to extract. Default 30. Maximum 200. Use 10 for quick probes, 30 for normal research, 100-200 when the user asks for everything/full/deep research. Larger harvests get a longer server time budget (151-200 questions \u2192 up to 280s). Credits are charged by extracted question; unused request hold is refunded."),
25659
- gl: import_zod30.z.string().length(2).default("us").describe("Google country code inferred from location or user language. Examples: United States us, United Kingdom gb, Japan jp, Canada ca, Australia au."),
25660
- hl: import_zod30.z.string().default("en").describe("Google interface/content language inferred from the user request. Use en unless the user asks for another language or locale."),
25661
- device: import_zod30.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings."),
25662
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset \u2014 routing is automatic (clean egress by default; residential only when a location is given, with fallback). Set "location" only to force local-pack targeting.'),
25663
- proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override for residential location proxy targeting. Use only with proxyMode location when the user gives a specific ZIP or city-center targeting needs to be forced."),
25664
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior.")
25942
+ query: import_zod31.z.string().min(1).describe('The search query. For localized results, KEEP the place in the query text \u2014 if the user says "best hvac company in Denver CO", use query="best hvac company Denver CO" (and also set location="Denver, CO"). City-in-query is what localizes results reliably; do not strip it out.'),
25943
+ location: import_zod31.z.string().optional().describe('City, region, or country for geo signals (uule + location evidence), e.g. "Denver, CO", "Tokyo, Japan". Set it alongside a city-in-query wording; on its own it does NOT reliably localize results.'),
25944
+ maxQuestions: import_zod31.z.number().int().min(1).max(200).default(30).describe("Number of PAA questions to extract. Default 30. Maximum 200. Use 10 for quick probes, 30 for normal research, 100-200 when the user asks for everything/full/deep research. Larger harvests get a longer server time budget (151-200 questions \u2192 up to 280s). Credits are charged by extracted question; unused request hold is refunded."),
25945
+ gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from location or user language. Examples: United States us, United Kingdom gb, Japan jp, Canada ca, Australia au."),
25946
+ hl: import_zod31.z.string().default("en").describe("Google interface/content language inferred from the user request. Use en unless the user asks for another language or locale."),
25947
+ device: import_zod31.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings."),
25948
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress \u2014 reliable). Do NOT set "location" just because the user named a city; localized results come from city-in-query wording. "location" forces a residential geo-IP for rank-tracking fidelity only, is frequently CAPTCHA-blocked, and should be used only when the user explicitly demands as-seen-from-the-city results and accepts failures.'),
25949
+ proxyZip: import_zod31.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location" (see its warning); ignored otherwise.'),
25950
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior.")
25665
25951
  };
25666
25952
  ExtractUrlInputSchema = {
25667
- url: import_zod30.z.string().url().describe("Public http/https URL to extract. Use this when the user provides one specific page URL."),
25668
- screenshot: import_zod30.z.boolean().default(false).describe("Also capture a full-page screenshot of the URL. Saved to ~/Downloads/mcp-scraper/screenshots/ and returned inline. Use when the user asks to see or capture the page visually."),
25669
- screenshotDevice: import_zod30.z.enum(["desktop", "mobile"]).default("desktop").describe("Viewport for screenshot. desktop = 1440\xD7900. mobile = 390\xD7844. Default desktop."),
25670
- extractBranding: import_zod30.z.boolean().default(false).describe("Extract brand colors, fonts, logo, and favicon using a rendered browser session. Returns colorScheme (light/dark), colors (primary/accent/background/text/heading as hex), fonts (heading/body family names), and assets (logo URL, favicon URL). Use when the user asks about brand colors, site theme, or brand assets."),
25671
- downloadMedia: import_zod30.z.boolean().default(false).describe("Extract and download all page media (images, video, audio) to ~/Downloads/mcp-scraper/media/. Ad networks, tracking pixels, and noise URLs are filtered automatically. Use when the user asks to download or harvest assets from a page."),
25672
- mediaTypes: import_zod30.z.array(import_zod30.z.enum(["image", "video", "audio"])).default(["image", "video", "audio"]).describe("Which media types to download. Default all three."),
25673
- allowLocal: import_zod30.z.boolean().default(false).describe("Allow localhost and private-network URLs. For local development only."),
25674
- depositToVault: import_zod30.z.boolean().default(false).describe("Also save the full page content into the user's MCP Memory Library vault, server-side. The complete body is stored and embedded for semantic recall WITHOUT passing through this conversation \u2014 the tool result only confirms the saved note. Use when the user asks to save/remember/store a page, or to build a knowledge base from scrapes."),
25675
- vaultName: import_zod30.z.string().trim().min(1).max(120).optional().describe("Optional vault to deposit into. Defaults to the user's personal vault.")
25953
+ url: import_zod31.z.string().url().describe("Public http/https URL to extract. Use this when the user provides one specific page URL."),
25954
+ screenshot: import_zod31.z.boolean().default(false).describe("Also capture a full-page screenshot of the URL. Saved to ~/Downloads/mcp-scraper/screenshots/ and returned inline. Use when the user asks to see or capture the page visually."),
25955
+ screenshotDevice: import_zod31.z.enum(["desktop", "mobile"]).default("desktop").describe("Viewport for screenshot. desktop = 1440\xD7900. mobile = 390\xD7844. Default desktop."),
25956
+ extractBranding: import_zod31.z.boolean().default(false).describe("Extract brand colors, fonts, logo, and favicon using a rendered browser session. Returns colorScheme (light/dark), colors (primary/accent/background/text/heading as hex), fonts (heading/body family names), and assets (logo URL, favicon URL). Use when the user asks about brand colors, site theme, or brand assets."),
25957
+ downloadMedia: import_zod31.z.boolean().default(false).describe("Extract and download all page media (images, video, audio) to ~/Downloads/mcp-scraper/media/. Ad networks, tracking pixels, and noise URLs are filtered automatically. Use when the user asks to download or harvest assets from a page."),
25958
+ mediaTypes: import_zod31.z.array(import_zod31.z.enum(["image", "video", "audio"])).default(["image", "video", "audio"]).describe("Which media types to download. Default all three."),
25959
+ allowLocal: import_zod31.z.boolean().default(false).describe("Allow localhost and private-network URLs. For local development only."),
25960
+ depositToVault: import_zod31.z.boolean().default(false).describe("Also save the full page content into the user's MCP Memory Library vault, server-side. The complete body is stored and embedded for semantic recall WITHOUT passing through this conversation \u2014 the tool result only confirms the saved note. Use when the user asks to save/remember/store a page, or to build a knowledge base from scrapes."),
25961
+ vaultName: import_zod31.z.string().trim().min(1).max(120).optional().describe("Optional vault to deposit into. Defaults to the user's personal vault.")
25676
25962
  };
25677
25963
  MapSiteUrlsInputSchema = {
25678
- url: import_zod30.z.string().url().describe("Public website URL or domain to crawl for internal URLs. Use before extract_site when the user asks to audit/map/crawl a site."),
25679
- maxUrls: import_zod30.z.number().int().min(1).max(1e4).optional().describe("Maximum URLs to discover. Use 100 for normal maps, up to 10000 for a full inventory. Large maps (over 500 URLs) write the complete inventory to a local file and return only a summary plus the file path instead of the full list inline.")
25964
+ url: import_zod31.z.string().url().describe("Public website URL or domain to crawl for internal URLs. Use before extract_site when the user asks to audit/map/crawl a site."),
25965
+ maxUrls: import_zod31.z.number().int().min(1).max(1e4).optional().describe("Maximum URLs to discover. Use 100 for normal maps, up to 10000 for a full inventory. Large maps (over 500 URLs) write the complete inventory to a local file and return only a summary plus the file path instead of the full list inline.")
25680
25966
  };
25681
25967
  ExtractSiteInputSchema = {
25682
- url: import_zod30.z.string().url().describe("Public website URL or domain to crawl for page CONTENT across multiple pages (map + scrape). Use when the user wants the content/text/markdown of a site's pages. For a technical SEO audit (issues, link graph, indexability, headings, image weights) use audit_site instead \u2014 extract_site returns content only, not analysis."),
25683
- maxPages: import_zod30.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to extract. Use 50 for a normal crawl, up to 10000 for a full-site bulk scrape. Bulk crawls (over 25 pages) switch to folder mode: every page is saved as its own Markdown file in a local folder and the response returns only a summary plus the folder path, so the full content never floods the context window."),
25684
- rotateProxies: import_zod30.z.boolean().optional().describe("Route page fetches through rotating residential proxies in headful browsers to defeat rate-limiting and bot blocks (403/429). Discovers URLs from the sitemap, fetches in batches with a fresh proxy per batch, retries failures on a new proxy, and automatically parallelizes across the account's concurrency slots. Slower and pricier than the default fetch path, so use only when a site blocks normal crawling."),
25685
- rotateProxyEvery: import_zod30.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, how many pages to fetch per browser/proxy before discarding it and minting a fresh one. Default 30. Lower values rotate IPs more aggressively against strict rate limits."),
25686
- formats: import_zod30.z.array(import_zod30.z.enum(["markdown", "links", "json", "images", "branding"])).optional().describe("Which data formats to include in the per-page output. markdown=page content as Markdown, links=internal/external link graph, json=structured data/schema, images=per-page image URLs (links only, no downloads), branding=site-level logo/colors/fonts captured once from the homepage (requires a browser, adds time). markdown, links, json, and images are always captured cheaply from the HTML; branding is the only opt-in capture. Defaults to markdown+links when omitted.")
25968
+ url: import_zod31.z.string().url().describe("Public website URL or domain to crawl for page CONTENT across multiple pages (map + scrape). Use when the user wants the content/text/markdown of a site's pages. For a technical SEO audit (issues, link graph, indexability, headings, image weights) use audit_site instead \u2014 extract_site returns content only, not analysis."),
25969
+ maxPages: import_zod31.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to extract. Use 50 for a normal crawl, up to 10000 for a full-site bulk scrape. Bulk crawls (over 25 pages) switch to folder mode: every page is saved as its own Markdown file in a local folder and the response returns only a summary plus the folder path, so the full content never floods the context window."),
25970
+ rotateProxies: import_zod31.z.boolean().optional().describe("Route page fetches through rotating residential proxies in headful browsers to defeat rate-limiting and bot blocks (403/429). Discovers URLs from the sitemap, fetches in batches with a fresh proxy per batch, retries failures on a new proxy, and automatically parallelizes across the account's concurrency slots. Slower and pricier than the default fetch path, so use only when a site blocks normal crawling."),
25971
+ rotateProxyEvery: import_zod31.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, how many pages to fetch per browser/proxy before discarding it and minting a fresh one. Default 30. Lower values rotate IPs more aggressively against strict rate limits."),
25972
+ formats: import_zod31.z.array(import_zod31.z.enum(["markdown", "links", "json", "images", "branding"])).optional().describe("Which data formats to include in the per-page output. markdown=page content as Markdown, links=internal/external link graph, json=structured data/schema, images=per-page image URLs (links only, no downloads), branding=site-level logo/colors/fonts captured once from the homepage (requires a browser, adds time). markdown, links, json, and images are always captured cheaply from the HTML; branding is the only opt-in capture. Defaults to markdown+links when omitted.")
25687
25973
  };
25688
25974
  AuditSiteInputSchema = {
25689
- url: import_zod30.z.string().url().describe("Public website URL or domain to run a full technical SEO audit on. Use when the user asks for a technical audit, SEO audit, site health check, or a Screaming-Frog-style crawl \u2014 i.e. they want ANALYSIS (issues, internal link graph, indexability, heading breakdown, image sizes/formats), not just page content. For plain content scraping use extract_site instead."),
25690
- maxPages: import_zod30.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to crawl and audit. Use 50 for a normal audit, up to 10000 for a full-site audit. The audit always writes a folder of analysis files (report.md, issues.json, pages.jsonl, links.jsonl, link-metrics.jsonl, images.jsonl) plus per-page content, and returns a headline summary plus the folder path."),
25691
- rotateProxies: import_zod30.z.boolean().optional().describe("Route page fetches through rotating residential proxies to defeat rate-limiting and bot blocks (403/429). Slower and pricier than the default fetch path, so use only when a site blocks normal crawling."),
25692
- rotateProxyEvery: import_zod30.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, how many pages to fetch per browser/proxy before discarding it and minting a fresh one. Default 30.")
25975
+ url: import_zod31.z.string().url().describe("Public website URL or domain to run a full technical SEO audit on. Use when the user asks for a technical audit, SEO audit, site health check, or a Screaming-Frog-style crawl \u2014 i.e. they want ANALYSIS (issues, internal link graph, indexability, heading breakdown, image sizes/formats), not just page content. For plain content scraping use extract_site instead."),
25976
+ maxPages: import_zod31.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to crawl and audit. Use 50 for a normal audit, up to 10000 for a full-site audit. The audit always writes a folder of analysis files (report.md, issues.json, pages.jsonl, links.jsonl, link-metrics.jsonl, images.jsonl) plus per-page content, and returns a headline summary plus the folder path."),
25977
+ rotateProxies: import_zod31.z.boolean().optional().describe("Route page fetches through rotating residential proxies to defeat rate-limiting and bot blocks (403/429). Slower and pricier than the default fetch path, so use only when a site blocks normal crawling."),
25978
+ rotateProxyEvery: import_zod31.z.number().int().min(1).max(100).optional().describe("When rotateProxies is on, how many pages to fetch per browser/proxy before discarding it and minting a fresh one. Default 30.")
25693
25979
  };
25694
25980
  YoutubeHarvestInputSchema = {
25695
- mode: import_zod30.z.enum(["search", "channel"]).describe("Use search for topic/keyword requests. Use channel when the user provides @handle, channel ID, or channel URL."),
25696
- query: import_zod30.z.string().optional().describe("Required when mode is search. The YouTube search topic in the user\u2019s words."),
25697
- channelHandle: import_zod30.z.string().optional().describe("YouTube channel handle, channel ID, or URL. Examples: @mkbhd, UC..., https://youtube.com/@mkbhd."),
25698
- maxVideos: import_zod30.z.number().int().min(1).max(500).default(50).describe("Number of videos to return. Default 50, maximum 500. Use 10-25 for quick topic discovery, 50 for normal channel/search harvests, and larger values only when the user asks for full channel/history because large responses consume more context.")
25981
+ mode: import_zod31.z.enum(["search", "channel"]).describe("Use search for topic/keyword requests. Use channel when the user provides @handle, channel ID, or channel URL."),
25982
+ query: import_zod31.z.string().optional().describe("Required when mode is search. The YouTube search topic in the user\u2019s words."),
25983
+ channelHandle: import_zod31.z.string().optional().describe("YouTube channel handle, channel ID, or URL. Examples: @mkbhd, UC..., https://youtube.com/@mkbhd."),
25984
+ maxVideos: import_zod31.z.number().int().min(1).max(500).default(50).describe("Number of videos to return. Default 50, maximum 500. Use 10-25 for quick topic discovery, 50 for normal channel/search harvests, and larger values only when the user asks for full channel/history because large responses consume more context.")
25699
25985
  };
25700
25986
  YoutubeTranscribeInputSchema = {
25701
- videoId: import_zod30.z.string().min(1).optional().describe("YouTube video ID, e.g. dQw4w9WgXcQ. Use only an ID returned by youtube_harvest or visible in a YouTube URL; do not invent one."),
25702
- url: import_zod30.z.string().url().optional().describe("Full YouTube URL, e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ. Use this when the user pasted a URL instead of an ID. Provide videoId or url.")
25987
+ videoId: import_zod31.z.string().min(1).optional().describe("YouTube video ID, e.g. dQw4w9WgXcQ. Use only an ID returned by youtube_harvest or visible in a YouTube URL; do not invent one."),
25988
+ url: import_zod31.z.string().url().optional().describe("Full YouTube URL, e.g. https://www.youtube.com/watch?v=dQw4w9WgXcQ or https://youtu.be/dQw4w9WgXcQ. Use this when the user pasted a URL instead of an ID. Provide videoId or url.")
25703
25989
  };
25704
25990
  FacebookPageIntelInputSchema = {
25705
- pageId: import_zod30.z.string().optional().describe("Facebook advertiser/page ID. Use only a pageId returned by facebook_ad_search/facebook_page_intel or copied from Facebook Ad Library; do not construct one yourself."),
25706
- libraryId: import_zod30.z.string().optional().describe("Facebook Ad Library archive ID for a known ad or advertiser sample. Use a libraryId returned by facebook_ad_search, or a libraryId/adArchiveId visible in Ad Library."),
25707
- query: import_zod30.z.string().optional().describe("Advertiser or brand name when pageId/libraryId is not known. One of pageId, libraryId, or query is required."),
25708
- maxAds: import_zod30.z.number().int().min(1).max(200).default(50).describe("Maximum ads to inspect. Default 50, maximum 200. Prefer 25-50 for focused advertiser scans; use 100-200 only when the user asks for a broad ad archive sweep."),
25709
- country: import_zod30.z.string().length(2).default("US").describe("Two-letter Ad Library country code. Default US. Examples: US, CA, GB, AU. Infer from the user request when they name a country.")
25991
+ pageId: import_zod31.z.string().optional().describe("Facebook advertiser/page ID. Use only a pageId returned by facebook_ad_search/facebook_page_intel or copied from Facebook Ad Library; do not construct one yourself."),
25992
+ libraryId: import_zod31.z.string().optional().describe("Facebook Ad Library archive ID for a known ad or advertiser sample. Use a libraryId returned by facebook_ad_search, or a libraryId/adArchiveId visible in Ad Library."),
25993
+ query: import_zod31.z.string().optional().describe("Advertiser or brand name when pageId/libraryId is not known. One of pageId, libraryId, or query is required."),
25994
+ maxAds: import_zod31.z.number().int().min(1).max(200).default(50).describe("Maximum ads to inspect. Default 50, maximum 200. Prefer 25-50 for focused advertiser scans; use 100-200 only when the user asks for a broad ad archive sweep."),
25995
+ country: import_zod31.z.string().length(2).default("US").describe("Two-letter Ad Library country code. Default US. Examples: US, CA, GB, AU. Infer from the user request when they name a country.")
25710
25996
  };
25711
25997
  FacebookAdSearchInputSchema = {
25712
- query: import_zod30.z.string().min(1).describe("Advertiser, brand, competitor, niche, or keyword to search in Facebook Ad Library."),
25713
- country: import_zod30.z.string().length(2).default("US").describe("Two-letter Ad Library country code. Default US. Examples: US, CA, GB, AU."),
25714
- maxResults: import_zod30.z.number().int().min(1).max(20).default(10).describe("Maximum advertisers to return. Default 10, maximum 20. Prefer tighter search terms over maxing this out.")
25998
+ query: import_zod31.z.string().min(1).describe("Advertiser, brand, competitor, niche, or keyword to search in Facebook Ad Library."),
25999
+ country: import_zod31.z.string().length(2).default("US").describe("Two-letter Ad Library country code. Default US. Examples: US, CA, GB, AU."),
26000
+ maxResults: import_zod31.z.number().int().min(1).max(20).default(10).describe("Maximum advertisers to return. Default 10, maximum 20. Prefer tighter search terms over maxing this out.")
25715
26001
  };
25716
26002
  RedditThreadInputSchema = {
25717
- url: import_zod30.z.string().min(1).describe("A reddit.com thread/post URL (www, old, or new Reddit, or a redd.it link). The service fetches it via old.reddit through a residential proxy and returns the post plus its comment tree."),
25718
- maxComments: import_zod30.z.number().int().min(1).max(2e3).optional().describe("Optional cap on comments returned. Omit to return all captured comments.")
26003
+ url: import_zod31.z.string().min(1).describe("A reddit.com thread/post URL (www, old, or new Reddit, or a redd.it link). The service fetches it via old.reddit through a residential proxy and returns the post plus its comment tree."),
26004
+ maxComments: import_zod31.z.number().int().min(1).max(2e3).optional().describe("Optional cap on comments returned. Omit to return all captured comments.")
26005
+ };
26006
+ VideoFrameAnalysisInputSchema = {
26007
+ sourceUrl: import_zod31.z.string().min(1).describe("A DIRECT video file URL (.mp4/.webm/.mov). Not a YouTube/Facebook/Instagram page URL \u2014 resolve those to a direct media URL first. Videos up to 30 minutes are supported."),
26008
+ intervalS: import_zod31.z.number().min(1).max(30).optional().describe("Preferred seconds between sampled frames (1-30, default 2). Automatically widened for long videos so the whole duration is covered within the frame budget."),
26009
+ maxFrames: import_zod31.z.number().int().min(1).max(120).optional().describe("Max frames analyzed (<=120, default 120). Frames are spread evenly across the whole video."),
26010
+ detail: import_zod31.z.enum(["fast", "standard", "deep"]).optional().describe("Analysis depth. Default standard."),
26011
+ vault: import_zod31.z.string().min(1).optional().describe('Memory vault to save the finished breakdown into. Default "Library".')
26012
+ };
26013
+ VideoFrameAnalysisStatusInputSchema = {
26014
+ runId: import_zod31.z.string().min(1).describe("The runId returned by video_frame_analysis.")
25719
26015
  };
25720
26016
  FacebookAdTranscribeInputSchema = {
25721
- videoUrl: import_zod30.z.string().url().describe("Direct Facebook CDN video URL from a facebook_page_intel ad result. Do not pass a public Facebook reel/post/share URL here; use facebook_video_transcribe for organic Facebook URLs.")
26017
+ videoUrl: import_zod31.z.string().url().describe("Direct Facebook CDN video URL from a facebook_page_intel ad result. Do not pass a public Facebook reel/post/share URL here; use facebook_video_transcribe for organic Facebook URLs.")
25722
26018
  };
25723
26019
  FacebookVideoTranscribeInputSchema = {
25724
- url: import_zod30.z.string().url().describe("Organic Facebook reel, video, watch, post, or share URL from facebook.com, m.facebook.com, or fb.watch. The tool renders the page, extracts the best matching public Facebook CDN MP4 URL, then transcribes it. Use this when the user pastes a normal Facebook video page URL and asks for the transcript or downloadable MP4."),
25725
- quality: import_zod30.z.enum(["best", "hd", "sd"]).default("best").describe("Preferred progressive MP4 quality. Use best by default; hd prefers the highest HD progressive URL; sd forces the SD URL.")
26020
+ url: import_zod31.z.string().url().describe("Organic Facebook reel, video, watch, post, or share URL from facebook.com, m.facebook.com, or fb.watch. The tool renders the page, extracts the best matching public Facebook CDN MP4 URL, then transcribes it. Use this when the user pastes a normal Facebook video page URL and asks for the transcript or downloadable MP4."),
26021
+ quality: import_zod31.z.enum(["best", "hd", "sd"]).default("best").describe("Preferred progressive MP4 quality. Use best by default; hd prefers the highest HD progressive URL; sd forces the SD URL.")
25726
26022
  };
25727
26023
  GoogleAdsSearchInputSchema = {
25728
- query: import_zod30.z.string().min(1).describe("A domain (e.g. getviktor.com) or advertiser/brand name to look up in the Google Ads Transparency Center. Domains resolve to the advertisers running ads that point to that site."),
25729
- region: import_zod30.z.string().length(2).default("US").describe("Two-letter region code for where the ads are shown. Default US. Examples: US, CA, GB, AU."),
25730
- maxResults: import_zod30.z.number().int().min(1).max(20).default(10).describe("Maximum advertisers to return. Default 10, maximum 20.")
26024
+ query: import_zod31.z.string().min(1).describe("A domain (e.g. getviktor.com) or advertiser/brand name to look up in the Google Ads Transparency Center. Domains resolve to the advertisers running ads that point to that site."),
26025
+ region: import_zod31.z.string().length(2).default("US").describe("Two-letter region code for where the ads are shown. Default US. Examples: US, CA, GB, AU."),
26026
+ maxResults: import_zod31.z.number().int().min(1).max(20).default(10).describe("Maximum advertisers to return. Default 10, maximum 20.")
25731
26027
  };
25732
26028
  GoogleAdsPageIntelInputSchema = {
25733
- advertiserId: import_zod30.z.string().optional().describe("Google Ads Transparency advertiser ID (starts with AR...). Use one returned by google_ads_search; do not construct one yourself."),
25734
- domain: import_zod30.z.string().optional().describe("A domain (e.g. getviktor.com) whose primary advertiser to inspect when advertiserId is unknown. One of advertiserId or domain is required."),
25735
- region: import_zod30.z.string().length(2).default("US").describe("Two-letter region code for where the ads are shown. Default US."),
25736
- maxAds: import_zod30.z.number().int().min(1).max(200).default(50).describe("Maximum creatives to inspect and hydrate. Default 50, maximum 200. Prefer 25-50 for focused scans.")
26029
+ advertiserId: import_zod31.z.string().optional().describe("Google Ads Transparency advertiser ID (starts with AR...). Use one returned by google_ads_search; do not construct one yourself."),
26030
+ domain: import_zod31.z.string().optional().describe("A domain (e.g. getviktor.com) whose primary advertiser to inspect when advertiserId is unknown. One of advertiserId or domain is required."),
26031
+ region: import_zod31.z.string().length(2).default("US").describe("Two-letter region code for where the ads are shown. Default US."),
26032
+ maxAds: import_zod31.z.number().int().min(1).max(200).default(50).describe("Maximum creatives to inspect and hydrate. Default 50, maximum 200. Prefer 25-50 for focused scans.")
25737
26033
  };
25738
26034
  GoogleAdsTranscribeInputSchema = {
25739
- videoUrl: import_zod30.z.string().url().describe("Direct googlevideo.com playback URL from a google_ads_page_intel video ad result (the videoUrl field). For YouTube-hosted ads use youtube_transcribe with the returned youtubeVideoId instead.")
26035
+ videoUrl: import_zod31.z.string().url().describe("Direct googlevideo.com playback URL from a google_ads_page_intel video ad result (the videoUrl field). For YouTube-hosted ads use youtube_transcribe with the returned youtubeVideoId instead.")
25740
26036
  };
25741
26037
  InstagramProfileContentInputSchema = {
25742
- handle: import_zod30.z.string().min(1).optional().describe("Instagram handle, with or without @. Provide handle or url."),
25743
- url: import_zod30.z.string().url().optional().describe("Instagram profile URL, e.g. https://www.instagram.com/nasaartemis/. Provide handle or url."),
25744
- profile: import_zod30.z.string().min(1).optional().describe("Optional saved hosted browser profile name to load authenticated Instagram access. If omitted, the server uses its configured default profile when present."),
25745
- saveProfileChanges: import_zod30.z.boolean().optional().describe("Whether to save browser changes back to the hosted profile. Leave unset unless intentionally updating the saved login session."),
25746
- maxItems: import_zod30.z.number().int().min(1).max(2e3).default(50).describe("Maximum profile grid post/reel/tv URLs to collect. Default 50, maximum 2000. Use higher values only when the user asks for a fuller archive."),
25747
- maxScrolls: import_zod30.z.number().int().min(0).max(250).default(10).describe("Maximum pagination scroll attempts. Default 10, maximum 250. Increase for long profiles when Instagram continues loading more grid links."),
25748
- scrollDelayMs: import_zod30.z.number().int().min(250).max(5e3).default(1200).describe("Delay after each pagination scroll before collecting newly loaded links. Default 1200ms. Increase to 2000-3000ms when Instagram loads slowly."),
25749
- stableScrollLimit: import_zod30.z.number().int().min(1).max(10).default(4).describe("Stop after this many consecutive scrolls with no new links or scroll progress. Default 4.")
26038
+ handle: import_zod31.z.string().min(1).optional().describe("Instagram handle, with or without @. Provide handle or url."),
26039
+ url: import_zod31.z.string().url().optional().describe("Instagram profile URL, e.g. https://www.instagram.com/nasaartemis/. Provide handle or url."),
26040
+ profile: import_zod31.z.string().min(1).optional().describe("Optional saved hosted browser profile name to load authenticated Instagram access. If omitted, the server uses its configured default profile when present."),
26041
+ saveProfileChanges: import_zod31.z.boolean().optional().describe("Whether to save browser changes back to the hosted profile. Leave unset unless intentionally updating the saved login session."),
26042
+ maxItems: import_zod31.z.number().int().min(1).max(2e3).default(50).describe("Maximum profile grid post/reel/tv URLs to collect. Default 50, maximum 2000. Use higher values only when the user asks for a fuller archive."),
26043
+ maxScrolls: import_zod31.z.number().int().min(0).max(250).default(10).describe("Maximum pagination scroll attempts. Default 10, maximum 250. Increase for long profiles when Instagram continues loading more grid links."),
26044
+ scrollDelayMs: import_zod31.z.number().int().min(250).max(5e3).default(1200).describe("Delay after each pagination scroll before collecting newly loaded links. Default 1200ms. Increase to 2000-3000ms when Instagram loads slowly."),
26045
+ stableScrollLimit: import_zod31.z.number().int().min(1).max(10).default(4).describe("Stop after this many consecutive scrolls with no new links or scroll progress. Default 4.")
25750
26046
  };
25751
26047
  InstagramMediaDownloadInputSchema = {
25752
- url: import_zod30.z.string().url().describe("Instagram post, reel, or tv URL, e.g. https://www.instagram.com/reel/SHORTCODE/. The tool renders the page, extracts text, image metadata, and Instagram CDN media tracks."),
25753
- profile: import_zod30.z.string().min(1).optional().describe("Optional saved hosted browser profile name to load authenticated Instagram access. If omitted, the server uses its configured default profile when present."),
25754
- saveProfileChanges: import_zod30.z.boolean().optional().describe("Whether to save browser changes back to the hosted profile. Leave unset unless intentionally updating the saved login session."),
25755
- mediaTypes: import_zod30.z.array(import_zod30.z.enum(["image", "video", "audio"])).default(["image", "video", "audio"]).describe("Which media types to download when downloadMedia is true. Reels commonly expose separate video-only and audio-only MP4 tracks."),
25756
- downloadMedia: import_zod30.z.boolean().default(true).describe("Download extracted text/media files to the MCP Scraper output directory when the API server can write files. Always returns extracted media URLs even when false."),
25757
- downloadAllTracks: import_zod30.z.boolean().default(false).describe("Download every captured Instagram MP4 track instead of only the selected best video and audio tracks. Use false by default to avoid duplicate bitrates."),
25758
- includeTranscript: import_zod30.z.boolean().default(false).describe("Transcribe the selected audio track when available. This adds transcription cost and may take longer."),
25759
- mux: import_zod30.z.boolean().default(true).describe("When video and audio tracks are downloaded separately, try to mux them into a single MP4 if ffmpeg is available. Returns separate tracks when muxing is unavailable.")
26048
+ url: import_zod31.z.string().url().describe("Instagram post, reel, or tv URL, e.g. https://www.instagram.com/reel/SHORTCODE/. The tool renders the page, extracts text, image metadata, and Instagram CDN media tracks."),
26049
+ profile: import_zod31.z.string().min(1).optional().describe("Optional saved hosted browser profile name to load authenticated Instagram access. If omitted, the server uses its configured default profile when present."),
26050
+ saveProfileChanges: import_zod31.z.boolean().optional().describe("Whether to save browser changes back to the hosted profile. Leave unset unless intentionally updating the saved login session."),
26051
+ mediaTypes: import_zod31.z.array(import_zod31.z.enum(["image", "video", "audio"])).default(["image", "video", "audio"]).describe("Which media types to download when downloadMedia is true. Reels commonly expose separate video-only and audio-only MP4 tracks."),
26052
+ downloadMedia: import_zod31.z.boolean().default(true).describe("Download extracted text/media files to the MCP Scraper output directory when the API server can write files. Always returns extracted media URLs even when false."),
26053
+ downloadAllTracks: import_zod31.z.boolean().default(false).describe("Download every captured Instagram MP4 track instead of only the selected best video and audio tracks. Use false by default to avoid duplicate bitrates."),
26054
+ includeTranscript: import_zod31.z.boolean().default(false).describe("Transcribe the selected audio track when available. This adds transcription cost and may take longer."),
26055
+ mux: import_zod31.z.boolean().default(true).describe("When video and audio tracks are downloaded separately, try to mux them into a single MP4 if ffmpeg is available. Returns separate tracks when muxing is unavailable.")
25760
26056
  };
25761
26057
  MapsPlaceIntelInputSchema = {
25762
- businessName: import_zod30.z.string().min(1).describe('Business name only. If user says "Elite Roofing Denver CO", use businessName="Elite Roofing" and location="Denver, CO".'),
25763
- location: import_zod30.z.string().min(1).describe('City/region/country where the business should be searched, e.g. "Denver, CO". Infer from the user request when possible.'),
25764
- gl: import_zod30.z.string().length(2).default("us").describe("Google country code inferred from location."),
25765
- hl: import_zod30.z.string().length(2).default("en").describe("Language inferred from user request."),
25766
- includeReviews: import_zod30.z.boolean().default(false).describe("Whether to fetch individual review cards. Use true when the user asks for reviews, customer pain, complaints, praise, themes, or review evidence."),
25767
- maxReviews: import_zod30.z.number().int().min(1).max(500).default(50).describe("Max review cards to return when includeReviews is true. Default 50, maximum 500. Use 50 for normal review analysis and larger values only for deep review mining.")
26058
+ businessName: import_zod31.z.string().min(1).describe('Business name only. If user says "Elite Roofing Denver CO", use businessName="Elite Roofing" and location="Denver, CO".'),
26059
+ location: import_zod31.z.string().min(1).describe('City/region/country where the business should be searched, e.g. "Denver, CO". Infer from the user request when possible.'),
26060
+ gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from location."),
26061
+ hl: import_zod31.z.string().length(2).default("en").describe("Language inferred from user request."),
26062
+ includeReviews: import_zod31.z.boolean().default(false).describe("Whether to fetch individual review cards. Use true when the user asks for reviews, customer pain, complaints, praise, themes, or review evidence."),
26063
+ maxReviews: import_zod31.z.number().int().min(1).max(500).default(50).describe("Max review cards to return when includeReviews is true. Default 50, maximum 500. Use 50 for normal review analysis and larger values only for deep review mining.")
25768
26064
  };
25769
26065
  MapsSearchInputSchema = {
25770
- query: import_zod30.z.string().min(1).describe('Business category, niche, keyword, or search term. If the user says "roofers in Denver CO", use query="roofers" and location="Denver, CO". Do not put the location here when it can be separated.'),
25771
- location: import_zod30.z.string().optional().describe('City, region, country, or service area for the Maps search, e.g. "Denver, CO". Infer from the user request when present.'),
25772
- gl: import_zod30.z.string().length(2).default("us").describe("Google country code inferred from location."),
25773
- hl: import_zod30.z.string().length(2).default("en").describe("Language inferred from user request."),
25774
- maxResults: import_zod30.z.number().int().min(1).max(50).default(10).describe("Number of Google Maps business/profile candidates to return. Default 10. Maximum 50. Use 10 unless the user asks for more."),
25775
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting mode. Maps defaults to location so local market searches get city/state residential proxy targeting and rotation. Use configured to force the service proxy without city/ZIP targeting, and none only for local direct-network debugging."),
25776
- proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override for residential location proxy targeting. Use when the user gives a specific ZIP or city-center ZIP."),
25777
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics when debugging Maps localization, CAPTCHA, or proxy behavior.")
26066
+ query: import_zod31.z.string().min(1).describe('Business category, niche, keyword, or search term. If the user says "roofers in Denver CO", use query="roofers" and location="Denver, CO". Do not put the location here when it can be separated.'),
26067
+ location: import_zod31.z.string().optional().describe('City, region, country, or service area for the Maps search, e.g. "Denver, CO". Infer from the user request when present.'),
26068
+ gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from location."),
26069
+ hl: import_zod31.z.string().length(2).default("en").describe("Language inferred from user request."),
26070
+ maxResults: import_zod31.z.number().int().min(1).max(50).default(10).describe("Number of Google Maps business/profile candidates to return. Default 10. Maximum 50. Use 10 unless the user asks for more."),
26071
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting mode. Maps defaults to location so local market searches get city/state residential proxy targeting and rotation. Use configured to force the service proxy without city/ZIP targeting, and none only for local direct-network debugging."),
26072
+ proxyZip: import_zod31.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override for residential location proxy targeting. Use when the user gives a specific ZIP or city-center ZIP."),
26073
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics when debugging Maps localization, CAPTCHA, or proxy behavior.")
25778
26074
  };
25779
26075
  DirectoryWorkflowInputSchema = {
25780
- query: import_zod30.z.string().min(1).describe("Business category, niche, or keyword to search on Google Maps for every selected market, e.g. roofers, dentists, med spas. Do not include the city here."),
25781
- state: import_zod30.z.string().min(2).default("TN").describe("US state abbreviation or state name used to select Census places, e.g. TN or Tennessee."),
25782
- minPopulation: import_zod30.z.number().int().min(0).default(1e5).describe('Minimum Census place population for market selection. Use 100000 for "cities above 100k population".'),
25783
- populationYear: import_zod30.z.number().int().min(2020).max(2025).default(2025).describe("Census population estimate year from the 2020-2025 Population Estimates Program city/place dataset."),
25784
- maxCities: import_zod30.z.number().int().min(1).max(100).default(25).describe("Maximum number of markets to process after sorting by population descending."),
25785
- maxResultsPerCity: import_zod30.z.number().int().min(1).max(50).default(50).describe("Google Maps business/profile candidates to collect for each city. Maximum 50."),
25786
- concurrency: import_zod30.z.number().int().min(1).max(5).default(5).describe("How many city Maps searches to run in parallel. Use 5 for broad directory batches unless debugging."),
25787
- includeZipGroups: import_zod30.z.boolean().default(true).describe("Attach ZIP groups from a configured US ZIPS CSV when available. Set MCP_SCRAPER_USZIPS_CSV_PATH on the API server or pass usZipsCsvPath in local/test mode."),
25788
- usZipsCsvPath: import_zod30.z.string().optional().describe("Local/test-only path to a US ZIPS CSV with state_abbr, zipcode, county, city columns, such as Lead Magician tools/analytics/data/uszips.csv. Deployed APIs should use MCP_SCRAPER_USZIPS_CSV_PATH instead."),
25789
- saveCsv: import_zod30.z.boolean().default(true).describe("Save a directory-ready CSV to the MCP Scraper output directory and return its path. CSV rows include source_location, result_position, business_name, review_stars, review_count, category, address, phone, hours_status, website_url, directions_url, place_url, CID fields, population, and ZIP groups."),
25790
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting mode for every city Maps search. Maps workflows default to location so each city can use city/state or ZIP-group residential proxy targeting. Use configured to force the service proxy without city/ZIP targeting, and none only for local direct-network debugging."),
25791
- proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional().describe("Optional ZIP override for proxy targeting. Normally omit it so each city can use its ZIP group or city/state location."),
25792
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics in each Maps browser session when supported.")
26076
+ query: import_zod31.z.string().min(1).describe("Business category, niche, or keyword to search on Google Maps for every selected market, e.g. roofers, dentists, med spas. Do not include the city here."),
26077
+ state: import_zod31.z.string().min(2).default("TN").describe("US state abbreviation or state name used to select Census places, e.g. TN or Tennessee."),
26078
+ minPopulation: import_zod31.z.number().int().min(0).default(1e5).describe('Minimum Census place population for market selection. Use 100000 for "cities above 100k population".'),
26079
+ populationYear: import_zod31.z.number().int().min(2020).max(2025).default(2025).describe("Census population estimate year from the 2020-2025 Population Estimates Program city/place dataset."),
26080
+ maxCities: import_zod31.z.number().int().min(1).max(100).default(25).describe("Maximum number of markets to process after sorting by population descending."),
26081
+ maxResultsPerCity: import_zod31.z.number().int().min(1).max(50).default(50).describe("Google Maps business/profile candidates to collect for each city. Maximum 50."),
26082
+ concurrency: import_zod31.z.number().int().min(1).max(5).default(5).describe("How many city Maps searches to run in parallel. Use 5 for broad directory batches unless debugging."),
26083
+ includeZipGroups: import_zod31.z.boolean().default(true).describe("Attach ZIP groups from a configured US ZIPS CSV when available. Set MCP_SCRAPER_USZIPS_CSV_PATH on the API server or pass usZipsCsvPath in local/test mode."),
26084
+ usZipsCsvPath: import_zod31.z.string().optional().describe("Local/test-only path to a US ZIPS CSV with state_abbr, zipcode, county, city columns, such as Lead Magician tools/analytics/data/uszips.csv. Deployed APIs should use MCP_SCRAPER_USZIPS_CSV_PATH instead."),
26085
+ saveCsv: import_zod31.z.boolean().default(true).describe("Save a directory-ready CSV to the MCP Scraper output directory and return its path. CSV rows include source_location, result_position, business_name, review_stars, review_count, category, address, phone, hours_status, website_url, directions_url, place_url, CID fields, population, and ZIP groups."),
26086
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting mode for every city Maps search. Maps workflows default to location so each city can use city/state or ZIP-group residential proxy targeting. Use configured to force the service proxy without city/ZIP targeting, and none only for local direct-network debugging."),
26087
+ proxyZip: import_zod31.z.string().regex(/^\d{5}$/).optional().describe("Optional ZIP override for proxy targeting. Normally omit it so each city can use its ZIP group or city/state location."),
26088
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics in each Maps browser session when supported.")
25793
26089
  };
25794
- RankTrackerModeSchema = import_zod30.z.enum(["maps", "organic", "ai_overview", "paa"]);
26090
+ RankTrackerModeSchema = import_zod31.z.enum(["maps", "organic", "ai_overview", "paa"]);
25795
26091
  RankTrackerBlueprintInputSchema = {
25796
- projectName: import_zod30.z.string().min(1).optional().describe("Optional name for the rank tracker project, client, or campaign."),
25797
- targetDomain: import_zod30.z.string().min(1).optional().describe("Primary domain to track in organic results, AI Overview citations, and PAA sources, e.g. example.com."),
25798
- targetBusinessName: import_zod30.z.string().min(1).optional().describe("Primary Google Business Profile or brand/business name to match in Maps results. Required for reliable Maps rank tracking."),
25799
- trackingModes: import_zod30.z.array(RankTrackerModeSchema).min(1).max(4).default(["maps", "organic", "ai_overview", "paa"]).describe("Rank tracker surfaces to build. maps uses directory_workflow/maps_search. organic uses search_serp. ai_overview uses search_serp/harvest_paa. paa uses harvest_paa source presence."),
25800
- keywords: import_zod30.z.array(import_zod30.z.string().min(1)).max(200).default([]).describe("Seed keywords or service queries to track. Leave empty when the downstream AI should create the keyword table from user input."),
25801
- locations: import_zod30.z.array(import_zod30.z.string().min(1)).max(100).default([]).describe("Markets, cities, ZIPs, or service areas to track. Use city/state strings like Denver, CO for localized SERP and Maps checks."),
25802
- competitors: import_zod30.z.array(import_zod30.z.string().min(1)).max(100).default([]).describe("Optional competitor domains or business names to persist as comparison targets."),
25803
- database: import_zod30.z.enum(["postgres", "neon", "supabase", "sqlite", "mysql"]).default("postgres").describe("Database family the downstream AI should target when generating migrations."),
25804
- scheduleCadence: import_zod30.z.enum(["daily", "weekly", "monthly", "custom"]).default("weekly").describe("Default recurring rank check cadence for the generated cron/heartbeat plan."),
25805
- customCron: import_zod30.z.string().min(1).optional().describe("Cron expression to use when scheduleCadence is custom."),
25806
- timezone: import_zod30.z.string().min(1).default("UTC").describe("IANA timezone for scheduled rank checks, e.g. America/Denver."),
25807
- includeCron: import_zod30.z.boolean().default(true).describe("Include a cron or heartbeat worker plan. Keep true for production rank trackers."),
25808
- includeDashboard: import_zod30.z.boolean().default(true).describe("Include dashboard/reporting requirements in the generated prompt."),
25809
- includeAlerts: import_zod30.z.boolean().default(true).describe("Include alert rules for rank movement and SERP feature gains/losses."),
25810
- notes: import_zod30.z.string().max(4e3).optional().describe("Extra product, client, stack, or hosting requirements to include in the implementation prompt.")
26092
+ projectName: import_zod31.z.string().min(1).optional().describe("Optional name for the rank tracker project, client, or campaign."),
26093
+ targetDomain: import_zod31.z.string().min(1).optional().describe("Primary domain to track in organic results, AI Overview citations, and PAA sources, e.g. example.com."),
26094
+ targetBusinessName: import_zod31.z.string().min(1).optional().describe("Primary Google Business Profile or brand/business name to match in Maps results. Required for reliable Maps rank tracking."),
26095
+ trackingModes: import_zod31.z.array(RankTrackerModeSchema).min(1).max(4).default(["maps", "organic", "ai_overview", "paa"]).describe("Rank tracker surfaces to build. maps uses directory_workflow/maps_search. organic uses search_serp. ai_overview uses search_serp/harvest_paa. paa uses harvest_paa source presence."),
26096
+ keywords: import_zod31.z.array(import_zod31.z.string().min(1)).max(200).default([]).describe("Seed keywords or service queries to track. Leave empty when the downstream AI should create the keyword table from user input."),
26097
+ locations: import_zod31.z.array(import_zod31.z.string().min(1)).max(100).default([]).describe("Markets, cities, ZIPs, or service areas to track. Use city/state strings like Denver, CO for localized SERP and Maps checks."),
26098
+ competitors: import_zod31.z.array(import_zod31.z.string().min(1)).max(100).default([]).describe("Optional competitor domains or business names to persist as comparison targets."),
26099
+ database: import_zod31.z.enum(["postgres", "neon", "supabase", "sqlite", "mysql"]).default("postgres").describe("Database family the downstream AI should target when generating migrations."),
26100
+ scheduleCadence: import_zod31.z.enum(["daily", "weekly", "monthly", "custom"]).default("weekly").describe("Default recurring rank check cadence for the generated cron/heartbeat plan."),
26101
+ customCron: import_zod31.z.string().min(1).optional().describe("Cron expression to use when scheduleCadence is custom."),
26102
+ timezone: import_zod31.z.string().min(1).default("UTC").describe("IANA timezone for scheduled rank checks, e.g. America/Denver."),
26103
+ includeCron: import_zod31.z.boolean().default(true).describe("Include a cron or heartbeat worker plan. Keep true for production rank trackers."),
26104
+ includeDashboard: import_zod31.z.boolean().default(true).describe("Include dashboard/reporting requirements in the generated prompt."),
26105
+ includeAlerts: import_zod31.z.boolean().default(true).describe("Include alert rules for rank movement and SERP feature gains/losses."),
26106
+ notes: import_zod31.z.string().max(4e3).optional().describe("Extra product, client, stack, or hosting requirements to include in the implementation prompt.")
25811
26107
  };
25812
- NullableString = import_zod30.z.string().nullable();
25813
- MapsSearchAttemptOutput = import_zod30.z.object({
25814
- attemptNumber: import_zod30.z.number().int().min(1),
25815
- maxAttempts: import_zod30.z.number().int().min(1),
25816
- status: import_zod30.z.enum(["ok", "failed"]),
25817
- outcome: import_zod30.z.string(),
25818
- willRetry: import_zod30.z.boolean(),
25819
- durationMs: import_zod30.z.number().int().min(0),
25820
- resultCount: import_zod30.z.number().int().min(0),
26108
+ NullableString = import_zod31.z.string().nullable();
26109
+ MapsSearchAttemptOutput = import_zod31.z.object({
26110
+ attemptNumber: import_zod31.z.number().int().min(1),
26111
+ maxAttempts: import_zod31.z.number().int().min(1),
26112
+ status: import_zod31.z.enum(["ok", "failed"]),
26113
+ outcome: import_zod31.z.string(),
26114
+ willRetry: import_zod31.z.boolean(),
26115
+ durationMs: import_zod31.z.number().int().min(0),
26116
+ resultCount: import_zod31.z.number().int().min(0),
25821
26117
  error: NullableString,
25822
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]),
25823
- proxyResolutionSource: import_zod30.z.enum(["disabled", "location_reused", "location_created", "configured_fallback", "unavailable"]).nullable(),
26118
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]),
26119
+ proxyResolutionSource: import_zod31.z.enum(["disabled", "location_reused", "location_created", "configured_fallback", "unavailable"]).nullable(),
25824
26120
  proxyIdSuffix: NullableString,
25825
- proxyTargetLevel: import_zod30.z.enum(["zip", "city", "state"]).nullable(),
26121
+ proxyTargetLevel: import_zod31.z.enum(["zip", "city", "state"]).nullable(),
25826
26122
  proxyTargetLocation: NullableString,
25827
26123
  proxyTargetZip: NullableString,
25828
26124
  browserSessionIdSuffix: NullableString,
@@ -25831,17 +26127,17 @@ var init_mcp_tool_schemas = __esm({
25831
26127
  observedRegion: NullableString
25832
26128
  });
25833
26129
  MapsSearchOutputSchema = {
25834
- query: import_zod30.z.string(),
25835
- location: import_zod30.z.string().nullable(),
25836
- searchQuery: import_zod30.z.string(),
25837
- searchUrl: import_zod30.z.string().url(),
25838
- extractedAt: import_zod30.z.string(),
25839
- requestedMaxResults: import_zod30.z.number().int().min(1).max(50),
25840
- resultCount: import_zod30.z.number().int().min(0).max(50),
25841
- results: import_zod30.z.array(import_zod30.z.object({
25842
- position: import_zod30.z.number().int().min(1),
25843
- name: import_zod30.z.string(),
25844
- placeUrl: import_zod30.z.string().url(),
26130
+ query: import_zod31.z.string(),
26131
+ location: import_zod31.z.string().nullable(),
26132
+ searchQuery: import_zod31.z.string(),
26133
+ searchUrl: import_zod31.z.string().url(),
26134
+ extractedAt: import_zod31.z.string(),
26135
+ requestedMaxResults: import_zod31.z.number().int().min(1).max(50),
26136
+ resultCount: import_zod31.z.number().int().min(0).max(50),
26137
+ results: import_zod31.z.array(import_zod31.z.object({
26138
+ position: import_zod31.z.number().int().min(1),
26139
+ name: import_zod31.z.string(),
26140
+ placeUrl: import_zod31.z.string().url(),
25845
26141
  cid: NullableString,
25846
26142
  cidDecimal: NullableString,
25847
26143
  rating: NullableString,
@@ -25852,15 +26148,15 @@ var init_mcp_tool_schemas = __esm({
25852
26148
  hoursStatus: NullableString,
25853
26149
  websiteUrl: NullableString,
25854
26150
  directionsUrl: NullableString,
25855
- metadata: import_zod30.z.array(import_zod30.z.string())
26151
+ metadata: import_zod31.z.array(import_zod31.z.string())
25856
26152
  })),
25857
- attempts: import_zod30.z.array(MapsSearchAttemptOutput),
25858
- durationMs: import_zod30.z.number().int().min(0)
26153
+ attempts: import_zod31.z.array(MapsSearchAttemptOutput),
26154
+ durationMs: import_zod31.z.number().int().min(0)
25859
26155
  };
25860
- DirectoryMapsBusinessOutput = import_zod30.z.object({
25861
- position: import_zod30.z.number().int().min(1),
25862
- name: import_zod30.z.string(),
25863
- placeUrl: import_zod30.z.string().url(),
26156
+ DirectoryMapsBusinessOutput = import_zod31.z.object({
26157
+ position: import_zod31.z.number().int().min(1),
26158
+ name: import_zod31.z.string(),
26159
+ placeUrl: import_zod31.z.string().url(),
25864
26160
  cid: NullableString,
25865
26161
  cidDecimal: NullableString,
25866
26162
  rating: NullableString,
@@ -25871,120 +26167,120 @@ var init_mcp_tool_schemas = __esm({
25871
26167
  hoursStatus: NullableString,
25872
26168
  websiteUrl: NullableString,
25873
26169
  directionsUrl: NullableString,
25874
- metadata: import_zod30.z.array(import_zod30.z.string())
26170
+ metadata: import_zod31.z.array(import_zod31.z.string())
25875
26171
  });
25876
26172
  DirectoryWorkflowOutputSchema = {
25877
- query: import_zod30.z.string(),
25878
- state: import_zod30.z.string(),
25879
- minPopulation: import_zod30.z.number().int().min(0),
25880
- populationYear: import_zod30.z.number().int().min(2020).max(2025),
25881
- maxResultsPerCity: import_zod30.z.number().int().min(1).max(50),
25882
- concurrency: import_zod30.z.number().int().min(1).max(5),
25883
- censusSourceUrl: import_zod30.z.string().url(),
26173
+ query: import_zod31.z.string(),
26174
+ state: import_zod31.z.string(),
26175
+ minPopulation: import_zod31.z.number().int().min(0),
26176
+ populationYear: import_zod31.z.number().int().min(2020).max(2025),
26177
+ maxResultsPerCity: import_zod31.z.number().int().min(1).max(50),
26178
+ concurrency: import_zod31.z.number().int().min(1).max(5),
26179
+ censusSourceUrl: import_zod31.z.string().url(),
25884
26180
  usZipsSourcePath: NullableString,
25885
- warnings: import_zod30.z.array(import_zod30.z.string()),
25886
- extractedAt: import_zod30.z.string(),
25887
- selectedCityCount: import_zod30.z.number().int().min(0),
25888
- totalResultCount: import_zod30.z.number().int().min(0),
26181
+ warnings: import_zod31.z.array(import_zod31.z.string()),
26182
+ extractedAt: import_zod31.z.string(),
26183
+ selectedCityCount: import_zod31.z.number().int().min(0),
26184
+ totalResultCount: import_zod31.z.number().int().min(0),
25889
26185
  csvPath: NullableString,
25890
- cities: import_zod30.z.array(import_zod30.z.object({
25891
- city: import_zod30.z.string(),
25892
- state: import_zod30.z.string(),
25893
- location: import_zod30.z.string(),
25894
- cityKey: import_zod30.z.string(),
25895
- censusName: import_zod30.z.string(),
25896
- population: import_zod30.z.number().int().min(0),
25897
- populationYear: import_zod30.z.number().int().min(2020).max(2025),
25898
- zips: import_zod30.z.array(import_zod30.z.string()),
25899
- counties: import_zod30.z.array(import_zod30.z.string()),
25900
- status: import_zod30.z.enum(["ok", "empty", "failed"]),
26186
+ cities: import_zod31.z.array(import_zod31.z.object({
26187
+ city: import_zod31.z.string(),
26188
+ state: import_zod31.z.string(),
26189
+ location: import_zod31.z.string(),
26190
+ cityKey: import_zod31.z.string(),
26191
+ censusName: import_zod31.z.string(),
26192
+ population: import_zod31.z.number().int().min(0),
26193
+ populationYear: import_zod31.z.number().int().min(2020).max(2025),
26194
+ zips: import_zod31.z.array(import_zod31.z.string()),
26195
+ counties: import_zod31.z.array(import_zod31.z.string()),
26196
+ status: import_zod31.z.enum(["ok", "empty", "failed"]),
25901
26197
  error: NullableString,
25902
- resultCount: import_zod30.z.number().int().min(0),
25903
- durationMs: import_zod30.z.number().int().min(0),
25904
- attempts: import_zod30.z.array(MapsSearchAttemptOutput),
25905
- results: import_zod30.z.array(DirectoryMapsBusinessOutput)
26198
+ resultCount: import_zod31.z.number().int().min(0),
26199
+ durationMs: import_zod31.z.number().int().min(0),
26200
+ attempts: import_zod31.z.array(MapsSearchAttemptOutput),
26201
+ results: import_zod31.z.array(DirectoryMapsBusinessOutput)
25906
26202
  })),
25907
- durationMs: import_zod30.z.number().int().min(0)
26203
+ durationMs: import_zod31.z.number().int().min(0)
25908
26204
  };
25909
- RankTrackerToolPlanOutput = import_zod30.z.object({
25910
- tool: import_zod30.z.string(),
25911
- purpose: import_zod30.z.string()
26205
+ RankTrackerToolPlanOutput = import_zod31.z.object({
26206
+ tool: import_zod31.z.string(),
26207
+ purpose: import_zod31.z.string()
25912
26208
  });
25913
- RankTrackerTableOutput = import_zod30.z.object({
25914
- name: import_zod30.z.string(),
25915
- purpose: import_zod30.z.string(),
25916
- keyColumns: import_zod30.z.array(import_zod30.z.string())
26209
+ RankTrackerTableOutput = import_zod31.z.object({
26210
+ name: import_zod31.z.string(),
26211
+ purpose: import_zod31.z.string(),
26212
+ keyColumns: import_zod31.z.array(import_zod31.z.string())
25917
26213
  });
25918
- RankTrackerCronJobOutput = import_zod30.z.object({
25919
- name: import_zod30.z.string(),
25920
- purpose: import_zod30.z.string(),
25921
- modes: import_zod30.z.array(RankTrackerModeSchema),
25922
- recommendedTools: import_zod30.z.array(import_zod30.z.string())
26214
+ RankTrackerCronJobOutput = import_zod31.z.object({
26215
+ name: import_zod31.z.string(),
26216
+ purpose: import_zod31.z.string(),
26217
+ modes: import_zod31.z.array(RankTrackerModeSchema),
26218
+ recommendedTools: import_zod31.z.array(import_zod31.z.string())
25923
26219
  });
25924
26220
  RankTrackerBlueprintOutputSchema = {
25925
- projectName: import_zod30.z.string(),
26221
+ projectName: import_zod31.z.string(),
25926
26222
  targetDomain: NullableString,
25927
26223
  targetBusinessName: NullableString,
25928
- trackingModes: import_zod30.z.array(RankTrackerModeSchema),
25929
- database: import_zod30.z.string(),
25930
- recommendedTools: import_zod30.z.array(RankTrackerToolPlanOutput),
25931
- tables: import_zod30.z.array(RankTrackerTableOutput),
25932
- cron: import_zod30.z.object({
25933
- enabled: import_zod30.z.boolean(),
25934
- cadence: import_zod30.z.string(),
25935
- expression: import_zod30.z.string(),
25936
- timezone: import_zod30.z.string(),
25937
- jobs: import_zod30.z.array(RankTrackerCronJobOutput)
26224
+ trackingModes: import_zod31.z.array(RankTrackerModeSchema),
26225
+ database: import_zod31.z.string(),
26226
+ recommendedTools: import_zod31.z.array(RankTrackerToolPlanOutput),
26227
+ tables: import_zod31.z.array(RankTrackerTableOutput),
26228
+ cron: import_zod31.z.object({
26229
+ enabled: import_zod31.z.boolean(),
26230
+ cadence: import_zod31.z.string(),
26231
+ expression: import_zod31.z.string(),
26232
+ timezone: import_zod31.z.string(),
26233
+ jobs: import_zod31.z.array(RankTrackerCronJobOutput)
25938
26234
  }),
25939
- metrics: import_zod30.z.array(import_zod30.z.string()),
25940
- implementationPrompt: import_zod30.z.string()
26235
+ metrics: import_zod31.z.array(import_zod31.z.string()),
26236
+ implementationPrompt: import_zod31.z.string()
25941
26237
  };
25942
- OrganicResultOutput = import_zod30.z.object({
25943
- position: import_zod30.z.number().int(),
25944
- title: import_zod30.z.string(),
25945
- url: import_zod30.z.string(),
25946
- domain: import_zod30.z.string(),
26238
+ OrganicResultOutput = import_zod31.z.object({
26239
+ position: import_zod31.z.number().int(),
26240
+ title: import_zod31.z.string(),
26241
+ url: import_zod31.z.string(),
26242
+ domain: import_zod31.z.string(),
25947
26243
  snippet: NullableString
25948
26244
  });
25949
- AiOverviewOutput = import_zod30.z.object({
25950
- detected: import_zod30.z.boolean(),
26245
+ AiOverviewOutput = import_zod31.z.object({
26246
+ detected: import_zod31.z.boolean(),
25951
26247
  text: NullableString,
25952
26248
  shareUrl: NullableString.optional()
25953
26249
  }).nullable();
25954
- EntityIdsOutput = import_zod30.z.object({
25955
- entities: import_zod30.z.array(import_zod30.z.object({
25956
- name: import_zod30.z.string(),
25957
- kgId: import_zod30.z.string().nullable(),
25958
- cid: import_zod30.z.string().nullable(),
25959
- gcid: import_zod30.z.string().nullable()
26250
+ EntityIdsOutput = import_zod31.z.object({
26251
+ entities: import_zod31.z.array(import_zod31.z.object({
26252
+ name: import_zod31.z.string(),
26253
+ kgId: import_zod31.z.string().nullable(),
26254
+ cid: import_zod31.z.string().nullable(),
26255
+ gcid: import_zod31.z.string().nullable()
25960
26256
  })).describe("Each entity actually named on the page, with whichever of its kgId/cid/gcid were found \u2014 the linked view. kgIds/cids/gcids below are the same IDs as flat deduplicated lists, without the name link, kept for backward compatibility."),
25961
- kgIds: import_zod30.z.array(import_zod30.z.string()),
25962
- cids: import_zod30.z.array(import_zod30.z.string()),
25963
- gcids: import_zod30.z.array(import_zod30.z.string())
26257
+ kgIds: import_zod31.z.array(import_zod31.z.string()),
26258
+ cids: import_zod31.z.array(import_zod31.z.string()),
26259
+ gcids: import_zod31.z.array(import_zod31.z.string())
25964
26260
  }).nullable();
25965
26261
  HarvestPaaOutputSchema = {
25966
- query: import_zod30.z.string(),
26262
+ query: import_zod31.z.string(),
25967
26263
  location: NullableString,
25968
- questionCount: import_zod30.z.number().int().min(0),
26264
+ questionCount: import_zod31.z.number().int().min(0),
25969
26265
  completionStatus: NullableString,
25970
- questions: import_zod30.z.array(import_zod30.z.object({
25971
- question: import_zod30.z.string(),
26266
+ questions: import_zod31.z.array(import_zod31.z.object({
26267
+ question: import_zod31.z.string(),
25972
26268
  answer: NullableString,
25973
26269
  sourceTitle: NullableString,
25974
26270
  sourceSite: NullableString
25975
26271
  })),
25976
- organicResults: import_zod30.z.array(OrganicResultOutput),
26272
+ organicResults: import_zod31.z.array(OrganicResultOutput),
25977
26273
  aiOverview: AiOverviewOutput,
25978
26274
  entityIds: EntityIdsOutput,
25979
- durationMs: import_zod30.z.number().min(0).nullable()
26275
+ durationMs: import_zod31.z.number().min(0).nullable()
25980
26276
  };
25981
26277
  SearchSerpOutputSchema = {
25982
- query: import_zod30.z.string(),
26278
+ query: import_zod31.z.string(),
25983
26279
  location: NullableString,
25984
- organicResults: import_zod30.z.array(OrganicResultOutput),
25985
- localPack: import_zod30.z.array(import_zod30.z.object({
25986
- position: import_zod30.z.number().int(),
25987
- name: import_zod30.z.string(),
26280
+ organicResults: import_zod31.z.array(OrganicResultOutput),
26281
+ localPack: import_zod31.z.array(import_zod31.z.object({
26282
+ position: import_zod31.z.number().int(),
26283
+ name: import_zod31.z.string(),
25988
26284
  rating: NullableString,
25989
26285
  reviewCount: NullableString,
25990
26286
  websiteUrl: NullableString
@@ -25993,61 +26289,61 @@ var init_mcp_tool_schemas = __esm({
25993
26289
  entityIds: EntityIdsOutput
25994
26290
  };
25995
26291
  ExtractUrlOutputSchema = {
25996
- url: import_zod30.z.string(),
26292
+ url: import_zod31.z.string(),
25997
26293
  title: NullableString,
25998
- headings: import_zod30.z.array(import_zod30.z.object({
25999
- level: import_zod30.z.number().int(),
26000
- text: import_zod30.z.string()
26294
+ headings: import_zod31.z.array(import_zod31.z.object({
26295
+ level: import_zod31.z.number().int(),
26296
+ text: import_zod31.z.string()
26001
26297
  })),
26002
- schemaBlockCount: import_zod30.z.number().int().min(0),
26298
+ schemaBlockCount: import_zod31.z.number().int().min(0),
26003
26299
  entityName: NullableString,
26004
- entityTypes: import_zod30.z.array(import_zod30.z.string()),
26005
- napScore: import_zod30.z.number().nullable(),
26006
- missingSchemaFields: import_zod30.z.array(import_zod30.z.string()),
26300
+ entityTypes: import_zod31.z.array(import_zod31.z.string()),
26301
+ napScore: import_zod31.z.number().nullable(),
26302
+ missingSchemaFields: import_zod31.z.array(import_zod31.z.string()),
26007
26303
  screenshotSaved: NullableString,
26008
- memory: import_zod30.z.object({
26009
- deposited: import_zod30.z.boolean(),
26010
- vault: import_zod30.z.string().optional(),
26011
- noteId: import_zod30.z.string().optional(),
26012
- path: import_zod30.z.string().optional(),
26013
- chunks: import_zod30.z.number().int().optional(),
26014
- fileUrl: import_zod30.z.string().optional(),
26015
- fileExpiresAt: import_zod30.z.string().optional(),
26016
- error: import_zod30.z.string().optional()
26304
+ memory: import_zod31.z.object({
26305
+ deposited: import_zod31.z.boolean(),
26306
+ vault: import_zod31.z.string().optional(),
26307
+ noteId: import_zod31.z.string().optional(),
26308
+ path: import_zod31.z.string().optional(),
26309
+ chunks: import_zod31.z.number().int().optional(),
26310
+ fileUrl: import_zod31.z.string().optional(),
26311
+ fileExpiresAt: import_zod31.z.string().optional(),
26312
+ error: import_zod31.z.string().optional()
26017
26313
  }).optional()
26018
26314
  };
26019
26315
  ExtractSiteOutputSchema = {
26020
- url: import_zod30.z.string(),
26021
- pageCount: import_zod30.z.number().int().min(0),
26022
- pages: import_zod30.z.array(import_zod30.z.object({
26023
- url: import_zod30.z.string(),
26316
+ url: import_zod31.z.string(),
26317
+ pageCount: import_zod31.z.number().int().min(0),
26318
+ pages: import_zod31.z.array(import_zod31.z.object({
26319
+ url: import_zod31.z.string(),
26024
26320
  title: NullableString,
26025
- schemaTypes: import_zod30.z.array(import_zod30.z.string())
26321
+ schemaTypes: import_zod31.z.array(import_zod31.z.string())
26026
26322
  })),
26027
- durationMs: import_zod30.z.number().min(0)
26323
+ durationMs: import_zod31.z.number().min(0)
26028
26324
  };
26029
26325
  AuditSiteOutputSchema = {
26030
- url: import_zod30.z.string(),
26031
- pageCount: import_zod30.z.number().int().min(0),
26032
- durationMs: import_zod30.z.number().min(0),
26033
- bulkFolder: import_zod30.z.string().nullable(),
26034
- issues: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.number()),
26035
- images: import_zod30.z.object({
26036
- unique: import_zod30.z.number().int().min(0),
26037
- totalBytes: import_zod30.z.number().min(0),
26038
- over100kb: import_zod30.z.number().int().min(0),
26039
- legacyFormat: import_zod30.z.number().int().min(0)
26326
+ url: import_zod31.z.string(),
26327
+ pageCount: import_zod31.z.number().int().min(0),
26328
+ durationMs: import_zod31.z.number().min(0),
26329
+ bulkFolder: import_zod31.z.string().nullable(),
26330
+ issues: import_zod31.z.record(import_zod31.z.string(), import_zod31.z.number()),
26331
+ images: import_zod31.z.object({
26332
+ unique: import_zod31.z.number().int().min(0),
26333
+ totalBytes: import_zod31.z.number().min(0),
26334
+ over100kb: import_zod31.z.number().int().min(0),
26335
+ legacyFormat: import_zod31.z.number().int().min(0)
26040
26336
  }),
26041
- links: import_zod30.z.object({
26042
- internal: import_zod30.z.number().int().min(0),
26043
- external: import_zod30.z.number().int().min(0),
26044
- orphans: import_zod30.z.number().int().min(0),
26045
- brokenInternal: import_zod30.z.number().int().min(0),
26046
- externalDomains: import_zod30.z.number().int().min(0)
26337
+ links: import_zod31.z.object({
26338
+ internal: import_zod31.z.number().int().min(0),
26339
+ external: import_zod31.z.number().int().min(0),
26340
+ orphans: import_zod31.z.number().int().min(0),
26341
+ brokenInternal: import_zod31.z.number().int().min(0),
26342
+ externalDomains: import_zod31.z.number().int().min(0)
26047
26343
  })
26048
26344
  };
26049
26345
  MapsPlaceIntelOutputSchema = {
26050
- name: import_zod30.z.string(),
26346
+ name: import_zod31.z.string(),
26051
26347
  rating: NullableString,
26052
26348
  reviewCount: NullableString,
26053
26349
  category: NullableString,
@@ -26059,75 +26355,75 @@ var init_mcp_tool_schemas = __esm({
26059
26355
  kgmid: NullableString,
26060
26356
  cidDecimal: NullableString,
26061
26357
  cidUrl: NullableString,
26062
- lat: import_zod30.z.number().nullable(),
26063
- lng: import_zod30.z.number().nullable(),
26064
- reviewsStatus: import_zod30.z.string(),
26065
- reviewsCollected: import_zod30.z.number().int().min(0),
26066
- reviewTopics: import_zod30.z.array(import_zod30.z.object({
26067
- label: import_zod30.z.string(),
26068
- count: import_zod30.z.string()
26358
+ lat: import_zod31.z.number().nullable(),
26359
+ lng: import_zod31.z.number().nullable(),
26360
+ reviewsStatus: import_zod31.z.string(),
26361
+ reviewsCollected: import_zod31.z.number().int().min(0),
26362
+ reviewTopics: import_zod31.z.array(import_zod31.z.object({
26363
+ label: import_zod31.z.string(),
26364
+ count: import_zod31.z.string()
26069
26365
  }))
26070
26366
  };
26071
26367
  CreditsInfoOutputSchema = {
26072
- balanceCredits: import_zod30.z.number().nullable(),
26073
- matchedCost: import_zod30.z.object({
26074
- label: import_zod30.z.string(),
26075
- credits: import_zod30.z.number(),
26076
- unit: import_zod30.z.string(),
26368
+ balanceCredits: import_zod31.z.number().nullable(),
26369
+ matchedCost: import_zod31.z.object({
26370
+ label: import_zod31.z.string(),
26371
+ credits: import_zod31.z.number(),
26372
+ unit: import_zod31.z.string(),
26077
26373
  notes: NullableString
26078
26374
  }).nullable(),
26079
- costs: import_zod30.z.array(import_zod30.z.object({
26080
- key: import_zod30.z.string(),
26081
- label: import_zod30.z.string(),
26082
- credits: import_zod30.z.number(),
26083
- unit: import_zod30.z.string(),
26375
+ costs: import_zod31.z.array(import_zod31.z.object({
26376
+ key: import_zod31.z.string(),
26377
+ label: import_zod31.z.string(),
26378
+ credits: import_zod31.z.number(),
26379
+ unit: import_zod31.z.string(),
26084
26380
  notes: NullableString
26085
26381
  })),
26086
- ledger: import_zod30.z.array(import_zod30.z.object({
26087
- createdAt: import_zod30.z.string(),
26088
- operation: import_zod30.z.string(),
26089
- credits: import_zod30.z.number(),
26382
+ ledger: import_zod31.z.array(import_zod31.z.object({
26383
+ createdAt: import_zod31.z.string(),
26384
+ operation: import_zod31.z.string(),
26385
+ credits: import_zod31.z.number(),
26090
26386
  description: NullableString
26091
26387
  })),
26092
- concurrency: import_zod30.z.object({
26093
- currentExtraSlots: import_zod30.z.number().int().min(0),
26094
- currentLimit: import_zod30.z.number().int().min(1),
26095
- hasSubscription: import_zod30.z.boolean(),
26096
- upgrade: import_zod30.z.object({
26097
- product: import_zod30.z.string(),
26098
- priceLabel: import_zod30.z.string(),
26099
- unitAmountUsd: import_zod30.z.number(),
26100
- currency: import_zod30.z.string(),
26101
- interval: import_zod30.z.string(),
26102
- billingUrl: import_zod30.z.string().url(),
26103
- terminalCommand: import_zod30.z.string(),
26104
- terminalCommandWithApiKeyEnv: import_zod30.z.string()
26388
+ concurrency: import_zod31.z.object({
26389
+ currentExtraSlots: import_zod31.z.number().int().min(0),
26390
+ currentLimit: import_zod31.z.number().int().min(1),
26391
+ hasSubscription: import_zod31.z.boolean(),
26392
+ upgrade: import_zod31.z.object({
26393
+ product: import_zod31.z.string(),
26394
+ priceLabel: import_zod31.z.string(),
26395
+ unitAmountUsd: import_zod31.z.number(),
26396
+ currency: import_zod31.z.string(),
26397
+ interval: import_zod31.z.string(),
26398
+ billingUrl: import_zod31.z.string().url(),
26399
+ terminalCommand: import_zod31.z.string(),
26400
+ terminalCommandWithApiKeyEnv: import_zod31.z.string()
26105
26401
  })
26106
26402
  }).nullable()
26107
26403
  };
26108
26404
  MapSiteUrlsOutputSchema = {
26109
- startUrl: import_zod30.z.string(),
26110
- totalFound: import_zod30.z.number().int().min(0),
26111
- truncated: import_zod30.z.boolean(),
26112
- okCount: import_zod30.z.number().int().min(0),
26113
- redirectCount: import_zod30.z.number().int().min(0),
26114
- brokenCount: import_zod30.z.number().int().min(0),
26115
- urls: import_zod30.z.array(import_zod30.z.object({
26116
- url: import_zod30.z.string(),
26117
- status: import_zod30.z.number().int().nullable()
26405
+ startUrl: import_zod31.z.string(),
26406
+ totalFound: import_zod31.z.number().int().min(0),
26407
+ truncated: import_zod31.z.boolean(),
26408
+ okCount: import_zod31.z.number().int().min(0),
26409
+ redirectCount: import_zod31.z.number().int().min(0),
26410
+ brokenCount: import_zod31.z.number().int().min(0),
26411
+ urls: import_zod31.z.array(import_zod31.z.object({
26412
+ url: import_zod31.z.string(),
26413
+ status: import_zod31.z.number().int().nullable()
26118
26414
  })),
26119
- durationMs: import_zod30.z.number().min(0)
26415
+ durationMs: import_zod31.z.number().min(0)
26120
26416
  };
26121
26417
  YoutubeHarvestOutputSchema = {
26122
- mode: import_zod30.z.string(),
26123
- videoCount: import_zod30.z.number().int().min(0),
26124
- channel: import_zod30.z.object({
26418
+ mode: import_zod31.z.string(),
26419
+ videoCount: import_zod31.z.number().int().min(0),
26420
+ channel: import_zod31.z.object({
26125
26421
  title: NullableString,
26126
26422
  subscriberCount: NullableString
26127
26423
  }).nullable(),
26128
- videos: import_zod30.z.array(import_zod30.z.object({
26129
- videoId: import_zod30.z.string(),
26130
- title: import_zod30.z.string(),
26424
+ videos: import_zod31.z.array(import_zod31.z.object({
26425
+ videoId: import_zod31.z.string(),
26426
+ title: import_zod31.z.string(),
26131
26427
  channelName: NullableString,
26132
26428
  views: NullableString,
26133
26429
  duration: NullableString,
@@ -26135,17 +26431,33 @@ var init_mcp_tool_schemas = __esm({
26135
26431
  }))
26136
26432
  };
26137
26433
  FacebookAdSearchOutputSchema = {
26138
- query: import_zod30.z.string(),
26139
- advertiserCount: import_zod30.z.number().int().min(0),
26140
- advertisers: import_zod30.z.array(import_zod30.z.object({
26434
+ query: import_zod31.z.string(),
26435
+ advertiserCount: import_zod31.z.number().int().min(0),
26436
+ advertisers: import_zod31.z.array(import_zod31.z.object({
26141
26437
  name: NullableString,
26142
26438
  pageId: NullableString,
26143
26439
  pageUrl: NullableString,
26144
- adCount: import_zod30.z.number().int().nullable(),
26440
+ adCount: import_zod31.z.number().int().nullable(),
26145
26441
  libraryId: NullableString,
26146
26442
  sampleLibraryId: NullableString
26147
26443
  }))
26148
26444
  };
26445
+ VideoFrameAnalysisOutputSchema = {
26446
+ ok: import_zod31.z.boolean(),
26447
+ runId: NullableString,
26448
+ status: NullableString,
26449
+ message: NullableString
26450
+ };
26451
+ VideoFrameAnalysisStatusOutputSchema = {
26452
+ ok: import_zod31.z.boolean(),
26453
+ runId: NullableString,
26454
+ status: NullableString,
26455
+ progress: import_zod31.z.object({ analyzed: import_zod31.z.number().int(), total: import_zod31.z.number().int() }).nullable().optional(),
26456
+ frameCount: import_zod31.z.number().int().nullable().optional(),
26457
+ artifactPath: NullableString,
26458
+ report: NullableString,
26459
+ error: NullableString
26460
+ };
26149
26461
  RedditThreadOutputSchema = {
26150
26462
  sourceUrl: NullableString,
26151
26463
  oldRedditUrl: NullableString,
@@ -26153,21 +26465,21 @@ var init_mcp_tool_schemas = __esm({
26153
26465
  author: NullableString,
26154
26466
  score: NullableString,
26155
26467
  postBody: NullableString,
26156
- numComments: import_zod30.z.number().int().min(0),
26157
- comments: import_zod30.z.array(import_zod30.z.object({
26468
+ numComments: import_zod31.z.number().int().min(0),
26469
+ comments: import_zod31.z.array(import_zod31.z.object({
26158
26470
  author: NullableString,
26159
26471
  score: NullableString,
26160
- depth: import_zod30.z.number().int().min(0),
26161
- body: import_zod30.z.string()
26472
+ depth: import_zod31.z.number().int().min(0),
26473
+ body: import_zod31.z.string()
26162
26474
  }))
26163
26475
  };
26164
26476
  FacebookPageIntelOutputSchema = {
26165
26477
  advertiserName: NullableString,
26166
- totalAds: import_zod30.z.number().int().min(0),
26167
- activeCount: import_zod30.z.number().int().min(0),
26168
- videoCount: import_zod30.z.number().int().min(0),
26169
- imageCount: import_zod30.z.number().int().min(0),
26170
- ads: import_zod30.z.array(import_zod30.z.object({
26478
+ totalAds: import_zod31.z.number().int().min(0),
26479
+ activeCount: import_zod31.z.number().int().min(0),
26480
+ videoCount: import_zod31.z.number().int().min(0),
26481
+ imageCount: import_zod31.z.number().int().min(0),
26482
+ ads: import_zod31.z.array(import_zod31.z.object({
26171
26483
  libraryId: NullableString,
26172
26484
  status: NullableString,
26173
26485
  creativeType: NullableString,
@@ -26180,18 +26492,18 @@ var init_mcp_tool_schemas = __esm({
26180
26492
  videoUrl: NullableString,
26181
26493
  imageUrl: NullableString,
26182
26494
  videoPoster: NullableString,
26183
- variations: import_zod30.z.number().int().nullable()
26495
+ variations: import_zod31.z.number().int().nullable()
26184
26496
  }))
26185
26497
  };
26186
26498
  GoogleAdsSearchOutputSchema = {
26187
- query: import_zod30.z.string(),
26188
- region: import_zod30.z.string(),
26189
- advertiserCount: import_zod30.z.number().int().min(0),
26190
- advertisers: import_zod30.z.array(import_zod30.z.object({
26499
+ query: import_zod31.z.string(),
26500
+ region: import_zod31.z.string(),
26501
+ advertiserCount: import_zod31.z.number().int().min(0),
26502
+ advertisers: import_zod31.z.array(import_zod31.z.object({
26191
26503
  advertiserId: NullableString,
26192
26504
  name: NullableString,
26193
26505
  domain: NullableString,
26194
- approxAdCount: import_zod30.z.number().int().nullable(),
26506
+ approxAdCount: import_zod31.z.number().int().nullable(),
26195
26507
  detailUrl: NullableString
26196
26508
  }))
26197
26509
  };
@@ -26199,205 +26511,205 @@ var init_mcp_tool_schemas = __esm({
26199
26511
  advertiserId: NullableString,
26200
26512
  advertiserName: NullableString,
26201
26513
  domain: NullableString,
26202
- region: import_zod30.z.string(),
26203
- totalCreatives: import_zod30.z.number().int().min(0),
26204
- videoCount: import_zod30.z.number().int().min(0),
26205
- imageCount: import_zod30.z.number().int().min(0),
26206
- textCount: import_zod30.z.number().int().min(0),
26207
- ads: import_zod30.z.array(import_zod30.z.object({
26514
+ region: import_zod31.z.string(),
26515
+ totalCreatives: import_zod31.z.number().int().min(0),
26516
+ videoCount: import_zod31.z.number().int().min(0),
26517
+ imageCount: import_zod31.z.number().int().min(0),
26518
+ textCount: import_zod31.z.number().int().min(0),
26519
+ ads: import_zod31.z.array(import_zod31.z.object({
26208
26520
  creativeId: NullableString,
26209
26521
  advertiserId: NullableString,
26210
26522
  format: NullableString,
26211
26523
  lastShown: NullableString,
26212
26524
  detailUrl: NullableString,
26213
26525
  landingDomain: NullableString,
26214
- imageUrls: import_zod30.z.array(import_zod30.z.string()),
26526
+ imageUrls: import_zod31.z.array(import_zod31.z.string()),
26215
26527
  youtubeVideoId: NullableString,
26216
26528
  videoUrl: NullableString,
26217
- variations: import_zod30.z.number().int().nullable()
26529
+ variations: import_zod31.z.number().int().nullable()
26218
26530
  }))
26219
26531
  };
26220
26532
  FacebookVideoTranscribeOutputSchema = {
26221
- sourceUrl: import_zod30.z.string().url(),
26222
- pageUrl: import_zod30.z.string().url(),
26533
+ sourceUrl: import_zod31.z.string().url(),
26534
+ pageUrl: import_zod31.z.string().url(),
26223
26535
  videoId: NullableString,
26224
26536
  ownerName: NullableString,
26225
- selectedQuality: import_zod30.z.string(),
26226
- bitrate: import_zod30.z.number().int().nullable(),
26227
- videoDurationSec: import_zod30.z.number().nullable(),
26228
- videoUrl: import_zod30.z.string().url(),
26229
- wordCount: import_zod30.z.number().int().min(0),
26230
- chunkCount: import_zod30.z.number().int().min(0),
26231
- transcriptText: import_zod30.z.string(),
26232
- chunks: import_zod30.z.array(import_zod30.z.object({
26233
- startSec: import_zod30.z.number(),
26234
- endSec: import_zod30.z.number(),
26235
- text: import_zod30.z.string()
26537
+ selectedQuality: import_zod31.z.string(),
26538
+ bitrate: import_zod31.z.number().int().nullable(),
26539
+ videoDurationSec: import_zod31.z.number().nullable(),
26540
+ videoUrl: import_zod31.z.string().url(),
26541
+ wordCount: import_zod31.z.number().int().min(0),
26542
+ chunkCount: import_zod31.z.number().int().min(0),
26543
+ transcriptText: import_zod31.z.string(),
26544
+ chunks: import_zod31.z.array(import_zod31.z.object({
26545
+ startSec: import_zod31.z.number(),
26546
+ endSec: import_zod31.z.number(),
26547
+ text: import_zod31.z.string()
26236
26548
  }))
26237
26549
  };
26238
- TranscriptChunkOutput = import_zod30.z.object({
26239
- startSec: import_zod30.z.number(),
26240
- endSec: import_zod30.z.number(),
26241
- text: import_zod30.z.string()
26242
- });
26243
- InstagramBrowserOutput = import_zod30.z.object({
26244
- mode: import_zod30.z.literal("hosted"),
26245
- requestedMode: import_zod30.z.literal("hosted"),
26550
+ TranscriptChunkOutput = import_zod31.z.object({
26551
+ startSec: import_zod31.z.number(),
26552
+ endSec: import_zod31.z.number(),
26553
+ text: import_zod31.z.string()
26554
+ });
26555
+ InstagramBrowserOutput = import_zod31.z.object({
26556
+ mode: import_zod31.z.literal("hosted"),
26557
+ requestedMode: import_zod31.z.literal("hosted"),
26246
26558
  profileName: NullableString,
26247
- profileSource: import_zod30.z.literal("hosted"),
26248
- profileDirConfigured: import_zod30.z.boolean(),
26249
- executablePathConfigured: import_zod30.z.boolean()
26250
- });
26251
- InstagramPaginationOutput = import_zod30.z.object({
26252
- maxItems: import_zod30.z.number().int().min(1).max(2e3),
26253
- maxScrolls: import_zod30.z.number().int().min(0).max(250),
26254
- attemptedScrolls: import_zod30.z.number().int().min(0),
26255
- stableScrolls: import_zod30.z.number().int().min(0),
26256
- stableScrollLimit: import_zod30.z.number().int().min(1).max(10),
26257
- scrollDelayMs: import_zod30.z.number().int().min(250).max(5e3),
26258
- reachedMaxItems: import_zod30.z.boolean(),
26259
- reachedReportedPostCount: import_zod30.z.boolean(),
26260
- finalScrollHeight: import_zod30.z.number().int().nullable(),
26261
- stoppedReason: import_zod30.z.enum(["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"]),
26262
- stages: import_zod30.z.array(import_zod30.z.object({
26263
- stage: import_zod30.z.string(),
26264
- itemCount: import_zod30.z.number().int().min(0),
26265
- addedCount: import_zod30.z.number().int().min(0),
26266
- scrollY: import_zod30.z.number().nullable(),
26267
- scrollHeight: import_zod30.z.number().nullable()
26559
+ profileSource: import_zod31.z.literal("hosted"),
26560
+ profileDirConfigured: import_zod31.z.boolean(),
26561
+ executablePathConfigured: import_zod31.z.boolean()
26562
+ });
26563
+ InstagramPaginationOutput = import_zod31.z.object({
26564
+ maxItems: import_zod31.z.number().int().min(1).max(2e3),
26565
+ maxScrolls: import_zod31.z.number().int().min(0).max(250),
26566
+ attemptedScrolls: import_zod31.z.number().int().min(0),
26567
+ stableScrolls: import_zod31.z.number().int().min(0),
26568
+ stableScrollLimit: import_zod31.z.number().int().min(1).max(10),
26569
+ scrollDelayMs: import_zod31.z.number().int().min(250).max(5e3),
26570
+ reachedMaxItems: import_zod31.z.boolean(),
26571
+ reachedReportedPostCount: import_zod31.z.boolean(),
26572
+ finalScrollHeight: import_zod31.z.number().int().nullable(),
26573
+ stoppedReason: import_zod31.z.enum(["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"]),
26574
+ stages: import_zod31.z.array(import_zod31.z.object({
26575
+ stage: import_zod31.z.string(),
26576
+ itemCount: import_zod31.z.number().int().min(0),
26577
+ addedCount: import_zod31.z.number().int().min(0),
26578
+ scrollY: import_zod31.z.number().nullable(),
26579
+ scrollHeight: import_zod31.z.number().nullable()
26268
26580
  }))
26269
26581
  });
26270
26582
  InstagramProfileContentOutputSchema = {
26271
- handle: import_zod30.z.string(),
26272
- profileUrl: import_zod30.z.string().url(),
26273
- pageUrl: import_zod30.z.string().url(),
26583
+ handle: import_zod31.z.string(),
26584
+ profileUrl: import_zod31.z.string().url(),
26585
+ pageUrl: import_zod31.z.string().url(),
26274
26586
  browser: InstagramBrowserOutput,
26275
26587
  profileName: NullableString,
26276
- reportedPostCount: import_zod30.z.number().int().nullable(),
26588
+ reportedPostCount: import_zod31.z.number().int().nullable(),
26277
26589
  reportedPostCountText: NullableString,
26278
26590
  followerCountText: NullableString,
26279
26591
  followingCountText: NullableString,
26280
- collectedContentCount: import_zod30.z.number().int().min(0),
26281
- typeCounts: import_zod30.z.object({
26282
- post: import_zod30.z.number().int().min(0),
26283
- reel: import_zod30.z.number().int().min(0),
26284
- tv: import_zod30.z.number().int().min(0)
26592
+ collectedContentCount: import_zod31.z.number().int().min(0),
26593
+ typeCounts: import_zod31.z.object({
26594
+ post: import_zod31.z.number().int().min(0),
26595
+ reel: import_zod31.z.number().int().min(0),
26596
+ tv: import_zod31.z.number().int().min(0)
26285
26597
  }),
26286
26598
  pagination: InstagramPaginationOutput,
26287
- limited: import_zod30.z.boolean(),
26288
- limitations: import_zod30.z.array(import_zod30.z.string()),
26289
- items: import_zod30.z.array(import_zod30.z.object({
26290
- url: import_zod30.z.string().url(),
26291
- type: import_zod30.z.enum(["post", "reel", "tv"]),
26292
- shortcode: import_zod30.z.string(),
26599
+ limited: import_zod31.z.boolean(),
26600
+ limitations: import_zod31.z.array(import_zod31.z.string()),
26601
+ items: import_zod31.z.array(import_zod31.z.object({
26602
+ url: import_zod31.z.string().url(),
26603
+ type: import_zod31.z.enum(["post", "reel", "tv"]),
26604
+ shortcode: import_zod31.z.string(),
26293
26605
  anchorText: NullableString,
26294
- firstSeenStage: import_zod30.z.string()
26606
+ firstSeenStage: import_zod31.z.string()
26295
26607
  }))
26296
26608
  };
26297
- InstagramMediaTrackOutput = import_zod30.z.object({
26298
- url: import_zod30.z.string().url(),
26299
- streamType: import_zod30.z.enum(["video", "audio", "unknown"]),
26300
- bitrate: import_zod30.z.number().int().nullable(),
26301
- durationSec: import_zod30.z.number().nullable(),
26609
+ InstagramMediaTrackOutput = import_zod31.z.object({
26610
+ url: import_zod31.z.string().url(),
26611
+ streamType: import_zod31.z.enum(["video", "audio", "unknown"]),
26612
+ bitrate: import_zod31.z.number().int().nullable(),
26613
+ durationSec: import_zod31.z.number().nullable(),
26302
26614
  vencodeTag: NullableString,
26303
- width: import_zod30.z.number().int().nullable(),
26304
- height: import_zod30.z.number().int().nullable()
26615
+ width: import_zod31.z.number().int().nullable(),
26616
+ height: import_zod31.z.number().int().nullable()
26305
26617
  });
26306
- InstagramDownloadOutput = import_zod30.z.object({
26307
- kind: import_zod30.z.enum(["text", "image", "video", "audio", "muxed_video"]),
26308
- url: import_zod30.z.string().url().nullable(),
26618
+ InstagramDownloadOutput = import_zod31.z.object({
26619
+ kind: import_zod31.z.enum(["text", "image", "video", "audio", "muxed_video"]),
26620
+ url: import_zod31.z.string().url().nullable(),
26309
26621
  savedPath: NullableString,
26310
- sizeBytes: import_zod30.z.number().int().nullable(),
26622
+ sizeBytes: import_zod31.z.number().int().nullable(),
26311
26623
  mimeType: NullableString,
26312
26624
  error: NullableString
26313
26625
  });
26314
26626
  InstagramMediaDownloadOutputSchema = {
26315
- sourceUrl: import_zod30.z.string().url(),
26316
- pageUrl: import_zod30.z.string().url(),
26627
+ sourceUrl: import_zod31.z.string().url(),
26628
+ pageUrl: import_zod31.z.string().url(),
26317
26629
  browser: InstagramBrowserOutput,
26318
- type: import_zod30.z.enum(["post", "reel", "tv"]).nullable(),
26630
+ type: import_zod31.z.enum(["post", "reel", "tv"]).nullable(),
26319
26631
  shortcode: NullableString,
26320
26632
  ownerName: NullableString,
26321
26633
  caption: NullableString,
26322
- imageUrl: import_zod30.z.string().url().nullable(),
26323
- trackCount: import_zod30.z.number().int().min(0),
26634
+ imageUrl: import_zod31.z.string().url().nullable(),
26635
+ trackCount: import_zod31.z.number().int().min(0),
26324
26636
  selectedVideoTrack: InstagramMediaTrackOutput.nullable(),
26325
26637
  selectedAudioTrack: InstagramMediaTrackOutput.nullable(),
26326
- downloads: import_zod30.z.array(InstagramDownloadOutput),
26638
+ downloads: import_zod31.z.array(InstagramDownloadOutput),
26327
26639
  outputDir: NullableString,
26328
- warnings: import_zod30.z.array(import_zod30.z.string()),
26329
- limitations: import_zod30.z.array(import_zod30.z.string()),
26330
- transcript: import_zod30.z.object({
26331
- wordCount: import_zod30.z.number().int().min(0),
26332
- chunkCount: import_zod30.z.number().int().min(0),
26333
- durationMs: import_zod30.z.number().nullable(),
26334
- transcriptText: import_zod30.z.string(),
26335
- chunks: import_zod30.z.array(TranscriptChunkOutput)
26640
+ warnings: import_zod31.z.array(import_zod31.z.string()),
26641
+ limitations: import_zod31.z.array(import_zod31.z.string()),
26642
+ transcript: import_zod31.z.object({
26643
+ wordCount: import_zod31.z.number().int().min(0),
26644
+ chunkCount: import_zod31.z.number().int().min(0),
26645
+ durationMs: import_zod31.z.number().nullable(),
26646
+ transcriptText: import_zod31.z.string(),
26647
+ chunks: import_zod31.z.array(TranscriptChunkOutput)
26336
26648
  }).nullable()
26337
26649
  };
26338
26650
  YoutubeTranscribeOutputSchema = {
26339
26651
  videoId: NullableString,
26340
26652
  url: NullableString,
26341
- wordCount: import_zod30.z.number().int().min(0),
26342
- chunkCount: import_zod30.z.number().int().min(0),
26343
- durationMs: import_zod30.z.number().nullable(),
26344
- transcriptText: import_zod30.z.string(),
26345
- chunks: import_zod30.z.array(TranscriptChunkOutput),
26346
- resolvedInputs: import_zod30.z.object({
26653
+ wordCount: import_zod31.z.number().int().min(0),
26654
+ chunkCount: import_zod31.z.number().int().min(0),
26655
+ durationMs: import_zod31.z.number().nullable(),
26656
+ transcriptText: import_zod31.z.string(),
26657
+ chunks: import_zod31.z.array(TranscriptChunkOutput),
26658
+ resolvedInputs: import_zod31.z.object({
26347
26659
  videoId: NullableString,
26348
26660
  url: NullableString
26349
26661
  })
26350
26662
  };
26351
26663
  FacebookAdTranscribeOutputSchema = {
26352
- videoUrl: import_zod30.z.string().url(),
26353
- wordCount: import_zod30.z.number().int().min(0),
26354
- chunkCount: import_zod30.z.number().int().min(0),
26355
- durationMs: import_zod30.z.number().nullable(),
26356
- transcriptText: import_zod30.z.string(),
26357
- chunks: import_zod30.z.array(TranscriptChunkOutput),
26358
- resolvedInputs: import_zod30.z.object({
26359
- videoUrl: import_zod30.z.string().url()
26664
+ videoUrl: import_zod31.z.string().url(),
26665
+ wordCount: import_zod31.z.number().int().min(0),
26666
+ chunkCount: import_zod31.z.number().int().min(0),
26667
+ durationMs: import_zod31.z.number().nullable(),
26668
+ transcriptText: import_zod31.z.string(),
26669
+ chunks: import_zod31.z.array(TranscriptChunkOutput),
26670
+ resolvedInputs: import_zod31.z.object({
26671
+ videoUrl: import_zod31.z.string().url()
26360
26672
  })
26361
26673
  };
26362
26674
  GoogleAdsTranscribeOutputSchema = {
26363
- videoUrl: import_zod30.z.string().url(),
26364
- wordCount: import_zod30.z.number().int().min(0),
26365
- chunkCount: import_zod30.z.number().int().min(0),
26366
- durationMs: import_zod30.z.number().nullable(),
26367
- transcriptText: import_zod30.z.string(),
26368
- chunks: import_zod30.z.array(TranscriptChunkOutput),
26369
- resolvedInputs: import_zod30.z.object({
26370
- videoUrl: import_zod30.z.string().url()
26675
+ videoUrl: import_zod31.z.string().url(),
26676
+ wordCount: import_zod31.z.number().int().min(0),
26677
+ chunkCount: import_zod31.z.number().int().min(0),
26678
+ durationMs: import_zod31.z.number().nullable(),
26679
+ transcriptText: import_zod31.z.string(),
26680
+ chunks: import_zod31.z.array(TranscriptChunkOutput),
26681
+ resolvedInputs: import_zod31.z.object({
26682
+ videoUrl: import_zod31.z.string().url()
26371
26683
  })
26372
26684
  };
26373
26685
  CaptureSerpSnapshotOutputSchema = {
26374
- schemaVersion: import_zod30.z.literal("serp-intelligence.capture.v1"),
26375
- status: import_zod30.z.string(),
26686
+ schemaVersion: import_zod31.z.literal("serp-intelligence.capture.v1"),
26687
+ status: import_zod31.z.string(),
26376
26688
  query: NullableString,
26377
26689
  location: NullableString,
26378
26690
  capturedAt: NullableString,
26379
- resultCount: import_zod30.z.number().int().min(0).nullable(),
26691
+ resultCount: import_zod31.z.number().int().min(0).nullable(),
26380
26692
  snapshotId: NullableString,
26381
- resolvedInputs: import_zod30.z.record(import_zod30.z.unknown()),
26382
- artifacts: import_zod30.z.array(import_zod30.z.record(import_zod30.z.unknown())),
26383
- diagnostics: import_zod30.z.record(import_zod30.z.unknown()).nullable(),
26384
- providerPayload: import_zod30.z.record(import_zod30.z.unknown())
26693
+ resolvedInputs: import_zod31.z.record(import_zod31.z.unknown()),
26694
+ artifacts: import_zod31.z.array(import_zod31.z.record(import_zod31.z.unknown())),
26695
+ diagnostics: import_zod31.z.record(import_zod31.z.unknown()).nullable(),
26696
+ providerPayload: import_zod31.z.record(import_zod31.z.unknown())
26385
26697
  };
26386
26698
  CaptureSerpPageSnapshotsOutputSchema = {
26387
- schemaVersion: import_zod30.z.literal("serp-intelligence.page-snapshots.v1"),
26388
- status: import_zod30.z.string(),
26389
- count: import_zod30.z.number().int().min(0),
26390
- failedCount: import_zod30.z.number().int().min(0),
26391
- captures: import_zod30.z.array(import_zod30.z.record(import_zod30.z.unknown())),
26392
- resolvedInputs: import_zod30.z.record(import_zod30.z.unknown()),
26393
- diagnostics: import_zod30.z.record(import_zod30.z.unknown()).nullable(),
26394
- providerPayload: import_zod30.z.record(import_zod30.z.unknown())
26699
+ schemaVersion: import_zod31.z.literal("serp-intelligence.page-snapshots.v1"),
26700
+ status: import_zod31.z.string(),
26701
+ count: import_zod31.z.number().int().min(0),
26702
+ failedCount: import_zod31.z.number().int().min(0),
26703
+ captures: import_zod31.z.array(import_zod31.z.record(import_zod31.z.unknown())),
26704
+ resolvedInputs: import_zod31.z.record(import_zod31.z.unknown()),
26705
+ diagnostics: import_zod31.z.record(import_zod31.z.unknown()).nullable(),
26706
+ providerPayload: import_zod31.z.record(import_zod31.z.unknown())
26395
26707
  };
26396
26708
  CreditsInfoInputSchema = {
26397
- item: import_zod30.z.string().optional().describe('Optional tool, action, or feature to look up, e.g. "maps reviews", "extract_url", "YouTube transcription", or "concurrency"'),
26398
- includeLedger: import_zod30.z.boolean().default(false).describe("Whether to include recent credit ledger entries")
26709
+ item: import_zod31.z.string().optional().describe('Optional tool, action, or feature to look up, e.g. "maps reviews", "extract_url", "YouTube transcription", or "concurrency"'),
26710
+ includeLedger: import_zod31.z.boolean().default(false).describe("Whether to include recent credit ledger entries")
26399
26711
  };
26400
- WorkflowIdSchema2 = import_zod30.z.enum([
26712
+ WorkflowIdSchema2 = import_zod31.z.enum([
26401
26713
  "directory",
26402
26714
  "get-leads",
26403
26715
  "agent-packet",
@@ -26408,129 +26720,129 @@ var init_mcp_tool_schemas = __esm({
26408
26720
  "ai-overview-language"
26409
26721
  ]);
26410
26722
  WorkflowListInputSchema = {
26411
- includeRecipes: import_zod30.z.boolean().default(true).describe("Include high-level AI-facing recipes such as market analysis, ICP research, forum/review research, brand design briefings, CRO audits, positioning briefs, content gaps, and AI search visibility audits.")
26723
+ includeRecipes: import_zod31.z.boolean().default(true).describe("Include high-level AI-facing recipes such as market analysis, ICP research, forum/review research, brand design briefings, CRO audits, positioning briefs, content gaps, and AI search visibility audits.")
26412
26724
  };
26413
26725
  WorkflowSuggestInputSchema = {
26414
- goal: import_zod30.z.string().min(1).describe('The user goal or job to route, e.g. "market analysis for roofers in Tennessee", "ICP research for med spas", "CRO audit for this URL", or "brand design briefing".'),
26415
- query: import_zod30.z.string().optional().describe("Business category, niche, or Maps query when known."),
26416
- keyword: import_zod30.z.string().optional().describe("Search keyword, audience problem, or content topic when known."),
26417
- domain: import_zod30.z.string().optional().describe("Target domain or brand domain when known."),
26418
- url: import_zod30.z.string().url().optional().describe("Target URL when the workflow should inspect a specific page."),
26419
- location: import_zod30.z.string().optional().describe("City/region/country for localized research, e.g. Denver, CO."),
26420
- state: import_zod30.z.string().optional().describe("US state abbreviation or name for state-wide market research."),
26421
- maxSuggestions: import_zod30.z.number().int().min(1).max(8).default(3).describe("Number of matching workflow recipes to return.")
26726
+ goal: import_zod31.z.string().min(1).describe('The user goal or job to route, e.g. "market analysis for roofers in Tennessee", "ICP research for med spas", "CRO audit for this URL", or "brand design briefing".'),
26727
+ query: import_zod31.z.string().optional().describe("Business category, niche, or Maps query when known."),
26728
+ keyword: import_zod31.z.string().optional().describe("Search keyword, audience problem, or content topic when known."),
26729
+ domain: import_zod31.z.string().optional().describe("Target domain or brand domain when known."),
26730
+ url: import_zod31.z.string().url().optional().describe("Target URL when the workflow should inspect a specific page."),
26731
+ location: import_zod31.z.string().optional().describe("City/region/country for localized research, e.g. Denver, CO."),
26732
+ state: import_zod31.z.string().optional().describe("US state abbreviation or name for state-wide market research."),
26733
+ maxSuggestions: import_zod31.z.number().int().min(1).max(8).default(3).describe("Number of matching workflow recipes to return.")
26422
26734
  };
26423
26735
  WorkflowRunInputSchema = {
26424
26736
  workflowId: WorkflowIdSchema2.describe("Workflow to run: directory, get-leads, agent-packet, local-competitive-audit, map-comparison, serp-comparison, paa-expansion-brief, ai-overview-language. Use only these values; call workflow_list or workflow_suggest first when unsure."),
26425
- input: import_zod30.z.record(import_zod30.z.unknown()).default({}).describe("Workflow-specific input object. Examples: get-leads uses {query, location, maxResults?, enrichWebsites?, hydrateReviewCounts?}; agent-packet uses {keyword, domain?, location?, maxQuestions?}; local-competitive-audit uses {query, state, minPopulation?, maxCities?, maxResultsPerCity?, hydrateTop?, maxReviews?}; serp-comparison uses {keyword, domain?, url?, location?, extractTop?}."),
26426
- webhookUrl: import_zod30.z.string().url().optional().describe("Optional HTTPS webhook to receive the completed hosted workflow run event.")
26737
+ input: import_zod31.z.record(import_zod31.z.unknown()).default({}).describe("Workflow-specific input object. Examples: get-leads uses {query, location, maxResults?, enrichWebsites?, hydrateReviewCounts?}; agent-packet uses {keyword, domain?, location?, maxQuestions?}; local-competitive-audit uses {query, state, minPopulation?, maxCities?, maxResultsPerCity?, hydrateTop?, maxReviews?}; serp-comparison uses {keyword, domain?, url?, location?, extractTop?}."),
26738
+ webhookUrl: import_zod31.z.string().url().optional().describe("Optional HTTPS webhook to receive the completed hosted workflow run event.")
26427
26739
  };
26428
26740
  WorkflowStepInputSchema = {
26429
- runId: import_zod30.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself. Advances the run by exactly one step (one logical leg, e.g. one live harvest).")
26741
+ runId: import_zod31.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself. Advances the run by exactly one step (one logical leg, e.g. one live harvest).")
26430
26742
  };
26431
26743
  WorkflowStatusInputSchema = {
26432
- runId: import_zod30.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself.")
26744
+ runId: import_zod31.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself.")
26433
26745
  };
26434
26746
  WorkflowArtifactReadInputSchema = {
26435
- runId: import_zod30.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself."),
26436
- artifactId: import_zod30.z.string().min(1).describe("Artifact id from the run artifact list returned by workflow_run, workflow_step, or workflow_status. Use only a returned artifactId; do not construct one yourself."),
26437
- maxBytes: import_zod30.z.number().int().min(1e3).max(1e6).default(2e5).describe("Maximum bytes of artifact text to return inline. Use lower values for large CSV/JSON artifacts; call again with the downloadUrl if needed outside MCP.")
26747
+ runId: import_zod31.z.string().min(1).describe("Workflow run id returned by workflow_run, workflow_step, or workflow_status. Use only a returned runId; do not construct one yourself."),
26748
+ artifactId: import_zod31.z.string().min(1).describe("Artifact id from the run artifact list returned by workflow_run, workflow_step, or workflow_status. Use only a returned artifactId; do not construct one yourself."),
26749
+ maxBytes: import_zod31.z.number().int().min(1e3).max(1e6).default(2e5).describe("Maximum bytes of artifact text to return inline. Use lower values for large CSV/JSON artifacts; call again with the downloadUrl if needed outside MCP.")
26438
26750
  };
26439
- WorkflowRecipeOutput = import_zod30.z.object({
26440
- id: import_zod30.z.string(),
26441
- title: import_zod30.z.string(),
26442
- description: import_zod30.z.string(),
26443
- primaryWorkflowId: import_zod30.z.string().nullable(),
26444
- recommendedTools: import_zod30.z.array(import_zod30.z.string()),
26445
- requiredInputs: import_zod30.z.array(import_zod30.z.string()),
26446
- optionalInputs: import_zod30.z.array(import_zod30.z.string()),
26447
- produces: import_zod30.z.array(import_zod30.z.string()),
26448
- runHint: import_zod30.z.string()
26449
- });
26450
- WorkflowDefinitionOutput = import_zod30.z.object({
26451
- id: import_zod30.z.string(),
26452
- title: import_zod30.z.string(),
26453
- description: import_zod30.z.string()
26751
+ WorkflowRecipeOutput = import_zod31.z.object({
26752
+ id: import_zod31.z.string(),
26753
+ title: import_zod31.z.string(),
26754
+ description: import_zod31.z.string(),
26755
+ primaryWorkflowId: import_zod31.z.string().nullable(),
26756
+ recommendedTools: import_zod31.z.array(import_zod31.z.string()),
26757
+ requiredInputs: import_zod31.z.array(import_zod31.z.string()),
26758
+ optionalInputs: import_zod31.z.array(import_zod31.z.string()),
26759
+ produces: import_zod31.z.array(import_zod31.z.string()),
26760
+ runHint: import_zod31.z.string()
26761
+ });
26762
+ WorkflowDefinitionOutput = import_zod31.z.object({
26763
+ id: import_zod31.z.string(),
26764
+ title: import_zod31.z.string(),
26765
+ description: import_zod31.z.string()
26454
26766
  });
26455
- WorkflowArtifactOutput = import_zod30.z.record(import_zod30.z.unknown());
26767
+ WorkflowArtifactOutput = import_zod31.z.record(import_zod31.z.unknown());
26456
26768
  WorkflowListOutputSchema = {
26457
- workflows: import_zod30.z.array(WorkflowDefinitionOutput),
26458
- recipes: import_zod30.z.array(WorkflowRecipeOutput)
26769
+ workflows: import_zod31.z.array(WorkflowDefinitionOutput),
26770
+ recipes: import_zod31.z.array(WorkflowRecipeOutput)
26459
26771
  };
26460
26772
  WorkflowSuggestOutputSchema = {
26461
- goal: import_zod30.z.string(),
26462
- suggestions: import_zod30.z.array(WorkflowRecipeOutput)
26773
+ goal: import_zod31.z.string(),
26774
+ suggestions: import_zod31.z.array(WorkflowRecipeOutput)
26463
26775
  };
26464
26776
  WorkflowRunOutputSchema = {
26465
- workflowId: import_zod30.z.string(),
26466
- input: import_zod30.z.record(import_zod30.z.unknown()),
26467
- run: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26468
- summary: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26469
- step: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26470
- nextStep: import_zod30.z.record(import_zod30.z.unknown()).nullable().optional(),
26471
- done: import_zod30.z.boolean().optional(),
26472
- artifacts: import_zod30.z.array(WorkflowArtifactOutput)
26777
+ workflowId: import_zod31.z.string(),
26778
+ input: import_zod31.z.record(import_zod31.z.unknown()),
26779
+ run: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26780
+ summary: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26781
+ step: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26782
+ nextStep: import_zod31.z.record(import_zod31.z.unknown()).nullable().optional(),
26783
+ done: import_zod31.z.boolean().optional(),
26784
+ artifacts: import_zod31.z.array(WorkflowArtifactOutput)
26473
26785
  };
26474
26786
  WorkflowStepOutputSchema = {
26475
- runId: import_zod30.z.string(),
26476
- run: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26477
- summary: import_zod30.z.record(import_zod30.z.unknown()).nullable().optional(),
26478
- step: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26479
- nextStep: import_zod30.z.record(import_zod30.z.unknown()).nullable().optional(),
26480
- done: import_zod30.z.boolean(),
26481
- artifacts: import_zod30.z.array(WorkflowArtifactOutput)
26787
+ runId: import_zod31.z.string(),
26788
+ run: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26789
+ summary: import_zod31.z.record(import_zod31.z.unknown()).nullable().optional(),
26790
+ step: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26791
+ nextStep: import_zod31.z.record(import_zod31.z.unknown()).nullable().optional(),
26792
+ done: import_zod31.z.boolean(),
26793
+ artifacts: import_zod31.z.array(WorkflowArtifactOutput)
26482
26794
  };
26483
26795
  WorkflowStatusOutputSchema = {
26484
- run: import_zod30.z.record(import_zod30.z.unknown()).optional(),
26485
- artifacts: import_zod30.z.array(WorkflowArtifactOutput)
26796
+ run: import_zod31.z.record(import_zod31.z.unknown()).optional(),
26797
+ artifacts: import_zod31.z.array(WorkflowArtifactOutput)
26486
26798
  };
26487
26799
  WorkflowArtifactReadOutputSchema = {
26488
- runId: import_zod30.z.string(),
26489
- artifactId: import_zod30.z.string(),
26490
- contentType: import_zod30.z.string(),
26491
- bytes: import_zod30.z.number().int().min(0),
26492
- truncated: import_zod30.z.boolean(),
26493
- text: import_zod30.z.string()
26800
+ runId: import_zod31.z.string(),
26801
+ artifactId: import_zod31.z.string(),
26802
+ contentType: import_zod31.z.string(),
26803
+ bytes: import_zod31.z.number().int().min(0),
26804
+ truncated: import_zod31.z.boolean(),
26805
+ text: import_zod31.z.string()
26494
26806
  };
26495
26807
  SearchSerpInputSchema = {
26496
- query: import_zod30.z.string().min(1).describe('Core search topic only. Separate location when possible. If user says "best dentist in Brooklyn NY serp", use query="best dentist" and location="Brooklyn, NY".'),
26497
- location: import_zod30.z.string().optional().describe("City, region, or country for geo-targeted results, inferred from user request when present."),
26498
- gl: import_zod30.z.string().length(2).default("us").describe("Google country code inferred from location or user language."),
26499
- hl: import_zod30.z.string().default("en").describe("Google interface/content language inferred from user request."),
26500
- device: import_zod30.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings."),
26501
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset \u2014 routing is automatic. Set "location" only to force local-pack targeting.'),
26502
- proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override for residential location proxy targeting. Use only with proxyMode location when the user gives a specific ZIP or city-center targeting needs to be forced."),
26503
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior."),
26504
- pages: import_zod30.z.number().int().min(1).max(2).default(1).describe("Number of result pages to fetch (1\u20132)")
26808
+ query: import_zod31.z.string().min(1).describe('The search query. For localized results, KEEP the place in the query text \u2014 "best dentist in Brooklyn NY" stays query="best dentist Brooklyn NY" (and also set location="Brooklyn, NY"). City-in-query is what localizes results reliably; do not strip it out.'),
26809
+ location: import_zod31.z.string().optional().describe("City, region, or country for geo signals (uule + location evidence). Set it alongside a city-in-query wording; on its own it does NOT reliably localize results."),
26810
+ gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from location or user language."),
26811
+ hl: import_zod31.z.string().default("en").describe("Google interface/content language inferred from user request."),
26812
+ device: import_zod31.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use desktop by default; use mobile only when the user asks for mobile rankings."),
26813
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress \u2014 reliable). Do NOT set "location" just because the user named a city; localized results come from city-in-query wording. "location" forces a residential geo-IP for rank-tracking fidelity only, is frequently CAPTCHA-blocked, and should be used only when the user explicitly demands as-seen-from-the-city results and accepts failures.'),
26814
+ proxyZip: import_zod31.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location" (see its warning); ignored otherwise.'),
26815
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser/session/location diagnostics in the response. Use true when debugging localization, CAPTCHA, or proxy behavior."),
26816
+ pages: import_zod31.z.number().int().min(1).max(2).default(1).describe("Number of result pages to fetch (1\u20132)")
26505
26817
  };
26506
26818
  CaptureSerpSnapshotInputSchema = {
26507
- query: import_zod30.z.string().min(1).describe("Core search query to capture as a structured SERP Intelligence snapshot. Separate the place into location when the user gives a city, region, country, or ZIP."),
26508
- location: import_zod30.z.string().optional().describe("City, region, country, or service area used for localized Google results. MCP Scraper records location evidence; UULE alone is not proof of localization."),
26509
- gl: import_zod30.z.string().length(2).default("us").describe("Google country code inferred from the requested market, e.g. us, gb, ca, au."),
26510
- hl: import_zod30.z.string().default("en").describe("Google interface/content language inferred from the user request."),
26511
- device: import_zod30.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use mobile only when the user asks for mobile rankings or mobile SERP evidence."),
26512
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset \u2014 routing is automatic. Set "location" only to force city/ZIP targeting.'),
26513
- proxyZip: import_zod30.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override for residential location proxy targeting. Use only with proxyMode location when a precise city-center or ZIP proxy is needed."),
26514
- pages: import_zod30.z.number().int().min(1).max(2).default(1).describe("Number of Google result pages to capture. Use 1 normally and 2 only when the user needs deeper ranking evidence."),
26515
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser, proxy, and location diagnostics. Use true when debugging localization, CAPTCHA, proxy selection, or capture reliability."),
26516
- includePageSnapshots: import_zod30.z.boolean().default(false).describe("Also capture ranking-page snapshots for selected SERP URLs through the same product capture path."),
26517
- pageSnapshotLimit: import_zod30.z.number().int().min(0).max(10).default(0).describe("Maximum ranking-page snapshots to capture when includePageSnapshots is true. Use 0 when only SERP evidence is needed.")
26819
+ query: import_zod31.z.string().min(1).describe('Search query to capture as a structured SERP Intelligence snapshot. For localized captures, KEEP the place in the query text (e.g. "botox clinic austin tx") and also set location; city-in-query is what localizes results reliably.'),
26820
+ location: import_zod31.z.string().optional().describe("City, region, country, or service area used for localized Google results. MCP Scraper records location evidence; UULE alone is not proof of localization."),
26821
+ gl: import_zod31.z.string().length(2).default("us").describe("Google country code inferred from the requested market, e.g. us, gb, ca, au."),
26822
+ hl: import_zod31.z.string().default("en").describe("Google interface/content language inferred from the user request."),
26823
+ device: import_zod31.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use mobile only when the user asks for mobile rankings or mobile SERP evidence."),
26824
+ proxyMode: import_zod31.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress \u2014 reliable). Do NOT set "location" just because a city was named; localized captures come from city-in-query wording. "location" forces a residential geo-IP (rank-tracking fidelity only), is frequently CAPTCHA-blocked, and should be used only when the user explicitly needs as-seen-from-the-city evidence and accepts failures.'),
26825
+ proxyZip: import_zod31.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location" (see its warning); ignored otherwise.'),
26826
+ pages: import_zod31.z.number().int().min(1).max(2).default(1).describe("Number of Google result pages to capture. Use 1 normally and 2 only when the user needs deeper ranking evidence."),
26827
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser, proxy, and location diagnostics. Use true when debugging localization, CAPTCHA, proxy selection, or capture reliability."),
26828
+ includePageSnapshots: import_zod31.z.boolean().default(false).describe("Also capture ranking-page snapshots for selected SERP URLs through the same product capture path."),
26829
+ pageSnapshotLimit: import_zod31.z.number().int().min(0).max(10).default(0).describe("Maximum ranking-page snapshots to capture when includePageSnapshots is true. Use 0 when only SERP evidence is needed.")
26518
26830
  };
26519
26831
  ScreenshotInputSchema = {
26520
- url: import_zod30.z.string().url().describe("URL to capture as a full-page screenshot. Use http or https. Pass allowLocal: true to capture localhost or private-network URLs during development."),
26521
- device: import_zod30.z.enum(["desktop", "mobile"]).default("desktop").describe("Viewport profile. desktop = 1440\xD7900. mobile = 390\xD7844. Use desktop by default; use mobile when the user asks for a mobile view."),
26522
- allowLocal: import_zod30.z.boolean().default(false).describe("Allow localhost and private-network URLs (127.x, 192.168.x, 10.x, etc.). For local development only \u2014 not for production use.")
26832
+ url: import_zod31.z.string().url().describe("URL to capture as a full-page screenshot. Use http or https. Pass allowLocal: true to capture localhost or private-network URLs during development."),
26833
+ device: import_zod31.z.enum(["desktop", "mobile"]).default("desktop").describe("Viewport profile. desktop = 1440\xD7900. mobile = 390\xD7844. Use desktop by default; use mobile when the user asks for a mobile view."),
26834
+ allowLocal: import_zod31.z.boolean().default(false).describe("Allow localhost and private-network URLs (127.x, 192.168.x, 10.x, etc.). For local development only \u2014 not for production use.")
26523
26835
  };
26524
26836
  CaptureSerpPageSnapshotsInputSchema = {
26525
- urls: import_zod30.z.array(import_zod30.z.string().url()).min(1).max(25).describe("Public HTTP/HTTPS URLs to capture as SERP Intelligence page snapshots. Do not pass localhost, private IPs, file URLs, or internal admin URLs."),
26526
- targets: import_zod30.z.array(import_zod30.z.object({
26527
- url: import_zod30.z.string().url().describe("Public HTTP/HTTPS URL to capture."),
26528
- sourceKind: import_zod30.z.enum(["organic", "ai_citation", "local_pack_website", "configured_target", "site_subject"]).default("configured_target").describe("Why this page is being captured for SERP Intelligence evidence."),
26529
- sourcePosition: import_zod30.z.number().int().min(1).optional().describe("Ranking or citation position when the page came from SERP evidence.")
26837
+ urls: import_zod31.z.array(import_zod31.z.string().url()).min(1).max(25).describe("Public HTTP/HTTPS URLs to capture as SERP Intelligence page snapshots. Do not pass localhost, private IPs, file URLs, or internal admin URLs."),
26838
+ targets: import_zod31.z.array(import_zod31.z.object({
26839
+ url: import_zod31.z.string().url().describe("Public HTTP/HTTPS URL to capture."),
26840
+ sourceKind: import_zod31.z.enum(["organic", "ai_citation", "local_pack_website", "configured_target", "site_subject"]).default("configured_target").describe("Why this page is being captured for SERP Intelligence evidence."),
26841
+ sourcePosition: import_zod31.z.number().int().min(1).optional().describe("Ranking or citation position when the page came from SERP evidence.")
26530
26842
  }).strict()).min(1).max(25).optional().describe("Structured page snapshot targets. Use this instead of urls when source kind or position should be preserved."),
26531
- maxConcurrency: import_zod30.z.number().int().min(1).max(5).default(2).describe("Parallel page captures. Use 2 normally; higher values can increase proxy/browser pressure."),
26532
- timeoutMs: import_zod30.z.number().int().min(1e3).max(6e4).default(15e3).describe("Per-page capture timeout in milliseconds. Increase for slow pages; timeout artifacts are returned as structured capture failures."),
26533
- debug: import_zod30.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics for page snapshot debugging. Use true for capture, network, or proxy troubleshooting.")
26843
+ maxConcurrency: import_zod31.z.number().int().min(1).max(5).default(2).describe("Parallel page captures. Use 2 normally; higher values can increase proxy/browser pressure."),
26844
+ timeoutMs: import_zod31.z.number().int().min(1e3).max(6e4).default(15e3).describe("Per-page capture timeout in milliseconds. Increase for slow pages; timeout artifacts are returned as structured capture failures."),
26845
+ debug: import_zod31.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics for page snapshot debugging. Use true for capture, network, or proxy troubleshooting.")
26534
26846
  };
26535
26847
  }
26536
26848
  });
@@ -27020,6 +27332,20 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
27020
27332
  outputSchema: RedditThreadOutputSchema,
27021
27333
  annotations: liveWebToolAnnotations("Reddit Thread + Comments")
27022
27334
  }, async (input) => formatRedditThread(await executor.redditThread(input), input));
27335
+ server.registerTool("video_frame_analysis", {
27336
+ title: "Video Breakdown (frame-by-frame + transcript)",
27337
+ description: `Produce a deep, structured breakdown of a video: what happens on screen, what is said, how it is paced, and how to make one like it. Use this when the user wants to analyze, break down, study, reverse-engineer, or "figure out how they made" a video (an ad, a YouTube video, a reel, a competitor's content). It samples up to 120 frames spread across the whole video (up to 30 minutes), runs vision AI on every frame, transcribes the audio, and returns a report with: Summary, Pacing & Energy, Words-per-Minute & delivery, Topic Outline, Key Points, Hook Analysis, Visual Style, and a step-by-step "How to Replicate This Video" recipe \u2014 all quality-checked. Pass a DIRECT video file URL (.mp4/.webm/.mov); for a YouTube/Facebook/Instagram link, resolve it to a direct media URL first (e.g. facebook_page_intel returns a videoUrl). This runs asynchronously and costs a flat $1 (refunded if it fails): it returns a runId immediately \u2014 then call video_frame_analysis_status with that runId every few seconds until status is "done" to get the finished report.`,
27338
+ inputSchema: VideoFrameAnalysisInputSchema,
27339
+ outputSchema: VideoFrameAnalysisOutputSchema,
27340
+ annotations: { title: "Video Breakdown", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
27341
+ }, async (input) => executor.videoFrameAnalysis(input));
27342
+ server.registerTool("video_frame_analysis_status", {
27343
+ title: "Video Breakdown Status",
27344
+ description: 'Check the progress of a video breakdown started with video_frame_analysis, using the runId it returned. Poll this every few seconds. While running it reports the current phase and how many frames have been analyzed; when status is "done" it returns the full breakdown report (Markdown) and the memory vault path where it was saved. Free to call. Stop polling when status is "done" or "failed".',
27345
+ inputSchema: VideoFrameAnalysisStatusInputSchema,
27346
+ outputSchema: VideoFrameAnalysisStatusOutputSchema,
27347
+ annotations: { title: "Video Breakdown Status", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
27348
+ }, async (input) => executor.videoFrameAnalysisStatus(input));
27023
27349
  server.registerTool("facebook_ad_transcribe", {
27024
27350
  title: "Facebook Ad Transcription",
27025
27351
  description: "Transcribe audio from a Facebook ad video CDN URL. Use this when facebook_page_intel returned a direct videoUrl and the user asks what the ad says, what claims it makes, or wants ad-message extraction. Returns full transcript, timestamped chunks, word count, and resolvedInputs. Use only with the direct videoUrl value from facebook_page_intel results; do not pass public Facebook post/reel/share URLs. Use facebook_video_transcribe for organic Facebook URLs, and facebook_page_intel first when you only have a brand/page/ad library handle.",
@@ -27382,6 +27708,12 @@ var init_http_mcp_tool_executor = __esm({
27382
27708
  redditThread(input) {
27383
27709
  return this.call("/reddit/thread", input, this.httpTimeoutOverrideMs ?? 24e4);
27384
27710
  }
27711
+ videoFrameAnalysis(input) {
27712
+ return this.call("/video/analyze", input);
27713
+ }
27714
+ videoFrameAnalysisStatus(input) {
27715
+ return this.call("/video/status", input);
27716
+ }
27385
27717
  facebookAdTranscribe(input) {
27386
27718
  return this.call("/facebook/transcribe", input);
27387
27719
  }
@@ -27588,17 +27920,17 @@ var init_export = __esm({
27588
27920
  });
27589
27921
 
27590
27922
  // src/mcp/browser-agent-tool-schemas.ts
27591
- var import_zod31, NullableString2, BrowserRawObject, BrowserElementOutput, BrowserBaseOutput, BrowserReplayBaseOutput, BrowserOpenInputSchema, BrowserProfileConnectInputSchema, BrowserProfileListInputSchema, BrowserSessionInputSchema, BrowserLocateTargetSchema, BrowserLocateInputSchema, BrowserGotoInputSchema, BrowserClickInputSchema, BrowserTypeInputSchema, BrowserScrollInputSchema, BrowserPressInputSchema, BrowserReplayStopInputSchema, BrowserReplayDownloadInputSchema, BrowserReplayAnnotationSchema, BrowserReplayMarkInputSchema, BrowserReplayAnnotateInputSchema, BrowserListInputSchema, BrowserCaptureFanoutInputSchema, FanoutSourceOutput, BrowserCaptureFanoutOutputSchema, BrowserOpenOutputSchema, BrowserProfileLogin, BrowserProfileConnectOutputSchema, BrowserProfileListOutputSchema, BrowserScreenshotOutputSchema, BrowserReadOutputSchema, BrowserLocateOutputSchema, BrowserActionOutputSchema, BrowserReplayStartOutputSchema, BrowserReplayStopOutputSchema, BrowserListReplaysOutputSchema, BrowserReplayDownloadOutputSchema, BrowserReplayMarkOutputSchema, BrowserReplayAnnotateOutputSchema, BrowserCloseOutputSchema, BrowserListSessionsOutputSchema;
27923
+ var import_zod32, NullableString2, BrowserRawObject, BrowserElementOutput, BrowserBaseOutput, BrowserReplayBaseOutput, BrowserOpenInputSchema, BrowserProfileConnectInputSchema, BrowserProfileListInputSchema, BrowserSessionInputSchema, BrowserLocateTargetSchema, BrowserLocateInputSchema, BrowserGotoInputSchema, BrowserClickInputSchema, BrowserTypeInputSchema, BrowserScrollInputSchema, BrowserPressInputSchema, BrowserReplayStopInputSchema, BrowserReplayDownloadInputSchema, BrowserReplayAnnotationSchema, BrowserReplayMarkInputSchema, BrowserReplayAnnotateInputSchema, BrowserListInputSchema, BrowserCaptureFanoutInputSchema, FanoutSourceOutput, BrowserCaptureFanoutOutputSchema, BrowserOpenOutputSchema, BrowserProfileLogin, BrowserProfileConnectOutputSchema, BrowserProfileListOutputSchema, BrowserScreenshotOutputSchema, BrowserReadOutputSchema, BrowserLocateOutputSchema, BrowserActionOutputSchema, BrowserReplayStartOutputSchema, BrowserReplayStopOutputSchema, BrowserListReplaysOutputSchema, BrowserReplayDownloadOutputSchema, BrowserReplayMarkOutputSchema, BrowserReplayAnnotateOutputSchema, BrowserCloseOutputSchema, BrowserListSessionsOutputSchema;
27592
27924
  var init_browser_agent_tool_schemas = __esm({
27593
27925
  "src/mcp/browser-agent-tool-schemas.ts"() {
27594
27926
  "use strict";
27595
- import_zod31 = require("zod");
27596
- NullableString2 = import_zod31.z.string().nullable();
27597
- BrowserRawObject = import_zod31.z.record(import_zod31.z.unknown());
27598
- BrowserElementOutput = import_zod31.z.record(import_zod31.z.unknown());
27927
+ import_zod32 = require("zod");
27928
+ NullableString2 = import_zod32.z.string().nullable();
27929
+ BrowserRawObject = import_zod32.z.record(import_zod32.z.unknown());
27930
+ BrowserElementOutput = import_zod32.z.record(import_zod32.z.unknown());
27599
27931
  BrowserBaseOutput = {
27600
- ok: import_zod31.z.boolean().describe("Whether the browser-agent action succeeded."),
27601
- tool: import_zod31.z.string().describe("Browser Agent MCP tool that produced this response."),
27932
+ ok: import_zod32.z.boolean().describe("Whether the browser-agent action succeeded."),
27933
+ tool: import_zod32.z.string().describe("Browser Agent MCP tool that produced this response."),
27602
27934
  session_id: NullableString2.describe("Browser session id when the response is scoped to a session.")
27603
27935
  };
27604
27936
  BrowserReplayBaseOutput = {
@@ -27606,333 +27938,333 @@ var init_browser_agent_tool_schemas = __esm({
27606
27938
  replay_id: NullableString2.describe("Replay id when the response is scoped to a replay.")
27607
27939
  };
27608
27940
  BrowserOpenInputSchema = {
27609
- label: import_zod31.z.string().optional().describe("Optional human label for this session, shown in the watch console."),
27610
- url: import_zod31.z.string().url().optional().describe("Optional URL to navigate to immediately after opening."),
27611
- profile: import_zod31.z.string().optional().describe("Optional saved hosted profile name to load a logged-in session for a site."),
27612
- save_profile_changes: import_zod31.z.boolean().optional().describe("Persist cookies and browser storage back to the named profile when the session is closed. Use this for profile setup or intentional auth refreshes; avoid parallel sessions writing to the same profile."),
27613
- timeout_seconds: import_zod31.z.number().int().min(60).max(259200).optional().describe("How long the direct no-proxy browser session may live before auto-termination. Defaults to 600. The browser idles into a zero-cost standby between actions, so a longer timeout is cheap.")
27941
+ label: import_zod32.z.string().optional().describe("Optional human label for this session, shown in the watch console."),
27942
+ url: import_zod32.z.string().url().optional().describe("Optional URL to navigate to immediately after opening."),
27943
+ profile: import_zod32.z.string().optional().describe("Optional saved hosted profile name to load a logged-in session for a site."),
27944
+ save_profile_changes: import_zod32.z.boolean().optional().describe("Persist cookies and browser storage back to the named profile when the session is closed. Use this for profile setup or intentional auth refreshes; avoid parallel sessions writing to the same profile."),
27945
+ timeout_seconds: import_zod32.z.number().int().min(60).max(259200).optional().describe("How long the direct no-proxy browser session may live before auto-termination. Defaults to 600. The browser idles into a zero-cost standby between actions, so a longer timeout is cheap.")
27614
27946
  };
27615
27947
  BrowserProfileConnectInputSchema = {
27616
- email: import_zod31.z.string().optional().describe("Account email for the login being saved. Used to derive a stable, reusable profile name AND recorded as a note of who is connected. Does NOT import existing cookies \u2014 the user signs in fresh via the returned watch_url."),
27617
- profile: import_zod31.z.string().optional().describe("Profile to add this login to. Omit to derive one from email. A single profile holds MANY site logins \u2014 pass the same profile name again with a different domain to stack another account (e.g. add claude.ai to a profile that already has chatgpt.com)."),
27618
- domain: import_zod31.z.string().optional().describe("Site to log into, e.g. chatgpt.com, claude.ai, reddit.com. Defaults to chatgpt.com. Each domain is a separate login inside the profile."),
27619
- login_url: import_zod31.z.string().url().optional().describe("Login page for the domain. Defaults to https://<domain>/ (https://chatgpt.com/ when domain is omitted)."),
27620
- url: import_zod31.z.string().url().optional().describe("Deprecated alias for login_url. Use login_url."),
27621
- note: import_zod31.z.string().optional().describe('Free-text note describing this login, e.g. "ChatGPT Plus, work account". Surfaced by browser_profile_list so you can see what the profile holds.'),
27622
- label: import_zod31.z.string().optional().describe("Optional human label for this sign-in setup session."),
27623
- timeout_seconds: import_zod31.z.number().int().min(60).max(259200).optional().describe("How long the sign-in setup session may live before auto-termination. Defaults to 600.")
27948
+ email: import_zod32.z.string().optional().describe("Account email for the login being saved. Used to derive a stable, reusable profile name AND recorded as a note of who is connected. Does NOT import existing cookies \u2014 the user signs in fresh via the returned watch_url."),
27949
+ profile: import_zod32.z.string().optional().describe("Profile to add this login to. Omit to derive one from email. A single profile holds MANY site logins \u2014 pass the same profile name again with a different domain to stack another account (e.g. add claude.ai to a profile that already has chatgpt.com)."),
27950
+ domain: import_zod32.z.string().optional().describe("Site to log into, e.g. chatgpt.com, claude.ai, reddit.com. Defaults to chatgpt.com. Each domain is a separate login inside the profile."),
27951
+ login_url: import_zod32.z.string().url().optional().describe("Login page for the domain. Defaults to https://<domain>/ (https://chatgpt.com/ when domain is omitted)."),
27952
+ url: import_zod32.z.string().url().optional().describe("Deprecated alias for login_url. Use login_url."),
27953
+ note: import_zod32.z.string().optional().describe('Free-text note describing this login, e.g. "ChatGPT Plus, work account". Surfaced by browser_profile_list so you can see what the profile holds.'),
27954
+ label: import_zod32.z.string().optional().describe("Optional human label for this sign-in setup session."),
27955
+ timeout_seconds: import_zod32.z.number().int().min(60).max(259200).optional().describe("How long the sign-in setup session may live before auto-termination. Defaults to 600.")
27624
27956
  };
27625
27957
  BrowserProfileListInputSchema = {
27626
- profile: import_zod31.z.string().optional().describe("Profile whose saved logins to list. Omit to derive from email."),
27627
- email: import_zod31.z.string().optional().describe("Account email used to derive the profile name when profile is not given."),
27628
- domain: import_zod31.z.string().optional().describe("Restrict to one site login, e.g. chatgpt.com. Use this to poll a single login until its status reads AUTHENTICATED."),
27629
- connection_id: import_zod31.z.string().optional().describe("A specific login connection id returned by browser_profile_connect, to poll just that one.")
27958
+ profile: import_zod32.z.string().optional().describe("Profile whose saved logins to list. Omit to derive from email."),
27959
+ email: import_zod32.z.string().optional().describe("Account email used to derive the profile name when profile is not given."),
27960
+ domain: import_zod32.z.string().optional().describe("Restrict to one site login, e.g. chatgpt.com. Use this to poll a single login until its status reads AUTHENTICATED."),
27961
+ connection_id: import_zod32.z.string().optional().describe("A specific login connection id returned by browser_profile_connect, to poll just that one.")
27630
27962
  };
27631
27963
  BrowserSessionInputSchema = {
27632
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself.")
27964
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself.")
27633
27965
  };
27634
- BrowserLocateTargetSchema = import_zod31.z.object({
27635
- name: import_zod31.z.string().optional().describe("Optional label for this target, echoed in the result."),
27636
- selector: import_zod31.z.string().optional().describe('CSS selector for the exact DOM element to locate, for example h1, input[name="q"], or [data-testid="result"].'),
27637
- text: import_zod31.z.string().optional().describe("Visible text to locate when a selector is not known. The tool returns the text range bounds when possible."),
27638
- match: import_zod31.z.enum(["contains", "exact"]).default("contains").describe("How to match text targets. Defaults to contains."),
27639
- index: import_zod31.z.number().int().min(0).default(0).describe("Zero-based match index when multiple elements match.")
27966
+ BrowserLocateTargetSchema = import_zod32.z.object({
27967
+ name: import_zod32.z.string().optional().describe("Optional label for this target, echoed in the result."),
27968
+ selector: import_zod32.z.string().optional().describe('CSS selector for the exact DOM element to locate, for example h1, input[name="q"], or [data-testid="result"].'),
27969
+ text: import_zod32.z.string().optional().describe("Visible text to locate when a selector is not known. The tool returns the text range bounds when possible."),
27970
+ match: import_zod32.z.enum(["contains", "exact"]).default("contains").describe("How to match text targets. Defaults to contains."),
27971
+ index: import_zod32.z.number().int().min(0).default(0).describe("Zero-based match index when multiple elements match.")
27640
27972
  }).refine((value) => Boolean(value.selector || value.text), {
27641
27973
  message: "target requires selector or text"
27642
27974
  });
27643
27975
  BrowserLocateInputSchema = {
27644
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27645
- targets: import_zod31.z.array(BrowserLocateTargetSchema).min(1).max(20).describe("DOM targets to locate in the current viewport. Use selectors for exact elements, or text for visible text ranges.")
27976
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27977
+ targets: import_zod32.z.array(BrowserLocateTargetSchema).min(1).max(20).describe("DOM targets to locate in the current viewport. Use selectors for exact elements, or text for visible text ranges.")
27646
27978
  };
27647
27979
  BrowserGotoInputSchema = {
27648
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27649
- url: import_zod31.z.string().url().describe("URL to navigate the browser to.")
27980
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27981
+ url: import_zod32.z.string().url().describe("URL to navigate the browser to.")
27650
27982
  };
27651
27983
  BrowserClickInputSchema = {
27652
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27653
- x: import_zod31.z.number().describe("X coordinate to click, in screenshot pixels. Use only coordinates from the latest browser_screenshot, browser_read, or browser_locate result; do not guess."),
27654
- y: import_zod31.z.number().describe("Y coordinate to click, in screenshot pixels. Use only coordinates from the latest browser_screenshot, browser_read, or browser_locate result; do not guess."),
27655
- button: import_zod31.z.enum(["left", "right", "middle"]).default("left").describe("Mouse button."),
27656
- num_clicks: import_zod31.z.number().int().min(1).max(3).optional().describe("Number of clicks, e.g. 2 for double-click.")
27984
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27985
+ x: import_zod32.z.number().describe("X coordinate to click, in screenshot pixels. Use only coordinates from the latest browser_screenshot, browser_read, or browser_locate result; do not guess."),
27986
+ y: import_zod32.z.number().describe("Y coordinate to click, in screenshot pixels. Use only coordinates from the latest browser_screenshot, browser_read, or browser_locate result; do not guess."),
27987
+ button: import_zod32.z.enum(["left", "right", "middle"]).default("left").describe("Mouse button."),
27988
+ num_clicks: import_zod32.z.number().int().min(1).max(3).optional().describe("Number of clicks, e.g. 2 for double-click.")
27657
27989
  };
27658
27990
  BrowserTypeInputSchema = {
27659
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27660
- text: import_zod31.z.string().describe("Text to type at the current focus. Click a field first to focus it."),
27661
- delay: import_zod31.z.number().int().min(0).max(500).optional().describe("Optional per-keystroke delay in ms for human-like typing.")
27991
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27992
+ text: import_zod32.z.string().describe("Text to type at the current focus. Click a field first to focus it."),
27993
+ delay: import_zod32.z.number().int().min(0).max(500).optional().describe("Optional per-keystroke delay in ms for human-like typing.")
27662
27994
  };
27663
27995
  BrowserScrollInputSchema = {
27664
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27665
- delta_y: import_zod31.z.number().default(5).describe("Vertical scroll in wheel units. Positive scrolls down, negative up."),
27666
- delta_x: import_zod31.z.number().default(0).describe("Horizontal scroll in wheel units."),
27667
- x: import_zod31.z.number().optional().describe("X position to scroll at. Defaults to screen center."),
27668
- y: import_zod31.z.number().optional().describe("Y position to scroll at. Defaults to screen center.")
27996
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27997
+ delta_y: import_zod32.z.number().default(5).describe("Vertical scroll in wheel units. Positive scrolls down, negative up."),
27998
+ delta_x: import_zod32.z.number().default(0).describe("Horizontal scroll in wheel units."),
27999
+ x: import_zod32.z.number().optional().describe("X position to scroll at. Defaults to screen center."),
28000
+ y: import_zod32.z.number().optional().describe("Y position to scroll at. Defaults to screen center.")
27669
28001
  };
27670
28002
  BrowserPressInputSchema = {
27671
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27672
- keys: import_zod31.z.array(import_zod31.z.string()).min(1).describe('Keys or combinations to press, e.g. ["Return"], ["Ctrl+a"], ["Ctrl+Shift+Tab"].')
28003
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
28004
+ keys: import_zod32.z.array(import_zod32.z.string()).min(1).describe('Keys or combinations to press, e.g. ["Return"], ["Ctrl+a"], ["Ctrl+Shift+Tab"].')
27673
28005
  };
27674
28006
  BrowserReplayStopInputSchema = {
27675
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27676
- replay_id: import_zod31.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself.")
28007
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
28008
+ replay_id: import_zod32.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself.")
27677
28009
  };
27678
28010
  BrowserReplayDownloadInputSchema = {
27679
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27680
- replay_id: import_zod31.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself."),
27681
- filename: import_zod31.z.string().optional().describe("Optional local MP4 filename. Defaults to a timestamped replay filename.")
28011
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
28012
+ replay_id: import_zod32.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself."),
28013
+ filename: import_zod32.z.string().optional().describe("Optional local MP4 filename. Defaults to a timestamped replay filename.")
27682
28014
  };
27683
- BrowserReplayAnnotationSchema = import_zod31.z.object({
27684
- type: import_zod31.z.enum(["box", "circle", "underline", "arrow", "label"]).default("box").describe("Annotation style to draw over the replay."),
27685
- start_seconds: import_zod31.z.number().min(0).default(0).describe("When the annotation should appear in the replay."),
27686
- end_seconds: import_zod31.z.number().min(0).optional().describe("When the annotation should disappear. Defaults to two seconds after start_seconds."),
27687
- left: import_zod31.z.number().optional().describe("Target left edge in browser screenshot pixels. Use element.left from browser_screenshot/browser_read."),
27688
- top: import_zod31.z.number().optional().describe("Target top edge in browser screenshot pixels. Use element.top from browser_screenshot/browser_read."),
27689
- width: import_zod31.z.number().positive().optional().describe("Target width in browser screenshot pixels. Use element.width from browser_screenshot/browser_read."),
27690
- height: import_zod31.z.number().positive().optional().describe("Target height in browser screenshot pixels. Use element.height from browser_screenshot/browser_read."),
27691
- x: import_zod31.z.number().optional().describe("Point target x coordinate in browser screenshot pixels when no box is available."),
27692
- y: import_zod31.z.number().optional().describe("Point target y coordinate in browser screenshot pixels when no box is available."),
27693
- from_x: import_zod31.z.number().optional().describe("Arrow start x coordinate in browser screenshot pixels. Defaults near the target."),
27694
- from_y: import_zod31.z.number().optional().describe("Arrow start y coordinate in browser screenshot pixels. Defaults near the target."),
27695
- to_x: import_zod31.z.number().optional().describe("Arrow target x coordinate in browser screenshot pixels. Defaults to the target box center."),
27696
- to_y: import_zod31.z.number().optional().describe("Arrow target y coordinate in browser screenshot pixels. Defaults to the target box center."),
27697
- label: import_zod31.z.string().max(120).optional().describe("Optional text callout to render near the annotation."),
27698
- color: import_zod31.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("Annotation color as hex, for example #ff3b30."),
27699
- thickness: import_zod31.z.number().min(1).max(24).optional().describe("Stroke thickness in pixels. Defaults to 5.")
28015
+ BrowserReplayAnnotationSchema = import_zod32.z.object({
28016
+ type: import_zod32.z.enum(["box", "circle", "underline", "arrow", "label"]).default("box").describe("Annotation style to draw over the replay."),
28017
+ start_seconds: import_zod32.z.number().min(0).default(0).describe("When the annotation should appear in the replay."),
28018
+ end_seconds: import_zod32.z.number().min(0).optional().describe("When the annotation should disappear. Defaults to two seconds after start_seconds."),
28019
+ left: import_zod32.z.number().optional().describe("Target left edge in browser screenshot pixels. Use element.left from browser_screenshot/browser_read."),
28020
+ top: import_zod32.z.number().optional().describe("Target top edge in browser screenshot pixels. Use element.top from browser_screenshot/browser_read."),
28021
+ width: import_zod32.z.number().positive().optional().describe("Target width in browser screenshot pixels. Use element.width from browser_screenshot/browser_read."),
28022
+ height: import_zod32.z.number().positive().optional().describe("Target height in browser screenshot pixels. Use element.height from browser_screenshot/browser_read."),
28023
+ x: import_zod32.z.number().optional().describe("Point target x coordinate in browser screenshot pixels when no box is available."),
28024
+ y: import_zod32.z.number().optional().describe("Point target y coordinate in browser screenshot pixels when no box is available."),
28025
+ from_x: import_zod32.z.number().optional().describe("Arrow start x coordinate in browser screenshot pixels. Defaults near the target."),
28026
+ from_y: import_zod32.z.number().optional().describe("Arrow start y coordinate in browser screenshot pixels. Defaults near the target."),
28027
+ to_x: import_zod32.z.number().optional().describe("Arrow target x coordinate in browser screenshot pixels. Defaults to the target box center."),
28028
+ to_y: import_zod32.z.number().optional().describe("Arrow target y coordinate in browser screenshot pixels. Defaults to the target box center."),
28029
+ label: import_zod32.z.string().max(120).optional().describe("Optional text callout to render near the annotation."),
28030
+ color: import_zod32.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("Annotation color as hex, for example #ff3b30."),
28031
+ thickness: import_zod32.z.number().min(1).max(24).optional().describe("Stroke thickness in pixels. Defaults to 5.")
27700
28032
  });
27701
28033
  BrowserReplayMarkInputSchema = {
27702
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself. A replay must already be recording."),
28034
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself. A replay must already be recording."),
27703
28035
  target: BrowserLocateTargetSchema.describe("The exact DOM element or text range to mark in the current viewport."),
27704
- type: import_zod31.z.enum(["box", "circle", "underline", "arrow"]).default("box").describe("Annotation style to generate. Labels are included on the returned annotation when label is provided."),
27705
- label: import_zod31.z.string().max(120).optional().describe("Optional callout text to render near the target."),
27706
- color: import_zod31.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("Annotation color as hex, for example #ff3b30."),
27707
- thickness: import_zod31.z.number().min(1).max(24).optional().describe("Stroke thickness in pixels. Defaults to 5."),
27708
- padding: import_zod31.z.number().min(0).max(80).default(8).describe("Pixels to expand the DOM bounds so the highlight does not touch the text edge."),
27709
- start_offset_seconds: import_zod31.z.number().min(-5).max(10).default(-0.25).describe("Offset from the current replay time. Negative values make the callout appear just before the mark action is captured."),
27710
- duration_seconds: import_zod31.z.number().min(0.5).max(30).default(4).describe("How long the generated annotation should remain visible.")
28036
+ type: import_zod32.z.enum(["box", "circle", "underline", "arrow"]).default("box").describe("Annotation style to generate. Labels are included on the returned annotation when label is provided."),
28037
+ label: import_zod32.z.string().max(120).optional().describe("Optional callout text to render near the target."),
28038
+ color: import_zod32.z.string().regex(/^#?[0-9a-fA-F]{6}$/).optional().describe("Annotation color as hex, for example #ff3b30."),
28039
+ thickness: import_zod32.z.number().min(1).max(24).optional().describe("Stroke thickness in pixels. Defaults to 5."),
28040
+ padding: import_zod32.z.number().min(0).max(80).default(8).describe("Pixels to expand the DOM bounds so the highlight does not touch the text edge."),
28041
+ start_offset_seconds: import_zod32.z.number().min(-5).max(10).default(-0.25).describe("Offset from the current replay time. Negative values make the callout appear just before the mark action is captured."),
28042
+ duration_seconds: import_zod32.z.number().min(0.5).max(30).default(4).describe("How long the generated annotation should remain visible.")
27711
28043
  };
27712
28044
  BrowserReplayAnnotateInputSchema = {
27713
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
27714
- replay_id: import_zod31.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself."),
27715
- annotations: import_zod31.z.array(BrowserReplayAnnotationSchema).min(1).max(50).describe("Timed overlay annotations to render on the replay. Prefer annotations returned by browser_replay_mark; otherwise use exact DOM bounds from browser_locate/browser_screenshot/browser_read."),
27716
- filename: import_zod31.z.string().optional().describe("Optional output MP4 filename. Defaults to a timestamped annotated replay filename."),
27717
- source_width: import_zod31.z.number().positive().optional().describe("Width of the screenshot coordinate space used for annotations. Defaults to the replay video width."),
27718
- source_height: import_zod31.z.number().positive().optional().describe("Height of the coordinate space used for annotations. When this is a page viewport height smaller than the replay video height, the annotator infers the browser chrome top offset."),
27719
- source_left_offset: import_zod31.z.number().min(0).optional().describe("Optional explicit X offset from annotation coordinates to replay video coordinates. Usually omitted."),
27720
- source_top_offset: import_zod31.z.number().min(0).optional().describe("Optional explicit Y offset from annotation coordinates to replay video coordinates. Usually omitted because browser chrome offset is inferred when source_height is a page viewport height.")
28045
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself."),
28046
+ replay_id: import_zod32.z.string().describe("The replay id returned by browser_replay_start or browser_list_replays. Use only a returned replay_id; do not construct one yourself."),
28047
+ annotations: import_zod32.z.array(BrowserReplayAnnotationSchema).min(1).max(50).describe("Timed overlay annotations to render on the replay. Prefer annotations returned by browser_replay_mark; otherwise use exact DOM bounds from browser_locate/browser_screenshot/browser_read."),
28048
+ filename: import_zod32.z.string().optional().describe("Optional output MP4 filename. Defaults to a timestamped annotated replay filename."),
28049
+ source_width: import_zod32.z.number().positive().optional().describe("Width of the screenshot coordinate space used for annotations. Defaults to the replay video width."),
28050
+ source_height: import_zod32.z.number().positive().optional().describe("Height of the coordinate space used for annotations. When this is a page viewport height smaller than the replay video height, the annotator infers the browser chrome top offset."),
28051
+ source_left_offset: import_zod32.z.number().min(0).optional().describe("Optional explicit X offset from annotation coordinates to replay video coordinates. Usually omitted."),
28052
+ source_top_offset: import_zod32.z.number().min(0).optional().describe("Optional explicit Y offset from annotation coordinates to replay video coordinates. Usually omitted because browser chrome offset is inferred when source_height is a page viewport height.")
27721
28053
  };
27722
28054
  BrowserListInputSchema = {
27723
- include_closed: import_zod31.z.boolean().default(false).describe("Include closed sessions in the list.")
28055
+ include_closed: import_zod32.z.boolean().default(false).describe("Include closed sessions in the list.")
27724
28056
  };
27725
28057
  BrowserCaptureFanoutInputSchema = {
27726
- session_id: import_zod31.z.string().describe("The session id returned by browser_open or browser_list_sessions. The session must be on chatgpt.com or claude.ai and logged in through a saved hosted profile. Use only a returned session_id; do not construct one yourself."),
27727
- prompt: import_zod31.z.string().optional().describe("Optional prompt to type into the chat composer and submit before capturing. Omit to passively capture the fan-out of a prompt the user just ran in the visible browser. The prompt must trigger web search for there to be a fan-out."),
27728
- wait_ms: import_zod31.z.number().int().min(0).max(18e4).optional().describe("How long to wait for the answer stream to finish before parsing. Defaults to 90000 when a prompt is sent, 8000 for passive capture. Capture ends as soon as the answer stream finishes."),
27729
- first_party_domain: import_zod31.z.string().optional().describe("The brand/site being researched, for example example.com. Sources on this domain are tagged First-party/vendor. Set this when the prompt is about a specific business."),
27730
- reset: import_zod31.z.boolean().default(false).describe("Clear any previously buffered stream for this page before capturing. Use when re-running to avoid mixing turns."),
27731
- export: import_zod31.z.boolean().default(false).describe("When true, write JSON, CSV, TSV exports (queries, citations, all sources, browsed-only sources, snippets, domains) and a self-contained HTML report to MCP_SCRAPER_OUTPUT_DIR/fanout, returning paths relative to MCP_SCRAPER_OUTPUT_DIR.")
28058
+ session_id: import_zod32.z.string().describe("The session id returned by browser_open or browser_list_sessions. The session must be on chatgpt.com or claude.ai and logged in through a saved hosted profile. Use only a returned session_id; do not construct one yourself."),
28059
+ prompt: import_zod32.z.string().optional().describe("Optional prompt to type into the chat composer and submit before capturing. Omit to passively capture the fan-out of a prompt the user just ran in the visible browser. The prompt must trigger web search for there to be a fan-out."),
28060
+ wait_ms: import_zod32.z.number().int().min(0).max(18e4).optional().describe("How long to wait for the answer stream to finish before parsing. Defaults to 90000 when a prompt is sent, 8000 for passive capture. Capture ends as soon as the answer stream finishes."),
28061
+ first_party_domain: import_zod32.z.string().optional().describe("The brand/site being researched, for example example.com. Sources on this domain are tagged First-party/vendor. Set this when the prompt is about a specific business."),
28062
+ reset: import_zod32.z.boolean().default(false).describe("Clear any previously buffered stream for this page before capturing. Use when re-running to avoid mixing turns."),
28063
+ export: import_zod32.z.boolean().default(false).describe("When true, write JSON, CSV, TSV exports (queries, citations, all sources, browsed-only sources, snippets, domains) and a self-contained HTML report to MCP_SCRAPER_OUTPUT_DIR/fanout, returning paths relative to MCP_SCRAPER_OUTPUT_DIR.")
27732
28064
  };
27733
- FanoutSourceOutput = import_zod31.z.object({
27734
- url: import_zod31.z.string(),
27735
- domain: import_zod31.z.string(),
27736
- title: import_zod31.z.string(),
27737
- cited: import_zod31.z.boolean(),
27738
- timesCited: import_zod31.z.number().int().min(0),
27739
- snippet: import_zod31.z.string(),
27740
- round: import_zod31.z.number().int().nullable(),
27741
- siteType: import_zod31.z.string().describe("URL category: First-party/vendor, News/media, Reddit, Social/video, Encyclopedia, Review site, Docs, or Blog.")
28065
+ FanoutSourceOutput = import_zod32.z.object({
28066
+ url: import_zod32.z.string(),
28067
+ domain: import_zod32.z.string(),
28068
+ title: import_zod32.z.string(),
28069
+ cited: import_zod32.z.boolean(),
28070
+ timesCited: import_zod32.z.number().int().min(0),
28071
+ snippet: import_zod32.z.string(),
28072
+ round: import_zod32.z.number().int().nullable(),
28073
+ siteType: import_zod32.z.string().describe("URL category: First-party/vendor, News/media, Reddit, Social/video, Encyclopedia, Review site, Docs, or Blog.")
27742
28074
  });
27743
28075
  BrowserCaptureFanoutOutputSchema = {
27744
28076
  ...BrowserBaseOutput,
27745
- tool: import_zod31.z.literal("query_fanout_workflow"),
27746
- platform: import_zod31.z.enum(["ChatGPT", "Claude"]).describe("Which AI-search surface the fan-out was captured from."),
27747
- captured_at: import_zod31.z.string(),
27748
- prompt: import_zod31.z.string().describe("The user prompt that triggered the captured fan-out, when recoverable."),
27749
- meta: import_zod31.z.object({
27750
- model: import_zod31.z.string(),
27751
- finishType: import_zod31.z.string(),
27752
- title: import_zod31.z.string(),
27753
- rounds: import_zod31.z.number().int().min(0)
28077
+ tool: import_zod32.z.literal("query_fanout_workflow"),
28078
+ platform: import_zod32.z.enum(["ChatGPT", "Claude"]).describe("Which AI-search surface the fan-out was captured from."),
28079
+ captured_at: import_zod32.z.string(),
28080
+ prompt: import_zod32.z.string().describe("The user prompt that triggered the captured fan-out, when recoverable."),
28081
+ meta: import_zod32.z.object({
28082
+ model: import_zod32.z.string(),
28083
+ finishType: import_zod32.z.string(),
28084
+ title: import_zod32.z.string(),
28085
+ rounds: import_zod32.z.number().int().min(0)
27754
28086
  }),
27755
- queries: import_zod31.z.array(import_zod31.z.string()).describe("Every web-search sub-query the model issued, in capture order. Classify these by funnel stage and type yourself from the text."),
27756
- browsed_urls: import_zod31.z.array(FanoutSourceOutput).describe("Every researched URL (cited and browsed-only), cited first."),
27757
- cited_urls: import_zod31.z.array(FanoutSourceOutput).describe("The subset of researched URLs actually cited in the final answer."),
27758
- browsed_only: import_zod31.z.array(FanoutSourceOutput).describe("Researched URLs the model pulled but did not cite."),
27759
- snippets: import_zod31.z.array(import_zod31.z.object({ url: import_zod31.z.string(), domain: import_zod31.z.string(), title: import_zod31.z.string(), text: import_zod31.z.string() })),
27760
- counts: import_zod31.z.object({
27761
- subQueries: import_zod31.z.number().int().min(0),
27762
- browsed: import_zod31.z.number().int().min(0),
27763
- cited: import_zod31.z.number().int().min(0),
27764
- browsedOnly: import_zod31.z.number().int().min(0)
28087
+ queries: import_zod32.z.array(import_zod32.z.string()).describe("Every web-search sub-query the model issued, in capture order. Classify these by funnel stage and type yourself from the text."),
28088
+ browsed_urls: import_zod32.z.array(FanoutSourceOutput).describe("Every researched URL (cited and browsed-only), cited first."),
28089
+ cited_urls: import_zod32.z.array(FanoutSourceOutput).describe("The subset of researched URLs actually cited in the final answer."),
28090
+ browsed_only: import_zod32.z.array(FanoutSourceOutput).describe("Researched URLs the model pulled but did not cite."),
28091
+ snippets: import_zod32.z.array(import_zod32.z.object({ url: import_zod32.z.string(), domain: import_zod32.z.string(), title: import_zod32.z.string(), text: import_zod32.z.string() })),
28092
+ counts: import_zod32.z.object({
28093
+ subQueries: import_zod32.z.number().int().min(0),
28094
+ browsed: import_zod32.z.number().int().min(0),
28095
+ cited: import_zod32.z.number().int().min(0),
28096
+ browsedOnly: import_zod32.z.number().int().min(0)
27765
28097
  }),
27766
- aggregates: import_zod31.z.object({
27767
- topSites: import_zod31.z.array(import_zod31.z.object({ domain: import_zod31.z.string(), count: import_zod31.z.number().int(), cited: import_zod31.z.boolean(), timesCited: import_zod31.z.number().int(), siteType: import_zod31.z.string() })),
27768
- citationOrder: import_zod31.z.array(import_zod31.z.object({ rank: import_zod31.z.number().int(), domain: import_zod31.z.string(), url: import_zod31.z.string(), timesCited: import_zod31.z.number().int() })),
27769
- byCategory: import_zod31.z.record(import_zod31.z.number().int())
28098
+ aggregates: import_zod32.z.object({
28099
+ topSites: import_zod32.z.array(import_zod32.z.object({ domain: import_zod32.z.string(), count: import_zod32.z.number().int(), cited: import_zod32.z.boolean(), timesCited: import_zod32.z.number().int(), siteType: import_zod32.z.string() })),
28100
+ citationOrder: import_zod32.z.array(import_zod32.z.object({ rank: import_zod32.z.number().int(), domain: import_zod32.z.string(), url: import_zod32.z.string(), timesCited: import_zod32.z.number().int() })),
28101
+ byCategory: import_zod32.z.record(import_zod32.z.number().int())
27770
28102
  }).describe("Objective aggregates: top sourced sites by frequency, citation order, and URL-category counts."),
27771
- first_party_domain: import_zod31.z.string().nullable(),
27772
- exports: import_zod31.z.object({
27773
- relativeTo: import_zod31.z.string(),
27774
- dir: import_zod31.z.string(),
27775
- json: import_zod31.z.string(),
27776
- queriesCsv: import_zod31.z.string(),
27777
- queriesTsv: import_zod31.z.string(),
27778
- citationsCsv: import_zod31.z.string(),
27779
- sourcesCsv: import_zod31.z.string(),
27780
- browsedOnlyCsv: import_zod31.z.string(),
27781
- snippetsCsv: import_zod31.z.string(),
27782
- domainsCsv: import_zod31.z.string(),
27783
- report: import_zod31.z.string()
28103
+ first_party_domain: import_zod32.z.string().nullable(),
28104
+ exports: import_zod32.z.object({
28105
+ relativeTo: import_zod32.z.string(),
28106
+ dir: import_zod32.z.string(),
28107
+ json: import_zod32.z.string(),
28108
+ queriesCsv: import_zod32.z.string(),
28109
+ queriesTsv: import_zod32.z.string(),
28110
+ citationsCsv: import_zod32.z.string(),
28111
+ sourcesCsv: import_zod32.z.string(),
28112
+ browsedOnlyCsv: import_zod32.z.string(),
28113
+ snippetsCsv: import_zod32.z.string(),
28114
+ domainsCsv: import_zod32.z.string(),
28115
+ report: import_zod32.z.string()
27784
28116
  }).nullable().describe("Relative export paths when export=true, otherwise null. Paths are relative to MCP_SCRAPER_OUTPUT_DIR, or ~/Downloads/mcp-scraper when that env var is not set."),
27785
- debug: import_zod31.z.object({
27786
- interceptorReady: import_zod31.z.boolean(),
27787
- rawBytes: import_zod31.z.number().int().min(0),
27788
- unmappedKeys: import_zod31.z.array(import_zod31.z.string()),
27789
- note: import_zod31.z.string()
28117
+ debug: import_zod32.z.object({
28118
+ interceptorReady: import_zod32.z.boolean(),
28119
+ rawBytes: import_zod32.z.number().int().min(0),
28120
+ unmappedKeys: import_zod32.z.array(import_zod32.z.string()),
28121
+ note: import_zod32.z.string()
27790
28122
  }).optional()
27791
28123
  };
27792
28124
  BrowserOpenOutputSchema = {
27793
- ok: import_zod31.z.boolean(),
27794
- tool: import_zod31.z.literal("browser_open"),
27795
- session_id: import_zod31.z.string().describe("Session id returned by browser_open. Use only this exact value in later browser_* calls; do not construct one yourself."),
27796
- watch_url: import_zod31.z.string().describe("Human watch/takeover URL for this browser session on mcpscraper.dev."),
28125
+ ok: import_zod32.z.boolean(),
28126
+ tool: import_zod32.z.literal("browser_open"),
28127
+ session_id: import_zod32.z.string().describe("Session id returned by browser_open. Use only this exact value in later browser_* calls; do not construct one yourself."),
28128
+ watch_url: import_zod32.z.string().describe("Human watch/takeover URL for this browser session on mcpscraper.dev."),
27797
28129
  live_view_url: NullableString2.describe("Deprecated; always null. Open watch_url to view the live session."),
27798
28130
  url: NullableString2.describe("Initial URL requested by the caller, when provided."),
27799
- hint: import_zod31.z.string(),
28131
+ hint: import_zod32.z.string(),
27800
28132
  raw: BrowserRawObject.optional()
27801
28133
  };
27802
- BrowserProfileLogin = import_zod31.z.object({
28134
+ BrowserProfileLogin = import_zod32.z.object({
27803
28135
  connection_id: NullableString2.describe("Auth connection id for this login."),
27804
- domain: import_zod31.z.string().describe("Site this login is for, e.g. chatgpt.com."),
27805
- status: import_zod31.z.string().describe("Auth status, e.g. NEEDS_AUTH or AUTHENTICATED."),
28136
+ domain: import_zod32.z.string().describe("Site this login is for, e.g. chatgpt.com."),
28137
+ status: import_zod32.z.string().describe("Auth status, e.g. NEEDS_AUTH or AUTHENTICATED."),
27806
28138
  account_email: NullableString2.describe("Account email recorded for this login, when known."),
27807
28139
  note: NullableString2.describe("Free-text note describing this login."),
27808
28140
  watch_url: NullableString2.describe("mcpscraper.dev sign-in link when this login still needs the user to authenticate."),
27809
28141
  last_connected_at: NullableString2.describe("When this login was last saved or refreshed.")
27810
28142
  });
27811
28143
  BrowserProfileConnectOutputSchema = {
27812
- ok: import_zod31.z.boolean(),
27813
- tool: import_zod31.z.literal("browser_profile_connect"),
28144
+ ok: import_zod32.z.boolean(),
28145
+ tool: import_zod32.z.literal("browser_profile_connect"),
27814
28146
  session_id: NullableString2,
27815
- auth_connection_id: import_zod31.z.string(),
27816
- watch_url: import_zod31.z.string().describe("mcpscraper.dev sign-in link to give the user so they can complete this login."),
28147
+ auth_connection_id: import_zod32.z.string(),
28148
+ watch_url: import_zod32.z.string().describe("mcpscraper.dev sign-in link to give the user so they can complete this login."),
27817
28149
  live_view_url: NullableString2.describe("Deprecated; always null. Open watch_url to view the sign-in."),
27818
- profile: import_zod31.z.string().describe("Profile this login was added to. Reuse it to stack more logins or to open a session."),
27819
- domain: import_zod31.z.string(),
27820
- setup_url: import_zod31.z.string(),
28150
+ profile: import_zod32.z.string().describe("Profile this login was added to. Reuse it to stack more logins or to open a session."),
28151
+ domain: import_zod32.z.string(),
28152
+ setup_url: import_zod32.z.string(),
27821
28153
  account_email: NullableString2,
27822
28154
  note: NullableString2,
27823
- status: import_zod31.z.string(),
28155
+ status: import_zod32.z.string(),
27824
28156
  flow_status: NullableString2,
27825
28157
  flow_step: NullableString2,
27826
28158
  flow_expires_at: NullableString2,
27827
28159
  post_login_url: NullableString2,
27828
- connected_logins: import_zod31.z.array(BrowserProfileLogin).describe("Every login currently saved in this profile, so you can see what else is connected."),
27829
- next_steps: import_zod31.z.array(import_zod31.z.string()),
28160
+ connected_logins: import_zod32.z.array(BrowserProfileLogin).describe("Every login currently saved in this profile, so you can see what else is connected."),
28161
+ next_steps: import_zod32.z.array(import_zod32.z.string()),
27830
28162
  raw: BrowserRawObject.optional()
27831
28163
  };
27832
28164
  BrowserProfileListOutputSchema = {
27833
- ok: import_zod31.z.boolean(),
27834
- tool: import_zod31.z.literal("browser_profile_list"),
27835
- session_id: import_zod31.z.null(),
27836
- profile: import_zod31.z.string().describe("Profile these logins belong to."),
27837
- connections: import_zod31.z.array(BrowserProfileLogin).describe("All site logins saved in this profile, each with its current auth status and note."),
27838
- count: import_zod31.z.number().int().min(0)
28165
+ ok: import_zod32.z.boolean(),
28166
+ tool: import_zod32.z.literal("browser_profile_list"),
28167
+ session_id: import_zod32.z.null(),
28168
+ profile: import_zod32.z.string().describe("Profile these logins belong to."),
28169
+ connections: import_zod32.z.array(BrowserProfileLogin).describe("All site logins saved in this profile, each with its current auth status and note."),
28170
+ count: import_zod32.z.number().int().min(0)
27839
28171
  };
27840
28172
  BrowserScreenshotOutputSchema = {
27841
28173
  ...BrowserBaseOutput,
27842
- tool: import_zod31.z.literal("browser_screenshot"),
28174
+ tool: import_zod32.z.literal("browser_screenshot"),
27843
28175
  url: NullableString2,
27844
28176
  title: NullableString2,
27845
- text: import_zod31.z.string(),
27846
- elements: import_zod31.z.array(BrowserElementOutput),
27847
- screenshot: import_zod31.z.object({
27848
- mime_type: import_zod31.z.string(),
27849
- inline: import_zod31.z.boolean()
28177
+ text: import_zod32.z.string(),
28178
+ elements: import_zod32.z.array(BrowserElementOutput),
28179
+ screenshot: import_zod32.z.object({
28180
+ mime_type: import_zod32.z.string(),
28181
+ inline: import_zod32.z.boolean()
27850
28182
  }).nullable()
27851
28183
  };
27852
28184
  BrowserReadOutputSchema = {
27853
28185
  ...BrowserBaseOutput,
27854
- tool: import_zod31.z.literal("browser_read"),
28186
+ tool: import_zod32.z.literal("browser_read"),
27855
28187
  url: NullableString2,
27856
28188
  title: NullableString2,
27857
- text: import_zod31.z.string(),
27858
- elements: import_zod31.z.array(BrowserElementOutput),
28189
+ text: import_zod32.z.string(),
28190
+ elements: import_zod32.z.array(BrowserElementOutput),
27859
28191
  raw: BrowserRawObject.optional()
27860
28192
  };
27861
28193
  BrowserLocateOutputSchema = {
27862
28194
  ...BrowserBaseOutput,
27863
- tool: import_zod31.z.literal("browser_locate"),
28195
+ tool: import_zod32.z.literal("browser_locate"),
27864
28196
  url: NullableString2,
27865
28197
  title: NullableString2,
27866
28198
  viewport: BrowserRawObject.nullable(),
27867
28199
  replay: BrowserRawObject.nullable(),
27868
- targets: import_zod31.z.array(BrowserRawObject),
28200
+ targets: import_zod32.z.array(BrowserRawObject),
27869
28201
  raw: BrowserRawObject.optional()
27870
28202
  };
27871
28203
  BrowserActionOutputSchema = {
27872
28204
  ...BrowserBaseOutput,
27873
28205
  result: BrowserRawObject.describe("Provider action result. Check ok and follow with browser_screenshot/browser_read when page state matters."),
27874
- nextRecommendedTool: import_zod31.z.string().nullable()
28206
+ nextRecommendedTool: import_zod32.z.string().nullable()
27875
28207
  };
27876
28208
  BrowserReplayStartOutputSchema = {
27877
28209
  ...BrowserReplayBaseOutput,
27878
- tool: import_zod31.z.literal("browser_replay_start"),
28210
+ tool: import_zod32.z.literal("browser_replay_start"),
27879
28211
  view_url: NullableString2,
27880
28212
  download_url: NullableString2,
27881
28213
  raw: BrowserRawObject.optional()
27882
28214
  };
27883
28215
  BrowserReplayStopOutputSchema = {
27884
28216
  ...BrowserReplayBaseOutput,
27885
- tool: import_zod31.z.literal("browser_replay_stop"),
28217
+ tool: import_zod32.z.literal("browser_replay_stop"),
27886
28218
  view_url: NullableString2,
27887
28219
  download_url: NullableString2,
27888
28220
  raw: BrowserRawObject.optional()
27889
28221
  };
27890
28222
  BrowserListReplaysOutputSchema = {
27891
28223
  ...BrowserBaseOutput,
27892
- tool: import_zod31.z.literal("browser_list_replays"),
27893
- replays: import_zod31.z.array(BrowserRawObject),
27894
- count: import_zod31.z.number().int().min(0)
28224
+ tool: import_zod32.z.literal("browser_list_replays"),
28225
+ replays: import_zod32.z.array(BrowserRawObject),
28226
+ count: import_zod32.z.number().int().min(0)
27895
28227
  };
27896
28228
  BrowserReplayDownloadOutputSchema = {
27897
28229
  ...BrowserReplayBaseOutput,
27898
- tool: import_zod31.z.literal("browser_replay_download"),
28230
+ tool: import_zod32.z.literal("browser_replay_download"),
27899
28231
  file_path: NullableString2,
27900
- bytes: import_zod31.z.number().int().min(0).nullable(),
28232
+ bytes: import_zod32.z.number().int().min(0).nullable(),
27901
28233
  mime_type: NullableString2,
27902
28234
  download_url: NullableString2
27903
28235
  };
27904
28236
  BrowserReplayMarkOutputSchema = {
27905
28237
  ...BrowserReplayBaseOutput,
27906
- tool: import_zod31.z.literal("browser_replay_mark"),
28238
+ tool: import_zod32.z.literal("browser_replay_mark"),
27907
28239
  annotation: BrowserRawObject,
27908
- source_width: import_zod31.z.number().nullable(),
27909
- source_height: import_zod31.z.number().nullable(),
28240
+ source_width: import_zod32.z.number().nullable(),
28241
+ source_height: import_zod32.z.number().nullable(),
27910
28242
  target: BrowserRawObject.nullable(),
27911
- hint: import_zod31.z.string()
28243
+ hint: import_zod32.z.string()
27912
28244
  };
27913
28245
  BrowserReplayAnnotateOutputSchema = {
27914
28246
  ...BrowserReplayBaseOutput,
27915
- tool: import_zod31.z.literal("browser_replay_annotate"),
28247
+ tool: import_zod32.z.literal("browser_replay_annotate"),
27916
28248
  source_file_path: NullableString2,
27917
28249
  annotated_file_path: NullableString2,
27918
- bytes: import_zod31.z.number().int().min(0).nullable(),
27919
- width: import_zod31.z.number().int().min(0).nullable(),
27920
- height: import_zod31.z.number().int().min(0).nullable(),
27921
- annotation_count: import_zod31.z.number().int().min(0).nullable(),
28250
+ bytes: import_zod32.z.number().int().min(0).nullable(),
28251
+ width: import_zod32.z.number().int().min(0).nullable(),
28252
+ height: import_zod32.z.number().int().min(0).nullable(),
28253
+ annotation_count: import_zod32.z.number().int().min(0).nullable(),
27922
28254
  mime_type: NullableString2
27923
28255
  };
27924
28256
  BrowserCloseOutputSchema = {
27925
28257
  ...BrowserBaseOutput,
27926
- tool: import_zod31.z.literal("browser_close"),
27927
- closed: import_zod31.z.boolean(),
28258
+ tool: import_zod32.z.literal("browser_close"),
28259
+ closed: import_zod32.z.boolean(),
27928
28260
  raw: BrowserRawObject.optional()
27929
28261
  };
27930
28262
  BrowserListSessionsOutputSchema = {
27931
- ok: import_zod31.z.boolean(),
27932
- tool: import_zod31.z.literal("browser_list_sessions"),
27933
- session_id: import_zod31.z.null(),
27934
- sessions: import_zod31.z.array(BrowserRawObject),
27935
- count: import_zod31.z.number().int().min(0)
28263
+ ok: import_zod32.z.boolean(),
28264
+ tool: import_zod32.z.literal("browser_list_sessions"),
28265
+ session_id: import_zod32.z.null(),
28266
+ sessions: import_zod32.z.array(BrowserRawObject),
28267
+ count: import_zod32.z.number().int().min(0)
27936
28268
  };
27937
28269
  }
27938
28270
  });
@@ -29036,11 +29368,11 @@ async function requireMcpCallerKey(c) {
29036
29368
  if (!user) return mcpAuthError();
29037
29369
  return callerKey;
29038
29370
  }
29039
- var import_hono12, import_webStandardStreamableHttp, mcpApp;
29371
+ var import_hono14, import_webStandardStreamableHttp, mcpApp;
29040
29372
  var init_mcp_routes = __esm({
29041
29373
  "src/mcp/mcp-routes.ts"() {
29042
29374
  "use strict";
29043
- import_hono12 = require("hono");
29375
+ import_hono14 = require("hono");
29044
29376
  import_webStandardStreamableHttp = require("@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js");
29045
29377
  init_paa_mcp_server();
29046
29378
  init_http_mcp_tool_executor();
@@ -29049,7 +29381,7 @@ var init_mcp_routes = __esm({
29049
29381
  init_db();
29050
29382
  init_mcp_oauth();
29051
29383
  configureReportSaving(false);
29052
- mcpApp = new import_hono12.Hono();
29384
+ mcpApp = new import_hono14.Hono();
29053
29385
  mcpApp.all("/", async (c) => {
29054
29386
  try {
29055
29387
  const keyOrError = await requireMcpCallerKey(c);
@@ -29185,7 +29517,7 @@ async function listAuthConnectionsByProfile(profile) {
29185
29517
  }
29186
29518
  async function createSessionRow(input) {
29187
29519
  const db = getDb();
29188
- const id = `bas_${(0, import_node_crypto7.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
29520
+ const id = `bas_${(0, import_node_crypto9.randomUUID)().replace(/-/g, "").slice(0, 20)}`;
29189
29521
  await db.execute({
29190
29522
  sql: `INSERT INTO browser_agent_sessions (id, runtime_session_id, live_view_url, cdp_ws_url, status, label, user_id, concurrency_lock_id, last_action_at)
29191
29523
  VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
@@ -29254,7 +29586,7 @@ async function recordAction(input) {
29254
29586
  sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
29255
29587
  VALUES (?, ?, ?, ?, ?, ?)`,
29256
29588
  args: [
29257
- `baa_${(0, import_node_crypto7.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
29589
+ `baa_${(0, import_node_crypto9.randomUUID)().replace(/-/g, "").slice(0, 20)}`,
29258
29590
  input.sessionId,
29259
29591
  input.type,
29260
29592
  input.params == null ? null : JSON.stringify(input.params),
@@ -29294,11 +29626,11 @@ async function listReplayRows(sessionId) {
29294
29626
  });
29295
29627
  return res.rows;
29296
29628
  }
29297
- var import_node_crypto7, _ready2;
29629
+ var import_node_crypto9, _ready2;
29298
29630
  var init_browser_agent_db = __esm({
29299
29631
  "src/api/browser-agent-db.ts"() {
29300
29632
  "use strict";
29301
- import_node_crypto7 = require("crypto");
29633
+ import_node_crypto9 = require("crypto");
29302
29634
  init_db();
29303
29635
  _ready2 = false;
29304
29636
  }
@@ -30573,7 +30905,7 @@ async function loadOpenSession(id, userId) {
30573
30905
  return row;
30574
30906
  }
30575
30907
  function buildBrowserAgentRoutes() {
30576
- const app2 = new import_hono13.Hono();
30908
+ const app2 = new import_hono15.Hono();
30577
30909
  app2.use("*", async (c, next) => {
30578
30910
  await migrateBrowserAgent();
30579
30911
  return next();
@@ -31035,11 +31367,11 @@ function buildBrowserAgentRoutes() {
31035
31367
  });
31036
31368
  return app2;
31037
31369
  }
31038
- var import_hono13, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS;
31370
+ var import_hono15, auth, DEFAULT_BROWSER_SESSION_LOCK_TTL_SECONDS;
31039
31371
  var init_browser_agent_routes = __esm({
31040
31372
  "src/api/browser-agent-routes.ts"() {
31041
31373
  "use strict";
31042
- import_hono13 = require("hono");
31374
+ import_hono15 = require("hono");
31043
31375
  init_api_auth();
31044
31376
  init_errors();
31045
31377
  init_db();
@@ -31299,168 +31631,6 @@ var init_browser_agent_console = __esm({
31299
31631
  }
31300
31632
  });
31301
31633
 
31302
- // src/api/session.ts
31303
- function getSessionSecret() {
31304
- const configured = process.env.SESSION_SECRET?.trim();
31305
- if (configured) return configured;
31306
- if (isProduction()) throw new Error("SESSION_SECRET is not set \u2014 add it to your Vercel env vars (see src/api/env.ts)");
31307
- return "dev-secret-change-me";
31308
- }
31309
- function safeEqualHex(a, b) {
31310
- if (a.length !== b.length) return false;
31311
- try {
31312
- return (0, import_node_crypto8.timingSafeEqual)(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
31313
- } catch {
31314
- return false;
31315
- }
31316
- }
31317
- function signSession(userId) {
31318
- const payload = String(userId);
31319
- const sig = (0, import_node_crypto8.createHmac)("sha256", secret()).update(payload).digest("hex");
31320
- return `${payload}.${sig}`;
31321
- }
31322
- function verifySession(token) {
31323
- const dot = token.lastIndexOf(".");
31324
- if (dot === -1) return null;
31325
- const payload = token.slice(0, dot);
31326
- const sig = token.slice(dot + 1);
31327
- const expected = (0, import_node_crypto8.createHmac)("sha256", secret()).update(payload).digest("hex");
31328
- if (!safeEqualHex(sig, expected)) return null;
31329
- const id = parseInt(payload);
31330
- return isNaN(id) ? null : id;
31331
- }
31332
- var import_node_crypto8, isProduction, secret;
31333
- var init_session = __esm({
31334
- "src/api/session.ts"() {
31335
- "use strict";
31336
- import_node_crypto8 = require("crypto");
31337
- isProduction = () => process.env.NODE_ENV === "production" || process.env.VERCEL === "1";
31338
- secret = () => getSessionSecret();
31339
- }
31340
- });
31341
-
31342
- // src/api/memory.ts
31343
- function isMemoryOperator(email) {
31344
- if (!email) return false;
31345
- const ops = (process.env.MEMORY_OPERATOR_IDENTITIES ?? "").split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
31346
- return ops.includes(email.trim().toLowerCase());
31347
- }
31348
- function encKey() {
31349
- return (0, import_node_crypto9.scryptSync)(getSessionSecret(), "mcp-memory-key-v1", 32);
31350
- }
31351
- function encryptMemoryKey(secret2) {
31352
- const iv = (0, import_node_crypto9.randomBytes)(12);
31353
- const cipher = (0, import_node_crypto9.createCipheriv)("aes-256-gcm", encKey(), iv);
31354
- const enc = Buffer.concat([cipher.update(secret2, "utf8"), cipher.final()]);
31355
- const tag = cipher.getAuthTag();
31356
- return `${iv.toString("base64")}:${tag.toString("base64")}:${enc.toString("base64")}`;
31357
- }
31358
- function decryptMemoryKey(stored) {
31359
- try {
31360
- const [ivB, tagB, dataB] = stored.split(":");
31361
- const decipher = (0, import_node_crypto9.createDecipheriv)("aes-256-gcm", encKey(), Buffer.from(ivB, "base64"));
31362
- decipher.setAuthTag(Buffer.from(tagB, "base64"));
31363
- return Buffer.concat([decipher.update(Buffer.from(dataB, "base64")), decipher.final()]).toString("utf8");
31364
- } catch {
31365
- return null;
31366
- }
31367
- }
31368
- async function memoryCall(toolName, args, userMemoryKey) {
31369
- try {
31370
- const res = await fetch(`${MEMORY_BASE_URL()}/api/mcp/memoryServer/tools/${toolName}/execute`, {
31371
- method: "POST",
31372
- headers: { "content-type": "application/json" },
31373
- body: JSON.stringify({ data: { ...args, apiKey: userMemoryKey } })
31374
- });
31375
- const body = await res.json().catch(() => null);
31376
- if (!res.ok) return { ok: false, error: body?.error ?? `memory ${toolName} failed (${res.status})` };
31377
- if (body?.result) return body.result;
31378
- return { ok: false, error: body?.error ?? `memory ${toolName} returned no result` };
31379
- } catch (err) {
31380
- return { ok: false, error: err?.message ?? "memory call failed" };
31381
- }
31382
- }
31383
- function personalVault(user) {
31384
- return `mcp-${user.id}`;
31385
- }
31386
- function memoryIdentity(user) {
31387
- return user.email;
31388
- }
31389
- function resolveMemoryIdentity(user) {
31390
- return memoryIdentity(user);
31391
- }
31392
- function memoryPlanForReads(user) {
31393
- if (isMemoryOperator(user.email)) return "unlimited";
31394
- if (user.memory_plan === "pro" || user.memory_plan === "team") return user.memory_plan;
31395
- return "free";
31396
- }
31397
- async function provisionMemoryForUser(user) {
31398
- try {
31399
- const { key } = await getOrCreateUserMemoryKey(user);
31400
- if (key) await setMemoryProvisioned(user.id, true);
31401
- } catch {
31402
- }
31403
- }
31404
- async function getOrCreateUserMemoryKey(user) {
31405
- const creds = await getUserMemoryCreds(user.id);
31406
- if (creds.memory_key) {
31407
- const decrypted = decryptMemoryKey(creds.memory_key);
31408
- if (decrypted) return { key: decrypted };
31409
- }
31410
- const admin = ADMIN_KEY();
31411
- if (!admin) return { key: null, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
31412
- const identity = memoryIdentity(user);
31413
- const plan = isMemoryOperator(user.email) ? "unlimited" : (await getMemoryPlan(user.id)).plan;
31414
- const provisioned = await memoryCall(
31415
- "provisionDefaultsTool",
31416
- { granteeIdentity: identity, issueKey: true, plan },
31417
- admin
31418
- );
31419
- if (!provisioned.ok || !provisioned.secret) {
31420
- return { key: null, error: provisioned.error ?? "failed to provision default vaults" };
31421
- }
31422
- await setUserMemoryCreds(user.id, encryptMemoryKey(provisioned.secret), identity);
31423
- return { key: provisioned.secret };
31424
- }
31425
- async function syncMemoryKeyPlan(user, plan) {
31426
- const effectivePlan = isMemoryOperator(user.email) ? "unlimited" : plan;
31427
- const { key, error } = await getOrCreateUserMemoryKey(user);
31428
- if (!key) return { ok: false, error: error ?? "memory unavailable" };
31429
- const listed = await memoryCall(
31430
- "listKeysTool",
31431
- {},
31432
- key
31433
- );
31434
- if (!listed.ok || !listed.keys?.length) return { ok: false, error: listed.error ?? "no memory keys found" };
31435
- const target = listed.keys[0];
31436
- if (target.plan === effectivePlan) return { ok: true };
31437
- const res = await memoryCall("setScopeTool", { keyId: target.keyId, plan: effectivePlan }, key);
31438
- return { ok: res.ok, error: res.error };
31439
- }
31440
- async function syncScheduleEntitlement(user, enabled, quotaPerPeriod) {
31441
- const admin = ADMIN_KEY();
31442
- if (!admin) return { ok: false, error: "memory not configured (MCP_MEMORY_ADMIN_KEY missing)" };
31443
- const identity = resolveMemoryIdentity(user);
31444
- const res = await memoryCall("setScheduleEntitlementTool", {
31445
- granteeIdentity: identity,
31446
- enabled,
31447
- quotaPerPeriod,
31448
- mcpScraperApiKey: user.api_key
31449
- }, admin);
31450
- return { ok: res.ok, error: res.error };
31451
- }
31452
- var import_node_crypto9, MEMORY_BASE_URL, ADMIN_KEY;
31453
- var init_memory = __esm({
31454
- "src/api/memory.ts"() {
31455
- "use strict";
31456
- import_node_crypto9 = require("crypto");
31457
- init_session();
31458
- init_db();
31459
- MEMORY_BASE_URL = () => (process.env.MCP_MEMORY_BASE_URL ?? "https://mcp-memory-omega.vercel.app").replace(/\/$/, "");
31460
- ADMIN_KEY = () => process.env.MCP_MEMORY_ADMIN_KEY?.trim() ?? "";
31461
- }
31462
- });
31463
-
31464
31634
  // src/api/stripe-routes.ts
31465
31635
  function linePriceId(line) {
31466
31636
  const l = line;
@@ -31474,17 +31644,17 @@ async function resolveUser(customerId, emailFallback) {
31474
31644
  if (user) await setStripeCustomerId(user.id, customerId);
31475
31645
  return user;
31476
31646
  }
31477
- var import_stripe, import_hono14, stripe, stripeApp;
31647
+ var import_stripe, import_hono16, stripe, stripeApp;
31478
31648
  var init_stripe_routes = __esm({
31479
31649
  "src/api/stripe-routes.ts"() {
31480
31650
  "use strict";
31481
31651
  import_stripe = __toESM(require("stripe"), 1);
31482
- import_hono14 = require("hono");
31652
+ import_hono16 = require("hono");
31483
31653
  init_db();
31484
31654
  init_rates();
31485
31655
  init_memory();
31486
31656
  stripe = new import_stripe.default(process.env.STRIPE_SECRET_KEY, { apiVersion: "2026-02-25.clover" });
31487
- stripeApp = new import_hono14.Hono();
31657
+ stripeApp = new import_hono16.Hono();
31488
31658
  stripeApp.post("/webhooks", async (c) => {
31489
31659
  const sig = c.req.header("stripe-signature");
31490
31660
  const body = await c.req.text();
@@ -31600,8 +31770,9 @@ function isAllowedRedirect(uri) {
31600
31770
  } catch {
31601
31771
  return false;
31602
31772
  }
31603
- if (u.protocol !== "https:") return false;
31604
31773
  const h = u.hostname.toLowerCase();
31774
+ if (u.protocol === "http:" && (h === "localhost" || h === "127.0.0.1" || h === "::1")) return true;
31775
+ if (u.protocol !== "https:") return false;
31605
31776
  if (["claude.ai", "www.claude.ai", "claude.com", "www.claude.com"].includes(h)) return true;
31606
31777
  if (h.endsWith(".claude.ai") || h.endsWith(".claude.com")) return true;
31607
31778
  if (["chatgpt.com", "www.chatgpt.com", "chat.openai.com", "www.chat.openai.com"].includes(h)) return true;
@@ -31719,36 +31890,27 @@ function redirectWithError(redirectUri, state, error) {
31719
31890
  if (state) u.searchParams.set("state", state);
31720
31891
  return new Response(null, { status: 302, headers: { Location: u.toString() } });
31721
31892
  }
31722
- function authServerMetadata(scopes = SUPPORTED_SCOPES) {
31893
+ function authServerMetadata() {
31723
31894
  return {
31724
31895
  issuer: ISSUER,
31725
31896
  authorization_endpoint: `${ISSUER}/oauth/authorize`,
31726
31897
  token_endpoint: `${ISSUER}/oauth/token`,
31727
31898
  registration_endpoint: `${ISSUER}/oauth/register`,
31728
31899
  jwks_uri: `${ISSUER}/.well-known/jwks.json`,
31729
- scopes_supported: [...scopes],
31900
+ scopes_supported: [...SUPPORTED_SCOPES],
31730
31901
  response_types_supported: ["code"],
31731
31902
  grant_types_supported: ["authorization_code", "refresh_token"],
31732
31903
  code_challenge_methods_supported: ["S256"],
31733
31904
  token_endpoint_auth_methods_supported: ["none"]
31734
31905
  };
31735
31906
  }
31736
- function openidConfiguration(scopes = SUPPORTED_SCOPES) {
31907
+ function openidConfiguration() {
31737
31908
  return {
31738
- ...authServerMetadata(scopes),
31909
+ ...authServerMetadata(),
31739
31910
  subject_types_supported: ["public"],
31740
31911
  id_token_signing_alg_values_supported: ["RS256"]
31741
31912
  };
31742
31913
  }
31743
- function scopesForRequest(c) {
31744
- const host = (c.req.header("host") ?? "").toLowerCase();
31745
- if (!host) return SUPPORTED_SCOPES;
31746
- const suffix2 = c.req.path.replace(/^\/\.well-known\/(oauth-authorization-server|openid-configuration)/, "");
31747
- const candidate = `https://${host}${suffix2}`.replace(/\/$/, "");
31748
- if (candidate === SCRAPER_RESOURCE()) return SCRAPER_SCOPES;
31749
- if (candidate === RESOURCE().replace(/\/$/, "")) return MEMORY_SCOPES;
31750
- return SUPPORTED_SCOPES;
31751
- }
31752
31914
  function parseAuthParams(get) {
31753
31915
  return {
31754
31916
  response_type: get("response_type") ?? "",
@@ -31783,11 +31945,11 @@ async function mintAccessToken(identity, scope, plan, audience) {
31783
31945
  function tokenErrorResponse(c, error, description, status) {
31784
31946
  return c.json({ error, error_description: description }, status);
31785
31947
  }
31786
- var import_hono15, import_cookie, import_node_crypto10, import_jose2, ISSUER, RESOURCE, SCRAPER_RESOURCE, MEMORY_SCOPES, SCRAPER_SCOPES, SUPPORTED_SCOPES, ACCESS_TTL_SECONDS, REFRESH_TTL_SECONDS, CODE_TTL_SECONDS, secureCookies, sessionCookieOptions, cachedKeys, oauthApp;
31948
+ var import_hono17, import_cookie, import_node_crypto10, import_jose2, ISSUER, RESOURCE, SCRAPER_RESOURCE, MEMORY_SCOPES, SCRAPER_SCOPES, SUPPORTED_SCOPES, ACCESS_TTL_SECONDS, REFRESH_TTL_SECONDS, CODE_TTL_SECONDS, secureCookies, sessionCookieOptions, cachedKeys, oauthApp;
31787
31949
  var init_oauth_routes = __esm({
31788
31950
  "src/api/oauth-routes.ts"() {
31789
31951
  "use strict";
31790
- import_hono15 = require("hono");
31952
+ import_hono17 = require("hono");
31791
31953
  import_cookie = require("hono/cookie");
31792
31954
  import_node_crypto10 = require("crypto");
31793
31955
  import_jose2 = require("jose");
@@ -31813,7 +31975,7 @@ var init_oauth_routes = __esm({
31813
31975
  sameSite: "Lax"
31814
31976
  };
31815
31977
  cachedKeys = null;
31816
- oauthApp = new import_hono15.Hono();
31978
+ oauthApp = new import_hono17.Hono();
31817
31979
  oauthApp.use("*", async (c, next) => {
31818
31980
  c.header("Access-Control-Allow-Origin", "*");
31819
31981
  c.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -31823,19 +31985,19 @@ var init_oauth_routes = __esm({
31823
31985
  });
31824
31986
  oauthApp.get("/.well-known/oauth-authorization-server", (c) => {
31825
31987
  console.log("[oauth-dcr] GET /.well-known/oauth-authorization-server ua=%s", c.req.header("user-agent") ?? "");
31826
- return c.json(authServerMetadata(scopesForRequest(c)));
31988
+ return c.json(authServerMetadata());
31827
31989
  });
31828
31990
  oauthApp.get("/.well-known/oauth-authorization-server/*", (c) => {
31829
31991
  console.log("[oauth-dcr] GET %s (path-aware AS) ua=%s", c.req.path, c.req.header("user-agent") ?? "");
31830
- return c.json(authServerMetadata(scopesForRequest(c)));
31992
+ return c.json(authServerMetadata());
31831
31993
  });
31832
31994
  oauthApp.get("/.well-known/openid-configuration", (c) => {
31833
31995
  console.log("[oauth-dcr] GET /.well-known/openid-configuration ua=%s", c.req.header("user-agent") ?? "");
31834
- return c.json(openidConfiguration(scopesForRequest(c)));
31996
+ return c.json(openidConfiguration());
31835
31997
  });
31836
31998
  oauthApp.get("/.well-known/openid-configuration/*", (c) => {
31837
31999
  console.log("[oauth-dcr] GET %s (path-aware OIDC) ua=%s", c.req.path, c.req.header("user-agent") ?? "");
31838
- return c.json(openidConfiguration(scopesForRequest(c)));
32000
+ return c.json(openidConfiguration());
31839
32001
  });
31840
32002
  oauthApp.get("/.well-known/jwks.json", async (c) => {
31841
32003
  const { publicJwk } = await getKeys();
@@ -32551,13 +32713,13 @@ loadChannels();
32551
32713
  </body>
32552
32714
  </html>`;
32553
32715
  }
32554
- var import_hono16, chatApp;
32716
+ var import_hono18, chatApp;
32555
32717
  var init_chat_routes = __esm({
32556
32718
  "src/api/chat-routes.ts"() {
32557
32719
  "use strict";
32558
- import_hono16 = require("hono");
32720
+ import_hono18 = require("hono");
32559
32721
  init_memory();
32560
- chatApp = new import_hono16.Hono();
32722
+ chatApp = new import_hono18.Hono();
32561
32723
  chatApp.get("/api/channels", async (c) => {
32562
32724
  const token = c.req.query("token");
32563
32725
  if (!tokenOk(token)) return jsonError("missing or malformed token", 401);
@@ -32947,13 +33109,13 @@ loadActions();
32947
33109
  </body>
32948
33110
  </html>`;
32949
33111
  }
32950
- var import_hono17, scheduleApp;
33112
+ var import_hono19, scheduleApp;
32951
33113
  var init_schedule_routes = __esm({
32952
33114
  "src/api/schedule-routes.ts"() {
32953
33115
  "use strict";
32954
- import_hono17 = require("hono");
33116
+ import_hono19 = require("hono");
32955
33117
  init_memory();
32956
- scheduleApp = new import_hono17.Hono();
33118
+ scheduleApp = new import_hono19.Hono();
32957
33119
  scheduleApp.get("/api/status", async (c) => {
32958
33120
  const token = c.req.query("token");
32959
33121
  if (!tokenOk2(token)) return jsonError2("missing or malformed token", 401);
@@ -33299,6 +33461,20 @@ async function entitledVaultRows(identity) {
33299
33461
  }
33300
33462
  return [...seen.values()];
33301
33463
  }
33464
+ async function embedBytesByPhysical(physicals) {
33465
+ const m = /* @__PURE__ */ new Map();
33466
+ try {
33467
+ const rows = await sql().query(
33468
+ `SELECT metadata->>'vault' AS vault, COUNT(*)::bigint AS chunks
33469
+ FROM "memory" WHERE metadata->>'vault' = ANY($1) GROUP BY 1`,
33470
+ [physicals]
33471
+ );
33472
+ for (const r of rows) if (r.vault) m.set(r.vault, Number(r.chunks) * EMBED_BYTES_PER_CHUNK);
33473
+ } catch {
33474
+ return m;
33475
+ }
33476
+ return m;
33477
+ }
33302
33478
  async function storageByPhysical(physicals) {
33303
33479
  if (physicals.length === 0) return /* @__PURE__ */ new Map();
33304
33480
  const rows = await sql().query(
@@ -33306,8 +33482,9 @@ async function storageByPhysical(physicals) {
33306
33482
  FROM mem_notes WHERE vault = ANY($1) GROUP BY vault`,
33307
33483
  [physicals]
33308
33484
  );
33485
+ const embed = await embedBytesByPhysical(physicals);
33309
33486
  const m = /* @__PURE__ */ new Map();
33310
- for (const r of rows) m.set(r.vault, { notes: Number(r.notes), bytes: Number(r.bytes) });
33487
+ for (const r of rows) m.set(r.vault, { notes: Number(r.notes), bytes: Number(r.bytes) + (embed.get(r.vault) ?? 0) });
33311
33488
  return m;
33312
33489
  }
33313
33490
  async function dbListVaults(identity) {
@@ -33420,13 +33597,14 @@ async function dbUsage(identity, plan) {
33420
33597
  unlimited: isUnlimited(plan)
33421
33598
  };
33422
33599
  }
33423
- var import_serverless, _sql, FREE_COST_CAP_USD;
33600
+ var import_serverless, _sql, EMBED_BYTES_PER_CHUNK, FREE_COST_CAP_USD;
33424
33601
  var init_memory_db = __esm({
33425
33602
  "src/api/memory-db.ts"() {
33426
33603
  "use strict";
33427
33604
  import_serverless = require("@neondatabase/serverless");
33428
33605
  init_rates();
33429
33606
  _sql = null;
33607
+ EMBED_BYTES_PER_CHUNK = Number(process.env.JINA_EMBED_DIM ?? 1024) * 4;
33430
33608
  FREE_COST_CAP_USD = 1;
33431
33609
  }
33432
33610
  });
@@ -33628,6 +33806,7 @@ function opForCostPath(p) {
33628
33806
  if (p.startsWith("/instagram/")) return "instagram";
33629
33807
  if (p === "/reddit/thread") return "reddit_thread";
33630
33808
  if (p.startsWith("/api/internal/site-architecture-auditor")) return "audit_site";
33809
+ if (p.startsWith("/api/internal/memory")) return "memory_ai";
33631
33810
  if (p.startsWith("/agent/")) return "browser_session";
33632
33811
  return null;
33633
33812
  }
@@ -33681,7 +33860,7 @@ async function checkHarvestLimits(user, reuseLockId) {
33681
33860
  }
33682
33861
  return null;
33683
33862
  }
33684
- var import_resend, import_hono18, import_hono19, import_factory6, import_cookie2, import_stripe2, secureCookies2, isProduction2, sessionCookieOptions2, requireAllowedOrigin, auth2, adminAuth, sessionAuth, app, STRIPE_API_VERSION, SYNC_HARVEST_TIMEOUT_OVERRIDE_MS;
33863
+ var import_resend, import_hono20, import_hono21, import_factory6, import_cookie2, import_stripe2, secureCookies2, isProduction2, sessionCookieOptions2, requireAllowedOrigin, auth2, adminAuth, sessionAuth, app, STRIPE_API_VERSION, SYNC_HARVEST_TIMEOUT_OVERRIDE_MS;
33685
33864
  var init_server = __esm({
33686
33865
  "src/api/server.ts"() {
33687
33866
  "use strict";
@@ -33699,20 +33878,22 @@ var init_server = __esm({
33699
33878
  init_media_extractor();
33700
33879
  init_site_mapper();
33701
33880
  init_site_extractor();
33702
- import_hono18 = require("hono");
33703
- import_hono19 = require("inngest/hono");
33881
+ import_hono20 = require("hono");
33882
+ import_hono21 = require("inngest/hono");
33704
33883
  init_client();
33705
33884
  init_site_audit();
33706
33885
  init_site_extract();
33707
33886
  init_site_extract_repository();
33708
33887
  init_catalog_seed();
33709
33888
  init_site_audit_routes();
33889
+ init_internal_memory_routes();
33710
33890
  init_youtube_routes();
33711
33891
  init_screenshot_routes();
33712
33892
  init_facebook_ad_routes();
33713
33893
  init_google_ads_routes();
33714
33894
  init_instagram_routes();
33715
33895
  init_reddit_routes();
33896
+ init_video_routes();
33716
33897
  init_maps_routes();
33717
33898
  init_directory_routes();
33718
33899
  init_workflow_routes();
@@ -33789,7 +33970,7 @@ var init_server = __esm({
33789
33970
  c.set("sessionUser", { ...refreshed, balance_mc: balanceMc });
33790
33971
  return next();
33791
33972
  });
33792
- app = new import_hono18.Hono();
33973
+ app = new import_hono20.Hono();
33793
33974
  STRIPE_API_VERSION = "2026-02-25.clover";
33794
33975
  app.use("*", async (c, next) => {
33795
33976
  await next();
@@ -33871,6 +34052,27 @@ var init_server = __esm({
33871
34052
  (0, import_cookie2.deleteCookie)(c, "session", { path: "/", secure: secureCookies2, sameSite: "Strict" });
33872
34053
  return c.json({ ok: true });
33873
34054
  });
34055
+ app.post("/account/delete", requireAllowedOrigin, sessionAuth, async (c) => {
34056
+ const user = c.get("sessionUser");
34057
+ const secret2 = requireStripeSecret();
34058
+ if (secret2 && user.stripe_customer_id) {
34059
+ const stripeClient = new import_stripe2.default(secret2, { apiVersion: STRIPE_API_VERSION });
34060
+ const subs = await stripeClient.subscriptions.list({ customer: user.stripe_customer_id, status: "all", limit: 100 });
34061
+ for (const sub of subs.data) {
34062
+ if (sub.status === "active" || sub.status === "trialing" || sub.status === "past_due") {
34063
+ try {
34064
+ await stripeClient.subscriptions.cancel(sub.id);
34065
+ } catch (err) {
34066
+ console.error("[account/delete] failed to cancel subscription", sub.id, err instanceof Error ? err.message : String(err));
34067
+ return c.json({ error: "Could not cancel an active subscription \u2014 please try again or contact support." }, 500);
34068
+ }
34069
+ }
34070
+ }
34071
+ }
34072
+ await deactivateUser(user.id);
34073
+ (0, import_cookie2.deleteCookie)(c, "session", { path: "/", secure: secureCookies2, sameSite: "Strict" });
34074
+ return c.json({ ok: true });
34075
+ });
33874
34076
  app.post("/auth/forgot-password", requireAllowedOrigin, async (c) => {
33875
34077
  const { email } = await c.req.json();
33876
34078
  const normalizedEmail = email?.trim().toLowerCase();
@@ -34843,6 +35045,24 @@ var init_server = __esm({
34843
35045
  return c.json({ error: message }, 500);
34844
35046
  }
34845
35047
  });
35048
+ app.post("/billing/portal", requireAllowedOrigin, sessionAuth, async (c) => {
35049
+ try {
35050
+ const user = c.get("sessionUser");
35051
+ if (!user.stripe_customer_id) return c.json({ error: "No billing account yet \u2014 subscribe first." }, 409);
35052
+ const secret2 = requireStripeSecret();
35053
+ if (!secret2) return c.json({ error: "Stripe is not configured." }, 503);
35054
+ const stripeClient = new import_stripe2.default(secret2, { apiVersion: STRIPE_API_VERSION });
35055
+ const session = await stripeClient.billingPortal.sessions.create({
35056
+ customer: user.stripe_customer_id,
35057
+ return_url: `${appOrigin()}/billing`
35058
+ });
35059
+ return c.json({ url: session.url });
35060
+ } catch (err) {
35061
+ const message = err instanceof Error ? err.message : "Unable to open billing portal.";
35062
+ console.error("[billing/portal]", message);
35063
+ return c.json({ error: message }, 500);
35064
+ }
35065
+ });
34846
35066
  app.post("/billing/concurrency/terminal-checkout", auth2, async (c) => {
34847
35067
  try {
34848
35068
  const user = c.get("user");
@@ -35023,14 +35243,16 @@ var init_server = __esm({
35023
35243
  ]);
35024
35244
  return c.json({ drained: results.length, results, sweepResult, reaped: reapResult, expired: expiredResult, blobCleanup, workflowDispatch: workflowDispatchResult });
35025
35245
  });
35026
- app.on(["GET", "POST", "PUT"], "/api/inngest", (0, import_hono19.serve)({ client: inngest, functions: [siteAuditFn, siteExtractFn] }));
35246
+ app.on(["GET", "POST", "PUT"], "/api/inngest", (0, import_hono21.serve)({ client: inngest, functions: [siteAuditFn, siteExtractFn] }));
35027
35247
  app.route("/api/internal/site-architecture-auditor", siteAuditApp);
35248
+ app.route("/api/internal/memory", internalMemoryApp);
35028
35249
  app.route("/youtube", youtubeApp);
35029
35250
  app.route("/screenshot", screenshotApp);
35030
35251
  app.route("/facebook", facebookAdApp);
35031
35252
  app.route("/google-ads", googleAdsApp);
35032
35253
  app.route("/instagram", instagramApp);
35033
35254
  app.route("/reddit", redditApp);
35255
+ app.route("/video", videoApp);
35034
35256
  app.route("/maps", mapsApp);
35035
35257
  app.route("/directory", directoryApp);
35036
35258
  app.route("/workflows", workflowApp);