mcp-scraper 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/dist/bin/api-server.cjs +1 -1
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +110 -10
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +110 -10
- package/dist/bin/mcp-scraper-cli.js.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +17 -10
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +4 -4
- package/dist/bin/mcp-scraper-install.cjs +17 -10
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +1 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-2H365TJ6.js → chunk-4TNQUYP7.js} +2 -2
- package/dist/chunk-ISIITOAL.js +7 -0
- package/dist/chunk-ISIITOAL.js.map +1 -0
- package/dist/{chunk-MLNCKQ2B.js → chunk-Q4STSM63.js} +17 -10
- package/dist/chunk-Q4STSM63.js.map +1 -0
- package/dist/{chunk-Q5XUNDN5.js → chunk-TTSW2MHR.js} +2 -2
- package/dist/{server-3LDQCOIN.js → server-TZ5EMANS.js} +3 -3
- package/docs/mcp-tool-craft-lint.generated.md +6 -2
- package/package.json +1 -1
- package/dist/chunk-MLNCKQ2B.js.map +0 -1
- package/dist/chunk-RXUIQTDU.js +0 -7
- package/dist/chunk-RXUIQTDU.js.map +0 -1
- /package/dist/{chunk-2H365TJ6.js.map → chunk-4TNQUYP7.js.map} +0 -0
- /package/dist/{chunk-Q5XUNDN5.js.map → chunk-TTSW2MHR.js.map} +0 -0
- /package/dist/{server-3LDQCOIN.js.map → server-TZ5EMANS.js.map} +0 -0
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "../chunk-DUEW4EOO.js";
|
|
16
16
|
import {
|
|
17
17
|
PACKAGE_VERSION
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-ISIITOAL.js";
|
|
19
19
|
|
|
20
20
|
// src/cli/human-cli.ts
|
|
21
21
|
import { Command } from "commander";
|
|
@@ -67,6 +67,22 @@ function renderClaudeCommand(options = {}) {
|
|
|
67
67
|
` -- npx ${combinedNpxArgs(options).join(" ")}`
|
|
68
68
|
].join(" \\\n");
|
|
69
69
|
}
|
|
70
|
+
function claudeMcpRemoveArgs() {
|
|
71
|
+
return ["mcp", "remove", "mcp-scraper", "-s", "user"];
|
|
72
|
+
}
|
|
73
|
+
function claudeMcpAddArgs(options = {}) {
|
|
74
|
+
const args = ["mcp", "add", "mcp-scraper", "--scope", "user"];
|
|
75
|
+
for (const [key, value] of Object.entries(envConfig(options))) {
|
|
76
|
+
args.push("--env", `${key}=${value}`);
|
|
77
|
+
}
|
|
78
|
+
args.push("--", "npx", ...combinedNpxArgs(options));
|
|
79
|
+
return args;
|
|
80
|
+
}
|
|
81
|
+
function normalizeAgentHost(host) {
|
|
82
|
+
if (host === "claude-code") return "claude";
|
|
83
|
+
if (host === "claude" || host === "codex" || host === "claude-desktop") return host;
|
|
84
|
+
throw new Error('Unknown host "' + host + '". Use: codex, claude, claude-code, or claude-desktop');
|
|
85
|
+
}
|
|
70
86
|
function renderClaudeDesktopConfig(options = {}) {
|
|
71
87
|
return JSON.stringify({
|
|
72
88
|
mcpServers: {
|
|
@@ -79,8 +95,10 @@ function renderClaudeDesktopConfig(options = {}) {
|
|
|
79
95
|
}, null, 2);
|
|
80
96
|
}
|
|
81
97
|
function renderAgentInstall(host, options = {}) {
|
|
98
|
+
const normalizedHost = normalizeAgentHost(host);
|
|
82
99
|
const restart = "Restart the MCP client so it starts a fresh npx process.";
|
|
83
|
-
|
|
100
|
+
const applyCommand = `MCP_SCRAPER_API_KEY=${apiKeyValue(options)} npx -y -p mcp-scraper@latest mcp-scraper-cli agent install claude --apply`;
|
|
101
|
+
if (normalizedHost === "codex") {
|
|
84
102
|
return [
|
|
85
103
|
"# Codex MCP config",
|
|
86
104
|
renderCodexConfig(options),
|
|
@@ -88,11 +106,14 @@ function renderAgentInstall(host, options = {}) {
|
|
|
88
106
|
restart
|
|
89
107
|
].join("\n");
|
|
90
108
|
}
|
|
91
|
-
if (
|
|
109
|
+
if (normalizedHost === "claude") {
|
|
92
110
|
return [
|
|
93
111
|
"# Claude Code command",
|
|
94
112
|
renderClaudeCommand(options),
|
|
95
113
|
"",
|
|
114
|
+
"# One-command Claude Code setup",
|
|
115
|
+
applyCommand,
|
|
116
|
+
"",
|
|
96
117
|
restart
|
|
97
118
|
].join("\n");
|
|
98
119
|
}
|
|
@@ -383,6 +404,34 @@ function writeOutput(data, json) {
|
|
|
383
404
|
`);
|
|
384
405
|
}
|
|
385
406
|
}
|
|
407
|
+
function maskSecrets(value) {
|
|
408
|
+
return value.replace(/sk_[A-Za-z0-9_-]+/g, "sk_***");
|
|
409
|
+
}
|
|
410
|
+
function runLocalCommand(command, args) {
|
|
411
|
+
return new Promise((resolve) => {
|
|
412
|
+
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
413
|
+
const stdout = [];
|
|
414
|
+
const stderr = [];
|
|
415
|
+
let settled = false;
|
|
416
|
+
const done = (result) => {
|
|
417
|
+
if (settled) return;
|
|
418
|
+
settled = true;
|
|
419
|
+
resolve(result);
|
|
420
|
+
};
|
|
421
|
+
child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk)));
|
|
422
|
+
child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk)));
|
|
423
|
+
child.on("error", (err) => {
|
|
424
|
+
done({ code: 127, stdout: "", stderr: err.message });
|
|
425
|
+
});
|
|
426
|
+
child.on("close", (code) => {
|
|
427
|
+
done({
|
|
428
|
+
code: typeof code === "number" ? code : 1,
|
|
429
|
+
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
430
|
+
stderr: Buffer.concat(stderr).toString("utf8")
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
}
|
|
386
435
|
function cadenceOpt(opts) {
|
|
387
436
|
if (opts.daily) return "daily";
|
|
388
437
|
if (opts.monthly) return "monthly";
|
|
@@ -484,8 +533,8 @@ function buildHumanCli() {
|
|
|
484
533
|
"",
|
|
485
534
|
"To clone a real local Chrome profile for MCP local browser mode:",
|
|
486
535
|
" mcp-scraper-cli browser import-chrome --email you@example.com --name <suggested profile name>",
|
|
487
|
-
"Then
|
|
488
|
-
" mcp-scraper-cli agent install claude
|
|
536
|
+
"Then apply Claude Code config with:",
|
|
537
|
+
" MCP_SCRAPER_API_KEY=sk_live_your_key mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile <suggested profile name>"
|
|
489
538
|
];
|
|
490
539
|
writeOutput(lines.join("\n"), false);
|
|
491
540
|
});
|
|
@@ -509,9 +558,9 @@ function buildHumanCli() {
|
|
|
509
558
|
`Managed user data dir: ${result.profile.userDataDir}`,
|
|
510
559
|
"",
|
|
511
560
|
"Install/config command:",
|
|
512
|
-
` mcp-scraper-cli agent install
|
|
561
|
+
` MCP_SCRAPER_API_KEY=sk_live_your_key mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile ${result.profile.name}`,
|
|
513
562
|
"",
|
|
514
|
-
"
|
|
563
|
+
"Fully exit Claude Code and start a new Claude terminal after applying config. Re-run sync-profile after signing into new sites in normal Chrome."
|
|
515
564
|
].join("\n"), false);
|
|
516
565
|
});
|
|
517
566
|
browser.command("sync-profile <name>").description("Refresh a managed local browser profile from its recorded source Chrome profile.").option("--output-dir <path>", "Managed profile base directory").option("--browser-executable <path>", "Chrome executable path for local launches").option("--json", "Print machine-readable JSON").action(async (name, opts) => {
|
|
@@ -531,11 +580,62 @@ function buildHumanCli() {
|
|
|
531
580
|
].join("\n"), false);
|
|
532
581
|
});
|
|
533
582
|
const agent = program.command("agent").description("Generate AI-agent install configs and workflow prompts.");
|
|
534
|
-
agent.command("install <host>").description("Print install/config instructions for codex, claude, or claude-desktop.").option("--api-key <key>", "API key to place in generated config").option("--package <spec>", "npm package spec", "mcp-scraper@latest").option("--browser-mode <mode>", "Browser mode: hosted or local", "hosted").option("--browser-profile <name>", "Default browser profile for browser_open sessions. In local mode this is a managed MCP Scraper profile name; in hosted mode it is a Kernel profile name.").option("--browser-executable <path>", "Chrome executable path for local browser mode").option("--save-browser-profile-changes", "Persist cookies/local storage back to the named browser profile when sessions close").option("--json", "Print machine-readable JSON").action((
|
|
535
|
-
const
|
|
536
|
-
if (!valid.includes(host)) throw new Error(`Unknown host "${host}". Use: ${valid.join(", ")}`);
|
|
583
|
+
agent.command("install <host>").description("Print or apply install/config instructions for codex, claude/claude-code, or claude-desktop.").option("--api-key <key>", "API key to place in generated config").option("--package <spec>", "npm package spec", "mcp-scraper@latest").option("--browser-mode <mode>", "Browser mode: hosted or local", "hosted").option("--browser-profile <name>", "Default browser profile for browser_open sessions. In local mode this is a managed MCP Scraper profile name; in hosted mode it is a Kernel profile name.").option("--browser-executable <path>", "Chrome executable path for local browser mode").option("--save-browser-profile-changes", "Persist cookies/local storage back to the named browser profile when sessions close").option("--apply", "Apply the config to the local client when supported. For Claude Code, this upserts the user-scope mcp-scraper server.").option("--json", "Print machine-readable JSON").action(async (hostInput, opts) => {
|
|
584
|
+
const host = normalizeAgentHost(hostInput);
|
|
537
585
|
const browserMode = String(opts.browserMode ?? "hosted");
|
|
538
586
|
if (!["hosted", "local"].includes(browserMode)) throw new Error("Unknown browser mode. Use: hosted or local");
|
|
587
|
+
const apiKey = opts.apiKey ?? process.env.MCP_SCRAPER_API_KEY;
|
|
588
|
+
if (opts.apply) {
|
|
589
|
+
if (host !== "claude") throw new Error('--apply is currently supported for Claude Code only. Use host "claude" or "claude-code".');
|
|
590
|
+
if (!apiKey?.trim()) {
|
|
591
|
+
throw new Error("MCP_SCRAPER_API_KEY is required for --apply. Set it in the environment or pass --api-key.");
|
|
592
|
+
}
|
|
593
|
+
const configOptions = {
|
|
594
|
+
apiKey,
|
|
595
|
+
packageSpec: opts.package,
|
|
596
|
+
browserMode,
|
|
597
|
+
browserProfileName: opts.browserProfile,
|
|
598
|
+
browserProfileSaveChanges: opts.saveBrowserProfileChanges,
|
|
599
|
+
browserExecutablePath: opts.browserExecutable
|
|
600
|
+
};
|
|
601
|
+
const remove = await runLocalCommand("claude", claudeMcpRemoveArgs());
|
|
602
|
+
const add = await runLocalCommand("claude", claudeMcpAddArgs(configOptions));
|
|
603
|
+
if (add.code !== 0) {
|
|
604
|
+
const reason = maskSecrets([add.stderr, add.stdout].filter(Boolean).join("\n").trim());
|
|
605
|
+
throw new Error([
|
|
606
|
+
"Claude Code MCP registration failed.",
|
|
607
|
+
reason || "No error output returned.",
|
|
608
|
+
"Make sure Claude Code is installed and the `claude` command is on PATH."
|
|
609
|
+
].join("\n"));
|
|
610
|
+
}
|
|
611
|
+
const list = await runLocalCommand("claude", ["mcp", "list"]);
|
|
612
|
+
const result = {
|
|
613
|
+
host: "claude",
|
|
614
|
+
applied: true,
|
|
615
|
+
replacedExisting: remove.code === 0,
|
|
616
|
+
command: "npx",
|
|
617
|
+
args: ["-y", "-p", opts.package, "mcp-scraper-combined"],
|
|
618
|
+
nextStep: "Fully exit Claude Code, start a new Claude terminal, then run: claude mcp list",
|
|
619
|
+
list: maskSecrets([list.stdout, list.stderr].filter(Boolean).join("\n").trim())
|
|
620
|
+
};
|
|
621
|
+
if (opts.json) {
|
|
622
|
+
writeOutput(result, true);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
writeOutput([
|
|
626
|
+
"Applied Claude Code MCP config: mcp-scraper",
|
|
627
|
+
remove.code === 0 ? "Replaced existing mcp-scraper entry." : "No existing mcp-scraper entry found; added a new one.",
|
|
628
|
+
"Command: npx -y -p " + opts.package + " mcp-scraper-combined",
|
|
629
|
+
browserMode === "local" && opts.browserProfile ? `Local browser profile: ${opts.browserProfile}` : "",
|
|
630
|
+
"",
|
|
631
|
+
"Next step: fully exit Claude Code, start a new Claude terminal, then run:",
|
|
632
|
+
" claude mcp list",
|
|
633
|
+
"",
|
|
634
|
+
result.list ? `Current Claude MCP list:
|
|
635
|
+
${result.list}` : ""
|
|
636
|
+
].filter(Boolean).join("\n"), false);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
539
639
|
const text = renderAgentInstall(host, {
|
|
540
640
|
apiKey: opts.apiKey,
|
|
541
641
|
packageSpec: opts.package,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/human-cli.ts","../../src/cli/agent-config.ts","../../src/cli/doctor.ts","../../src/cli/prompts.ts","../../bin/mcp-scraper-cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { spawn } from 'node:child_process'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { basename, join } from 'node:path'\nimport { PACKAGE_VERSION } from '../version.js'\nimport { listLocalChromeProfiles } from '../lib/chrome-profiles.js'\nimport { importChromeProfile, syncImportedChromeProfile } from '../lib/local-browser-profiles.js'\nimport { renderAgentInstall, type AgentHost, type BrowserMode } from './agent-config.js'\nimport { renderDoctor, runDoctor } from './doctor.js'\nimport { listPrompts, renderPrompt } from './prompts.js'\nimport { workflowOutputBaseDir } from '../workflows/artifact-writer.js'\nimport { findWorkflowReport, listWorkflowDefinitions, listWorkflowReports, openWorkflowReport, runWorkflow } from '../workflows/registry.js'\n\nfunction numberOpt(value: unknown): number | undefined {\n if (value === undefined || value === null || value === '') return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nfunction booleanOpt(value: unknown): boolean | undefined {\n if (value === undefined) return undefined\n if (typeof value === 'boolean') return value\n if (value === 'true') return true\n if (value === 'false') return false\n return undefined\n}\n\nfunction compactInput(input: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined))\n}\n\nfunction workflowInput(id: string, opts: Record<string, unknown>): Record<string, unknown> {\n if (id === 'agent-packet' || id === 'serp-comparison' || id === 'ai-overview-language') {\n return compactInput({\n keyword: opts.keyword,\n domain: opts.domain,\n url: opts.url,\n location: opts.location,\n maxResults: numberOpt(opts.maxResults),\n maxQuestions: numberOpt(opts.maxQuestions),\n extractTop: numberOpt(opts.extractTop),\n includeSerp: opts.serp === false ? false : undefined,\n includePaa: opts.paa === false ? false : undefined,\n includeAiOverview: booleanOpt(opts.includeAiOverview),\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n if (id === 'paa-expansion-brief') {\n return compactInput({\n keyword: opts.keyword,\n location: opts.location,\n maxQuestions: numberOpt(opts.maxQuestions),\n depth: numberOpt(opts.depth),\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n if (id === 'directory' || id === 'local-competitive-audit' || id === 'map-comparison') {\n return compactInput({\n query: opts.query,\n location: opts.location,\n state: opts.state,\n minPopulation: numberOpt(opts.minPop ?? opts.minPopulation),\n maxCities: numberOpt(opts.maxCities),\n maxResultsPerCity: numberOpt(opts.perCity ?? opts.maxResultsPerCity ?? opts.maxResults),\n concurrency: numberOpt(opts.concurrency),\n proxyMode: opts.proxyMode,\n hydrateTop: id === 'local-competitive-audit' || id === 'map-comparison' ? numberOpt(opts.hydrateTop) : undefined,\n maxReviews: id === 'local-competitive-audit' || id === 'map-comparison' ? numberOpt(opts.reviews ?? opts.maxReviews) : undefined,\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n return compactInput(opts)\n}\n\nfunction writeOutput(data: unknown, json: boolean | undefined): void {\n if (json) {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n } else if (typeof data === 'string') {\n process.stdout.write(`${data}\\n`)\n } else {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n }\n}\n\nfunction cadenceOpt(opts: Record<string, unknown>): 'daily' | 'weekly' | 'monthly' {\n if (opts.daily) return 'daily'\n if (opts.monthly) return 'monthly'\n return 'weekly'\n}\n\nfunction apiOptions(opts: Record<string, unknown>): { apiUrl: string; apiKey: string } {\n const apiKey = String(opts.apiKey ?? process.env.MCP_SCRAPER_API_KEY ?? '').trim()\n if (!apiKey) throw new Error('MCP_SCRAPER_API_KEY is required. Pass --api-key or set the environment variable.')\n return {\n apiUrl: String(opts.apiUrl ?? process.env.MCP_SCRAPER_API_URL ?? 'https://mcpscraper.dev').replace(/\\/$/, ''),\n apiKey,\n }\n}\n\nfunction openExternalUrl(url: string): boolean {\n const command = process.platform === 'darwin'\n ? 'open'\n : process.platform === 'win32'\n ? 'cmd'\n : 'xdg-open'\n const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]\n try {\n const child = spawn(command, args, { detached: true, stdio: 'ignore' })\n child.unref()\n return true\n } catch {\n return false\n }\n}\n\nasync function apiRequest<T>(path: string, method: string, opts: Record<string, unknown>, body?: unknown): Promise<T> {\n const { apiUrl, apiKey } = apiOptions(opts)\n const res = await fetch(`${apiUrl}${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: body == null ? undefined : JSON.stringify(body),\n })\n const data = await res.json().catch(() => ({}))\n if (!res.ok) {\n const message = typeof (data as { error?: unknown }).error === 'string'\n ? (data as { error: string }).error\n : `API request failed with ${res.status}`\n throw new Error(message)\n }\n return data as T\n}\n\nfunction addWorkflowInputOptions(command: Command): Command {\n return command\n .option('--keyword <keyword>', 'Agent packet keyword')\n .option('--domain <domain>', 'Target domain')\n .option('--url <url>', 'Target page URL')\n .option('--location <location>', 'Target location')\n .option('--max-results <n>', 'Maximum SERP or Maps results')\n .option('--max-questions <n>', 'Maximum PAA questions')\n .option('--extract-top <n>', 'Top result pages or citation pages to extract')\n .option('--depth <n>', 'PAA expansion depth')\n .option('--no-serp', 'Skip SERP evidence for agent packet')\n .option('--no-paa', 'Skip PAA evidence for agent packet')\n .option('--query <query>', 'Business category or workflow query')\n .option('--state <state>', 'US state')\n .option('--min-pop <n>', 'Minimum city population')\n .option('--max-cities <n>', 'Maximum selected cities')\n .option('--per-city <n>', 'Maps results per city')\n .option('--concurrency <n>', 'City search concurrency')\n .option('--proxy-mode <mode>', 'Proxy mode: location, configured, or none')\n .option('--hydrate-top <n>', 'Profiles to hydrate per city for competitive audits')\n .option('--reviews <n>', 'Review cards to collect per hydrated profile')\n .option('--no-return-partial', 'Fail instead of writing partial artifacts')\n}\n\nexport function buildHumanCli(): Command {\n const program = new Command()\n program\n .name('mcp-scraper-cli')\n .description('Human CLI for MCP Scraper setup, workflows, reports, and agent-ready SEO artifacts.')\n .version(PACKAGE_VERSION)\n\n program.command('doctor')\n .description('Check local setup, API key, output directory, package version, and recommended MCP config.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Output directory to test')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const output = await runDoctor({ apiKey: opts.apiKey, apiUrl: opts.apiUrl, outputDir: opts.outputDir })\n writeOutput(opts.json ? output : renderDoctor(output), opts.json)\n if (!output.ok) process.exitCode = 1\n })\n\n const billing = program.command('billing').description('Inspect billing and start checkout flows.')\n const billingConcurrency = billing.command('concurrency').description('Manage MCP Scraper concurrency slots.')\n\n billingConcurrency.command('info')\n .description('Show current concurrency limit and extra-slot price.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ concurrency: Record<string, unknown> }>('/billing/credits', 'POST', opts, {})\n if (opts.json) writeOutput(result.concurrency, true)\n else {\n const upgrade = result.concurrency?.upgrade as Record<string, unknown> | undefined\n writeOutput([\n `Current limit: ${result.concurrency?.current_limit ?? 'unknown'} concurrent operations`,\n `Extra slots: ${result.concurrency?.current_extra_slots ?? 'unknown'}`,\n `Extra concurrency slot: ${upgrade?.price_label ?? '$5/month'}`,\n `Upgrade command: ${upgrade?.terminal_command ?? 'mcp-scraper-cli billing concurrency checkout'}`,\n ].join('\\n'), false)\n }\n })\n\n billingConcurrency.command('checkout')\n .description('Create a hosted Stripe checkout for one extra concurrency slot.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .option('--no-open', 'Print the checkout URL without opening a browser')\n .action(async (opts) => {\n const result = await apiRequest<{ checkout_url: string; price?: { price_label?: string }; next_step?: string }>('/billing/concurrency/terminal-checkout', 'POST', opts, {})\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n const opened = opts.open !== false && openExternalUrl(result.checkout_url)\n writeOutput([\n `Extra concurrency slot: ${result.price?.price_label ?? '$5/month'}`,\n opened ? `Opened checkout: ${result.checkout_url}` : `Checkout URL: ${result.checkout_url}`,\n result.next_step ?? 'Complete checkout, then retry the MCP request.',\n ].join('\\n'), false)\n })\n\n const browser = program.command('browser').description('Inspect and manage browser-agent profile setup helpers.')\n browser.command('profiles')\n .description('List local Chrome profiles and suggested managed browser profile names.')\n .option('--email <email>', 'Filter by Chrome account email or displayed profile name')\n .option('--user-data-dir <path>', 'Chrome user data directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const profiles = await listLocalChromeProfiles(opts.userDataDir, opts.email)\n if (opts.json) {\n writeOutput({ profiles }, true)\n return\n }\n if (!profiles.length) {\n writeOutput('No matching Chrome profiles found.', false)\n return\n }\n const lines = [\n 'Local Chrome profiles:',\n ...profiles.map(profile => [\n `${profile.email || '(no email)'}\\t${profile.chromeProfileDirectory}\\t${profile.displayName}`,\n ` suggested profile name: ${profile.recommendedKernelProfileName}`,\n ` local Chrome path: ${profile.chromeProfilePath}`,\n ].join('\\n')),\n '',\n 'To clone a real local Chrome profile for MCP local browser mode:',\n ' mcp-scraper-cli browser import-chrome --email you@example.com --name <suggested profile name>',\n 'Then generate config with:',\n ' mcp-scraper-cli agent install claude-desktop --browser-mode local --browser-profile <suggested profile name>',\n ]\n writeOutput(lines.join('\\n'), false)\n })\n\n browser.command('import-chrome')\n .description('Clone a local Chrome profile into MCP Scraper managed local browser storage.')\n .option('--email <email>', 'Chrome account email or displayed profile name to import')\n .option('--name <name>', 'Managed MCP Scraper browser profile name')\n .option('--chrome-profile <directory>', 'Chrome profile directory, for example Default or Profile 1')\n .option('--user-data-dir <path>', 'Source Chrome user data directory')\n .option('--output-dir <path>', 'Managed profile base directory')\n .option('--browser-executable <path>', 'Chrome executable path for local launches')\n .option('--overwrite', 'Overwrite an existing managed profile clone')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await importChromeProfile({\n email: opts.email,\n name: opts.name,\n chromeProfileDirectory: opts.chromeProfile,\n sourceUserDataDir: opts.userDataDir,\n outputDir: opts.outputDir,\n browserExecutablePath: opts.browserExecutable,\n overwrite: opts.overwrite,\n })\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n writeOutput([\n `Imported Chrome profile: ${result.profile.name}`,\n `Source: ${result.sourceProfile.email || result.sourceProfile.displayName || result.sourceProfile.chromeProfileDirectory} (${result.sourceProfile.chromeProfileDirectory})`,\n `Managed user data dir: ${result.profile.userDataDir}`,\n '',\n 'Install/config command:',\n ` mcp-scraper-cli agent install codex --browser-mode local --browser-profile ${result.profile.name}`,\n '',\n 'Restart the MCP client after updating config. Re-run sync-profile after signing into new sites in normal Chrome.',\n ].join('\\n'), false)\n })\n\n browser.command('sync-profile <name>')\n .description('Refresh a managed local browser profile from its recorded source Chrome profile.')\n .option('--output-dir <path>', 'Managed profile base directory')\n .option('--browser-executable <path>', 'Chrome executable path for local launches')\n .option('--json', 'Print machine-readable JSON')\n .action(async (name: string, opts) => {\n const result = await syncImportedChromeProfile(name, {\n outputDir: opts.outputDir,\n browserExecutablePath: opts.browserExecutable,\n })\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n writeOutput([\n `Synced Chrome profile: ${result.profile.name}`,\n `Source: ${result.sourceProfile.email || result.sourceProfile.displayName || result.sourceProfile.chromeProfileDirectory} (${result.sourceProfile.chromeProfileDirectory})`,\n `Managed user data dir: ${result.profile.userDataDir}`,\n 'Restart any local browser sessions that were using this profile.',\n ].join('\\n'), false)\n })\n\n const agent = program.command('agent').description('Generate AI-agent install configs and workflow prompts.')\n agent.command('install <host>')\n .description('Print install/config instructions for codex, claude, or claude-desktop.')\n .option('--api-key <key>', 'API key to place in generated config')\n .option('--package <spec>', 'npm package spec', 'mcp-scraper@latest')\n .option('--browser-mode <mode>', 'Browser mode: hosted or local', 'hosted')\n .option('--browser-profile <name>', 'Default browser profile for browser_open sessions. In local mode this is a managed MCP Scraper profile name; in hosted mode it is a Kernel profile name.')\n .option('--browser-executable <path>', 'Chrome executable path for local browser mode')\n .option('--save-browser-profile-changes', 'Persist cookies/local storage back to the named browser profile when sessions close')\n .option('--json', 'Print machine-readable JSON')\n .action((host: AgentHost, opts) => {\n const valid = ['codex', 'claude', 'claude-desktop']\n if (!valid.includes(host)) throw new Error(`Unknown host \"${host}\". Use: ${valid.join(', ')}`)\n const browserMode = String(opts.browserMode ?? 'hosted') as BrowserMode\n if (!['hosted', 'local'].includes(browserMode)) throw new Error('Unknown browser mode. Use: hosted or local')\n const text = renderAgentInstall(host, {\n apiKey: opts.apiKey,\n packageSpec: opts.package,\n browserMode,\n browserProfileName: opts.browserProfile,\n browserProfileSaveChanges: opts.saveBrowserProfileChanges,\n browserExecutablePath: opts.browserExecutable,\n })\n writeOutput(opts.json ? { host, text } : text, opts.json)\n })\n\n agent.command('prompt [name]')\n .description('Print an agent prompt template.')\n .option('--json', 'Print machine-readable JSON')\n .action((name: string | undefined, opts) => {\n if (!name) {\n writeOutput(opts.json ? { prompts: listPrompts() } : listPrompts().join('\\n'), opts.json)\n return\n }\n const text = renderPrompt(name)\n writeOutput(opts.json ? { name, text } : text, opts.json)\n })\n\n const workflow = program.command('workflow').description('Run named SEO workflows.')\n workflow.command('list')\n .description('List available workflows.')\n .option('--json', 'Print machine-readable JSON')\n .action((opts) => {\n const rows = listWorkflowDefinitions()\n if (opts.json) writeOutput({ workflows: rows }, true)\n else writeOutput(rows.map(row => `${row.id}\\t${row.title}\\n ${row.description}`).join('\\n'), false)\n })\n\n workflow.command('run <id>')\n .description('Run a workflow and save local artifacts.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .option('--keyword <keyword>', 'Agent packet keyword')\n .option('--domain <domain>', 'Target domain')\n .option('--url <url>', 'Target page URL')\n .option('--location <location>', 'Target location')\n .option('--max-results <n>', 'Maximum SERP or Maps results')\n .option('--max-questions <n>', 'Maximum PAA questions')\n .option('--extract-top <n>', 'Top result pages or citation pages to extract')\n .option('--depth <n>', 'PAA expansion depth')\n .option('--no-serp', 'Skip SERP evidence for agent packet')\n .option('--no-paa', 'Skip PAA evidence for agent packet')\n .option('--query <query>', 'Business category or workflow query')\n .option('--state <state>', 'US state')\n .option('--min-pop <n>', 'Minimum city population')\n .option('--max-cities <n>', 'Maximum selected cities')\n .option('--per-city <n>', 'Maps results per city')\n .option('--concurrency <n>', 'City search concurrency')\n .option('--proxy-mode <mode>', 'Proxy mode: location, configured, or none')\n .option('--hydrate-top <n>', 'Profiles to hydrate per city for competitive audits')\n .option('--reviews <n>', 'Review cards to collect per hydrated profile')\n .option('--no-return-partial', 'Fail instead of writing partial artifacts')\n .action(async (id: string, opts) => {\n const summary = await runWorkflow(id, workflowInput(id, opts), {\n apiKey: opts.apiKey,\n apiUrl: opts.apiUrl,\n outputDir: opts.outputDir,\n })\n if (opts.json) writeOutput(summary, true)\n else {\n writeOutput([\n `${summary.title}: ${summary.status}`,\n summary.summary,\n summary.reportPath ? `Report: ${summary.reportPath}` : '',\n summary.warnings.length ? `Warnings:\\n${summary.warnings.map(w => `- ${w}`).join('\\n')}` : '',\n ].filter(Boolean).join('\\n'), false)\n }\n })\n\n const report = program.command('report').description('List and open local workflow reports.')\n report.command('list')\n .description('List recent workflow reports.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const reports = await listWorkflowReports(opts.outputDir)\n writeOutput(opts.json ? { reports } : reports.map(r => `${r.startedAt}\\t${r.workflow}\\t${r.status}\\t${r.reportPath ?? r.manifestPath}`).join('\\n'), opts.json)\n })\n report.command('path [id]')\n .description('Print a report path. Defaults to last.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id = 'last', opts) => {\n const found = await findWorkflowReport(id, opts.outputDir)\n if (!found?.reportPath) throw new Error(`No report found for \"${id}\"`)\n writeOutput(opts.json ? { path: found.reportPath, run: found } : found.reportPath, opts.json)\n })\n report.command('open [id]')\n .description('Open a report. Defaults to last.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON instead of opening')\n .action(async (id = 'last', opts) => {\n if (opts.json) {\n const found = await findWorkflowReport(id, opts.outputDir)\n if (!found?.reportPath) throw new Error(`No report found for \"${id}\"`)\n writeOutput({ path: found.reportPath, run: found }, true)\n return\n }\n const path = await openWorkflowReport(id, opts.outputDir)\n writeOutput(`Opened: ${path}`, false)\n })\n\n const schedule = program.command('schedule').description('Create and manage hosted workflow schedules.')\n addWorkflowInputOptions(schedule.command('create <workflowId>')\n .description('Create a recurring hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--name <name>', 'Schedule name')\n .option('--daily', 'Run daily')\n .option('--weekly', 'Run weekly')\n .option('--monthly', 'Run monthly')\n .option('--timezone <tz>', 'Schedule timezone', 'UTC')\n .option('--webhook <url>', 'HTTPS webhook URL')\n .option('--next-run-at <iso>', 'First run time as an ISO timestamp')\n .option('--json', 'Print machine-readable JSON'))\n .action(async (workflowId: string, opts) => {\n const result = await apiRequest('/workflows/schedules', 'POST', opts, {\n workflowId,\n name: opts.name,\n input: workflowInput(workflowId, opts),\n cadence: cadenceOpt(opts),\n timezone: opts.timezone,\n webhookUrl: opts.webhook,\n nextRunAt: opts.nextRunAt,\n })\n writeOutput(result, opts.json)\n })\n\n schedule.command('list')\n .description('List hosted workflow schedules.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ schedules: Array<Record<string, unknown>> }>('/workflows/schedules', 'GET', opts)\n if (opts.json) writeOutput(result, true)\n else writeOutput(result.schedules.map(scheduleRow => `${scheduleRow.id}\\t${scheduleRow.status}\\t${scheduleRow.workflow_id}\\t${scheduleRow.next_run_at ?? ''}`).join('\\n'), false)\n })\n\n schedule.command('pause <id>')\n .description('Pause a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'PATCH', opts, { status: 'paused' }), opts.json))\n\n schedule.command('resume <id>')\n .description('Resume a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'PATCH', opts, { status: 'active' }), opts.json))\n\n schedule.command('delete <id>')\n .description('Delete a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'DELETE', opts), opts.json))\n\n schedule.command('run <id>')\n .description('Run a hosted workflow schedule now.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}/run`, 'POST', opts, {}), opts.json))\n\n const runs = program.command('runs').description('Inspect and download hosted workflow runs.')\n runs.command('list')\n .description('List hosted workflow runs.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ runs: Array<Record<string, unknown>> }>('/workflows/runs', 'GET', opts)\n if (opts.json) writeOutput(result, true)\n else writeOutput(result.runs.map(run => `${run.id}\\t${run.status}\\t${run.workflow_id}\\t${run.queued_at}`).join('\\n'), false)\n })\n\n runs.command('status <id>')\n .description('Show a hosted workflow run.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/runs/${id}`, 'GET', opts), opts.json))\n\n runs.command('download <id>')\n .description('Download hosted workflow run artifacts.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Download directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => {\n const result = await apiRequest<{ run: { id: string; artifacts?: Array<{ id: string; label: string; path: string }> } }>(`/workflows/runs/${id}`, 'GET', opts)\n const { apiUrl, apiKey } = apiOptions(opts)\n const outDir = join(opts.outputDir ?? workflowOutputBaseDir(), 'workflow-downloads', id)\n await mkdir(outDir, { recursive: true })\n const downloaded: string[] = []\n for (const artifact of result.run.artifacts ?? []) {\n const res = await fetch(`${apiUrl}/workflows/runs/${id}/artifacts/${artifact.id}`, { headers: { 'x-api-key': apiKey } })\n if (!res.ok) throw new Error(`Failed to download ${artifact.label}: HTTP ${res.status}`)\n const file = join(outDir, basename(artifact.path))\n await writeFile(file, Buffer.from(await res.arrayBuffer()))\n downloaded.push(file)\n }\n writeOutput(opts.json ? { runId: id, files: downloaded } : downloaded.join('\\n'), opts.json)\n })\n\n return program\n}\n\nexport async function runHumanCli(argv = process.argv): Promise<void> {\n await buildHumanCli().parseAsync(argv)\n}\n","export type AgentHost = 'codex' | 'claude' | 'claude-desktop'\nexport type BrowserMode = 'hosted' | 'local'\n\nexport interface AgentConfigOptions {\n apiKey?: string\n packageSpec?: string\n browserMode?: BrowserMode\n browserProfileName?: string\n browserProfileSaveChanges?: boolean\n browserExecutablePath?: string\n}\n\nfunction apiKeyValue(options: AgentConfigOptions): string {\n return options.apiKey?.trim() || 'sk_live_your_key'\n}\n\nfunction packageSpec(options: AgentConfigOptions): string {\n return options.packageSpec?.trim() || 'mcp-scraper@latest'\n}\n\nexport function combinedNpxArgs(options: AgentConfigOptions = {}): string[] {\n return ['-y', '-p', packageSpec(options), 'mcp-scraper-combined']\n}\n\nfunction envConfig(options: AgentConfigOptions): Record<string, string> {\n const env: Record<string, string> = { MCP_SCRAPER_API_KEY: apiKeyValue(options) }\n const profileName = options.browserProfileName?.trim()\n if (options.browserMode === 'local') {\n env.MCP_SCRAPER_BROWSER_MODE = 'local'\n if (profileName) env.MCP_SCRAPER_BROWSER_PROFILE = profileName\n const executablePath = options.browserExecutablePath?.trim()\n if (executablePath) env.MCP_SCRAPER_BROWSER_EXECUTABLE = executablePath\n } else {\n if (profileName) env.BROWSER_AGENT_PROFILE_NAME = profileName\n if (options.browserProfileSaveChanges === true) env.BROWSER_AGENT_PROFILE_SAVE_CHANGES = 'true'\n }\n return env\n}\n\nfunction tomlInlineTable(value: Record<string, string>): string {\n const entries = Object.entries(value).map(([key, item]) => `${key} = ${JSON.stringify(item)}`)\n return `{ ${entries.join(', ')} }`\n}\n\nexport function renderCodexConfig(options: AgentConfigOptions = {}): string {\n return [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n `args = ${JSON.stringify(combinedNpxArgs(options))}`,\n `env = ${tomlInlineTable(envConfig(options))}`,\n ].join('\\n')\n}\n\nexport function renderClaudeCommand(options: AgentConfigOptions = {}): string {\n const env = Object.entries(envConfig(options)).map(([key, value]) => ` --env ${key}=${value}`)\n return [\n 'claude mcp add mcp-scraper --scope user',\n ...env,\n ` -- npx ${combinedNpxArgs(options).join(' ')}`,\n ].join(' \\\\\\n')\n}\n\nexport function renderClaudeDesktopConfig(options: AgentConfigOptions = {}): string {\n return JSON.stringify({\n mcpServers: {\n 'mcp-scraper': {\n command: 'npx',\n args: combinedNpxArgs(options),\n env: envConfig(options),\n },\n },\n }, null, 2)\n}\n\nexport function renderAgentInstall(host: AgentHost, options: AgentConfigOptions = {}): string {\n const restart = 'Restart the MCP client so it starts a fresh npx process.'\n if (host === 'codex') {\n return [\n '# Codex MCP config',\n renderCodexConfig(options),\n '',\n restart,\n ].join('\\n')\n }\n if (host === 'claude') {\n return [\n '# Claude Code command',\n renderClaudeCommand(options),\n '',\n restart,\n ].join('\\n')\n }\n return [\n '# Claude Desktop config',\n renderClaudeDesktopConfig(options),\n '',\n 'Desktop Extension: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n restart,\n ].join('\\n')\n}\n","import { access, mkdir, readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { PACKAGE_VERSION } from '../version.js'\nimport { combinedNpxArgs } from './agent-config.js'\n\nexport type DoctorStatus = 'pass' | 'warn' | 'fail' | 'skip'\n\nexport interface DoctorCheck {\n id: string\n label: string\n status: DoctorStatus\n detail: string\n fix?: string\n}\n\nexport interface DoctorOptions {\n apiKey?: string\n apiUrl?: string\n outputDir?: string\n fetchImpl?: typeof fetch\n}\n\nexport interface DoctorOutput {\n ok: boolean\n version: string\n npmLatest: string | null\n checks: DoctorCheck[]\n recommendedConfig: {\n command: 'npx'\n args: string[]\n env: Record<string, string>\n }\n}\n\nfunction status(ok: boolean, warn = false): DoctorStatus {\n if (ok) return 'pass'\n return warn ? 'warn' : 'fail'\n}\n\nfunction parseMajor(version: string): number {\n return Number(version.replace(/^v/, '').split('.')[0] ?? 0)\n}\n\nasync function readKeyFile(): Promise<string | null> {\n const path = process.env.MCP_SCRAPER_KEY_PATH?.trim() || join(homedir(), '.mcp-scraper-key')\n try {\n const value = (await readFile(path, 'utf8')).trim()\n return value || null\n } catch {\n return null\n }\n}\n\nasync function npmLatest(fetchImpl: typeof fetch): Promise<string | null> {\n try {\n const res = await fetchImpl('https://registry.npmjs.org/mcp-scraper/latest', {\n signal: AbortSignal.timeout(5_000),\n })\n if (!res.ok) return null\n const data = await res.json() as { version?: string }\n return data.version ?? null\n } catch {\n return null\n }\n}\n\nexport async function runDoctor(options: DoctorOptions = {}): Promise<DoctorOutput> {\n const fetchImpl = options.fetchImpl ?? fetch\n const apiUrl = (options.apiUrl ?? process.env.MCP_SCRAPER_API_URL ?? 'https://mcpscraper.dev').replace(/\\/$/, '')\n const outputDir = options.outputDir ?? process.env.MCP_SCRAPER_OUTPUT_DIR ?? join(homedir(), 'Downloads', 'mcp-scraper')\n const configuredKey = options.apiKey?.trim() || process.env.MCP_SCRAPER_API_KEY?.trim() || await readKeyFile()\n const latest = await npmLatest(fetchImpl)\n\n const checks: DoctorCheck[] = []\n const nodeMajor = parseMajor(process.version)\n checks.push({\n id: 'node',\n label: 'Node.js',\n status: status(nodeMajor >= 20),\n detail: process.version,\n fix: nodeMajor >= 20 ? undefined : 'Install Node.js 20 or newer.',\n })\n\n checks.push({\n id: 'package_version',\n label: 'Local package',\n status: latest && latest !== PACKAGE_VERSION ? 'warn' : 'pass',\n detail: latest ? `local ${PACKAGE_VERSION}, npm latest ${latest}` : `local ${PACKAGE_VERSION}, npm latest unavailable`,\n fix: latest && latest !== PACKAGE_VERSION ? 'Use mcp-scraper@latest and restart the MCP client.' : undefined,\n })\n\n checks.push({\n id: 'api_key',\n label: 'API key',\n status: configuredKey ? 'pass' : 'warn',\n detail: configuredKey ? 'configured' : 'not configured',\n fix: configuredKey ? undefined : 'Set MCP_SCRAPER_API_KEY or pass --api-key.',\n })\n\n try {\n await mkdir(outputDir, { recursive: true })\n await access(outputDir)\n checks.push({ id: 'output_dir', label: 'Output directory', status: 'pass', detail: outputDir })\n } catch (err) {\n checks.push({\n id: 'output_dir',\n label: 'Output directory',\n status: 'fail',\n detail: outputDir,\n fix: err instanceof Error ? err.message : 'Create a writable output directory.',\n })\n }\n\n if (configuredKey) {\n try {\n const res = await fetchImpl(`${apiUrl}/me`, {\n headers: { 'x-api-key': configuredKey },\n signal: AbortSignal.timeout(8_000),\n })\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: res.ok ? 'pass' : 'fail',\n detail: `${apiUrl}/me returned ${res.status}`,\n fix: res.ok ? undefined : 'Verify the API key and account status.',\n })\n } catch (err) {\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: 'fail',\n detail: err instanceof Error ? err.message : String(err),\n fix: 'Check network access and MCP_SCRAPER_API_URL.',\n })\n }\n } else {\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: 'skip',\n detail: 'skipped because no API key is configured',\n })\n }\n\n checks.push({\n id: 'mcp_config',\n label: 'MCP command',\n status: 'pass',\n detail: `npx ${combinedNpxArgs().join(' ')}`,\n fix: 'Restart the MCP client after package updates.',\n })\n\n return {\n ok: checks.every(check => check.status === 'pass' || check.status === 'skip'),\n version: PACKAGE_VERSION,\n npmLatest: latest,\n checks,\n recommendedConfig: {\n command: 'npx',\n args: combinedNpxArgs(),\n env: { MCP_SCRAPER_API_KEY: configuredKey ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key' },\n },\n }\n}\n\nexport function renderDoctor(output: DoctorOutput): string {\n const icon: Record<DoctorStatus, string> = { pass: 'PASS', warn: 'WARN', fail: 'FAIL', skip: 'SKIP' }\n const lines = [\n `mcp-scraper doctor v${output.version}`,\n '',\n ...output.checks.map(check => {\n const fix = check.fix ? `\\n Fix: ${check.fix}` : ''\n return `[${icon[check.status]}] ${check.label}: ${check.detail}${fix}`\n }),\n '',\n `Recommended MCP command: npx ${output.recommendedConfig.args.join(' ')}`,\n ]\n return lines.join('\\n')\n}\n\n","export const AGENT_PROMPTS: Record<string, string> = {\n 'agent-packet': [\n '# MCP Scraper Agent Packet Prompt',\n '',\n 'Use MCP Scraper as the evidence layer. Run the agent-packet workflow for the target keyword/domain, then treat `evidence.json`, `sources.csv`, and `competitors.csv` as source of truth.',\n '',\n 'Do not invent citations. If a recommendation is not supported by the packet, mark it as an assumption. Turn the evidence into a concise SEO brief, an implementation task list, and content recommendations tied to source rows.',\n ].join('\\n'),\n 'local-competitive-audit': [\n '# MCP Scraper Local Competitive Audit Prompt',\n '',\n 'Run the local-competitive-audit workflow for the niche and markets. Use the city summary, competitor CSV, and review-insight CSV to identify market difficulty, review themes, GBP category patterns, and weak competitors.',\n '',\n 'Ground recommendations in Maps rank position, review count, star rating, categories, profile details, and review topics. Do not overstate heuristic opportunity scores.',\n ].join('\\n'),\n 'directory-workflow': [\n '# MCP Scraper Directory Workflow Prompt',\n '',\n 'Use directory_workflow when the user wants cities selected by population and Google Maps candidates per city. Keep query and location separate. Preserve result_position, source_location, review stars/count, categories, and profile URLs for downstream CSV or directory use.',\n ].join('\\n'),\n 'map-comparison': [\n '# MCP Scraper Maps Comparison Prompt',\n '',\n 'Run the map-comparison workflow when the user wants to compare local Maps competitors in a city or across selected markets. Use `maps-results.csv`, `map-comparison.csv`, and `profile-insights.csv` as source of truth.',\n '',\n 'Ground recommendations in result_position, review_stars, review_count, category, website presence, review topics, and profile attributes. Treat review gaps and missing websites as opportunity signals, not guaranteed ranking factors.',\n ].join('\\n'),\n 'serp-comparison': [\n '# MCP Scraper SERP Comparison Prompt',\n '',\n 'Run the serp-comparison workflow when the user wants to know why competitors outrank a page or what the SERP rewards. Use organic results, extracted page headings, PAA questions, and AI Overview citations before making recommendations.',\n '',\n 'Tie each recommendation to `content-gaps.csv`, `page-comparison.csv`, `paa-questions.csv`, or `ai-overview-citations.csv`. Do not invent missing sections or citations.',\n ].join('\\n'),\n 'paa-expansion-brief': [\n '# MCP Scraper PAA Expansion Brief Prompt',\n '',\n 'Run the paa-expansion-brief workflow when the user wants to figure out what to write from People Also Ask expansion. Use `section-map.csv` to structure the brief and `paa-questions.csv` for exact customer-language headings.',\n '',\n 'Answer the highest-priority questions directly, preserve source URLs when present, and separate evidence-backed sections from assumptions.',\n ].join('\\n'),\n 'ai-overview-language': [\n '# MCP Scraper AI Overview Language Prompt',\n '',\n 'Run the ai-overview-language workflow when the user wants to know how to phrase content for AI Overview inclusion. Use `claim-patterns.csv`, `language-guidance.csv`, `ai-overview-citations.csv`, and PAA follow-ups as evidence.',\n '',\n 'Recommend concise answer blocks, criteria/step language, citation hooks, and follow-up sections. Do not claim the target will be cited; frame the output as evidence-based language guidance.',\n ].join('\\n'),\n 'ai-citation-monitor': [\n '# MCP Scraper AI Citation Monitor Prompt',\n '',\n 'Use search_serp and harvest_paa to check whether the target brand/domain appears in AI Overview citations, organic results, People Also Ask sources, local pack, forums, and videos. Save evidence before summarizing trends or gaps.',\n ].join('\\n'),\n 'serp-brief': [\n '# MCP Scraper SERP Brief Prompt',\n '',\n 'Use live SERP, PAA, AI Overview, forum, video, and source evidence to create a writer brief. Tie each recommended section to evidence rows and identify missing proof, entities, comparisons, and customer questions.',\n ].join('\\n'),\n}\n\nexport function listPrompts(): string[] {\n return Object.keys(AGENT_PROMPTS).sort()\n}\n\nexport function renderPrompt(name: string): string {\n const prompt = AGENT_PROMPTS[name]\n if (!prompt) throw new Error(`Unknown prompt \"${name}\". Available: ${listPrompts().join(', ')}`)\n return prompt\n}\n","#!/usr/bin/env node\nimport { runHumanCli } from '../src/cli/human-cli.js'\n\nrunHumanCli().catch((err) => {\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n})\n\n"],"mappings":"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","names":["mkdir","join","join","mkdir"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/human-cli.ts","../../src/cli/agent-config.ts","../../src/cli/doctor.ts","../../src/cli/prompts.ts","../../bin/mcp-scraper-cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { spawn } from 'node:child_process'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { basename, join } from 'node:path'\nimport { PACKAGE_VERSION } from '../version.js'\nimport { listLocalChromeProfiles } from '../lib/chrome-profiles.js'\nimport { importChromeProfile, syncImportedChromeProfile } from '../lib/local-browser-profiles.js'\nimport {\n claudeMcpAddArgs,\n claudeMcpRemoveArgs,\n normalizeAgentHost,\n renderAgentInstall,\n type AgentHost,\n type BrowserMode,\n} from './agent-config.js'\nimport { renderDoctor, runDoctor } from './doctor.js'\nimport { listPrompts, renderPrompt } from './prompts.js'\nimport { workflowOutputBaseDir } from '../workflows/artifact-writer.js'\nimport { findWorkflowReport, listWorkflowDefinitions, listWorkflowReports, openWorkflowReport, runWorkflow } from '../workflows/registry.js'\n\nfunction numberOpt(value: unknown): number | undefined {\n if (value === undefined || value === null || value === '') return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nfunction booleanOpt(value: unknown): boolean | undefined {\n if (value === undefined) return undefined\n if (typeof value === 'boolean') return value\n if (value === 'true') return true\n if (value === 'false') return false\n return undefined\n}\n\nfunction compactInput(input: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined))\n}\n\nfunction workflowInput(id: string, opts: Record<string, unknown>): Record<string, unknown> {\n if (id === 'agent-packet' || id === 'serp-comparison' || id === 'ai-overview-language') {\n return compactInput({\n keyword: opts.keyword,\n domain: opts.domain,\n url: opts.url,\n location: opts.location,\n maxResults: numberOpt(opts.maxResults),\n maxQuestions: numberOpt(opts.maxQuestions),\n extractTop: numberOpt(opts.extractTop),\n includeSerp: opts.serp === false ? false : undefined,\n includePaa: opts.paa === false ? false : undefined,\n includeAiOverview: booleanOpt(opts.includeAiOverview),\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n if (id === 'paa-expansion-brief') {\n return compactInput({\n keyword: opts.keyword,\n location: opts.location,\n maxQuestions: numberOpt(opts.maxQuestions),\n depth: numberOpt(opts.depth),\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n if (id === 'directory' || id === 'local-competitive-audit' || id === 'map-comparison') {\n return compactInput({\n query: opts.query,\n location: opts.location,\n state: opts.state,\n minPopulation: numberOpt(opts.minPop ?? opts.minPopulation),\n maxCities: numberOpt(opts.maxCities),\n maxResultsPerCity: numberOpt(opts.perCity ?? opts.maxResultsPerCity ?? opts.maxResults),\n concurrency: numberOpt(opts.concurrency),\n proxyMode: opts.proxyMode,\n hydrateTop: id === 'local-competitive-audit' || id === 'map-comparison' ? numberOpt(opts.hydrateTop) : undefined,\n maxReviews: id === 'local-competitive-audit' || id === 'map-comparison' ? numberOpt(opts.reviews ?? opts.maxReviews) : undefined,\n returnPartial: opts.returnPartial === false ? false : undefined,\n })\n }\n\n return compactInput(opts)\n}\n\nfunction writeOutput(data: unknown, json: boolean | undefined): void {\n if (json) {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n } else if (typeof data === 'string') {\n process.stdout.write(`${data}\\n`)\n } else {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n }\n}\n\nfunction maskSecrets(value: string): string {\n return value.replace(/sk_[A-Za-z0-9_-]+/g, 'sk_***')\n}\n\nfunction runLocalCommand(command: string, args: string[]): Promise<{ code: number; stdout: string; stderr: string }> {\n return new Promise((resolve) => {\n const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'pipe'] })\n const stdout: Buffer[] = []\n const stderr: Buffer[] = []\n let settled = false\n const done = (result: { code: number; stdout: string; stderr: string }) => {\n if (settled) return\n settled = true\n resolve(result)\n }\n child.stdout.on('data', chunk => stdout.push(Buffer.from(chunk)))\n child.stderr.on('data', chunk => stderr.push(Buffer.from(chunk)))\n child.on('error', err => {\n done({ code: 127, stdout: '', stderr: err.message })\n })\n child.on('close', code => {\n done({\n code: typeof code === 'number' ? code : 1,\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n })\n })\n })\n}\n\nfunction cadenceOpt(opts: Record<string, unknown>): 'daily' | 'weekly' | 'monthly' {\n if (opts.daily) return 'daily'\n if (opts.monthly) return 'monthly'\n return 'weekly'\n}\n\nfunction apiOptions(opts: Record<string, unknown>): { apiUrl: string; apiKey: string } {\n const apiKey = String(opts.apiKey ?? process.env.MCP_SCRAPER_API_KEY ?? '').trim()\n if (!apiKey) throw new Error('MCP_SCRAPER_API_KEY is required. Pass --api-key or set the environment variable.')\n return {\n apiUrl: String(opts.apiUrl ?? process.env.MCP_SCRAPER_API_URL ?? 'https://mcpscraper.dev').replace(/\\/$/, ''),\n apiKey,\n }\n}\n\nfunction openExternalUrl(url: string): boolean {\n const command = process.platform === 'darwin'\n ? 'open'\n : process.platform === 'win32'\n ? 'cmd'\n : 'xdg-open'\n const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]\n try {\n const child = spawn(command, args, { detached: true, stdio: 'ignore' })\n child.unref()\n return true\n } catch {\n return false\n }\n}\n\nasync function apiRequest<T>(path: string, method: string, opts: Record<string, unknown>, body?: unknown): Promise<T> {\n const { apiUrl, apiKey } = apiOptions(opts)\n const res = await fetch(`${apiUrl}${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey,\n },\n body: body == null ? undefined : JSON.stringify(body),\n })\n const data = await res.json().catch(() => ({}))\n if (!res.ok) {\n const message = typeof (data as { error?: unknown }).error === 'string'\n ? (data as { error: string }).error\n : `API request failed with ${res.status}`\n throw new Error(message)\n }\n return data as T\n}\n\nfunction addWorkflowInputOptions(command: Command): Command {\n return command\n .option('--keyword <keyword>', 'Agent packet keyword')\n .option('--domain <domain>', 'Target domain')\n .option('--url <url>', 'Target page URL')\n .option('--location <location>', 'Target location')\n .option('--max-results <n>', 'Maximum SERP or Maps results')\n .option('--max-questions <n>', 'Maximum PAA questions')\n .option('--extract-top <n>', 'Top result pages or citation pages to extract')\n .option('--depth <n>', 'PAA expansion depth')\n .option('--no-serp', 'Skip SERP evidence for agent packet')\n .option('--no-paa', 'Skip PAA evidence for agent packet')\n .option('--query <query>', 'Business category or workflow query')\n .option('--state <state>', 'US state')\n .option('--min-pop <n>', 'Minimum city population')\n .option('--max-cities <n>', 'Maximum selected cities')\n .option('--per-city <n>', 'Maps results per city')\n .option('--concurrency <n>', 'City search concurrency')\n .option('--proxy-mode <mode>', 'Proxy mode: location, configured, or none')\n .option('--hydrate-top <n>', 'Profiles to hydrate per city for competitive audits')\n .option('--reviews <n>', 'Review cards to collect per hydrated profile')\n .option('--no-return-partial', 'Fail instead of writing partial artifacts')\n}\n\nexport function buildHumanCli(): Command {\n const program = new Command()\n program\n .name('mcp-scraper-cli')\n .description('Human CLI for MCP Scraper setup, workflows, reports, and agent-ready SEO artifacts.')\n .version(PACKAGE_VERSION)\n\n program.command('doctor')\n .description('Check local setup, API key, output directory, package version, and recommended MCP config.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Output directory to test')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const output = await runDoctor({ apiKey: opts.apiKey, apiUrl: opts.apiUrl, outputDir: opts.outputDir })\n writeOutput(opts.json ? output : renderDoctor(output), opts.json)\n if (!output.ok) process.exitCode = 1\n })\n\n const billing = program.command('billing').description('Inspect billing and start checkout flows.')\n const billingConcurrency = billing.command('concurrency').description('Manage MCP Scraper concurrency slots.')\n\n billingConcurrency.command('info')\n .description('Show current concurrency limit and extra-slot price.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ concurrency: Record<string, unknown> }>('/billing/credits', 'POST', opts, {})\n if (opts.json) writeOutput(result.concurrency, true)\n else {\n const upgrade = result.concurrency?.upgrade as Record<string, unknown> | undefined\n writeOutput([\n `Current limit: ${result.concurrency?.current_limit ?? 'unknown'} concurrent operations`,\n `Extra slots: ${result.concurrency?.current_extra_slots ?? 'unknown'}`,\n `Extra concurrency slot: ${upgrade?.price_label ?? '$5/month'}`,\n `Upgrade command: ${upgrade?.terminal_command ?? 'mcp-scraper-cli billing concurrency checkout'}`,\n ].join('\\n'), false)\n }\n })\n\n billingConcurrency.command('checkout')\n .description('Create a hosted Stripe checkout for one extra concurrency slot.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .option('--no-open', 'Print the checkout URL without opening a browser')\n .action(async (opts) => {\n const result = await apiRequest<{ checkout_url: string; price?: { price_label?: string }; next_step?: string }>('/billing/concurrency/terminal-checkout', 'POST', opts, {})\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n const opened = opts.open !== false && openExternalUrl(result.checkout_url)\n writeOutput([\n `Extra concurrency slot: ${result.price?.price_label ?? '$5/month'}`,\n opened ? `Opened checkout: ${result.checkout_url}` : `Checkout URL: ${result.checkout_url}`,\n result.next_step ?? 'Complete checkout, then retry the MCP request.',\n ].join('\\n'), false)\n })\n\n const browser = program.command('browser').description('Inspect and manage browser-agent profile setup helpers.')\n browser.command('profiles')\n .description('List local Chrome profiles and suggested managed browser profile names.')\n .option('--email <email>', 'Filter by Chrome account email or displayed profile name')\n .option('--user-data-dir <path>', 'Chrome user data directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const profiles = await listLocalChromeProfiles(opts.userDataDir, opts.email)\n if (opts.json) {\n writeOutput({ profiles }, true)\n return\n }\n if (!profiles.length) {\n writeOutput('No matching Chrome profiles found.', false)\n return\n }\n const lines = [\n 'Local Chrome profiles:',\n ...profiles.map(profile => [\n `${profile.email || '(no email)'}\\t${profile.chromeProfileDirectory}\\t${profile.displayName}`,\n ` suggested profile name: ${profile.recommendedKernelProfileName}`,\n ` local Chrome path: ${profile.chromeProfilePath}`,\n ].join('\\n')),\n '',\n 'To clone a real local Chrome profile for MCP local browser mode:',\n ' mcp-scraper-cli browser import-chrome --email you@example.com --name <suggested profile name>',\n 'Then apply Claude Code config with:',\n ' MCP_SCRAPER_API_KEY=sk_live_your_key mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile <suggested profile name>',\n ]\n writeOutput(lines.join('\\n'), false)\n })\n\n browser.command('import-chrome')\n .description('Clone a local Chrome profile into MCP Scraper managed local browser storage.')\n .option('--email <email>', 'Chrome account email or displayed profile name to import')\n .option('--name <name>', 'Managed MCP Scraper browser profile name')\n .option('--chrome-profile <directory>', 'Chrome profile directory, for example Default or Profile 1')\n .option('--user-data-dir <path>', 'Source Chrome user data directory')\n .option('--output-dir <path>', 'Managed profile base directory')\n .option('--browser-executable <path>', 'Chrome executable path for local launches')\n .option('--overwrite', 'Overwrite an existing managed profile clone')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await importChromeProfile({\n email: opts.email,\n name: opts.name,\n chromeProfileDirectory: opts.chromeProfile,\n sourceUserDataDir: opts.userDataDir,\n outputDir: opts.outputDir,\n browserExecutablePath: opts.browserExecutable,\n overwrite: opts.overwrite,\n })\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n writeOutput([\n `Imported Chrome profile: ${result.profile.name}`,\n `Source: ${result.sourceProfile.email || result.sourceProfile.displayName || result.sourceProfile.chromeProfileDirectory} (${result.sourceProfile.chromeProfileDirectory})`,\n `Managed user data dir: ${result.profile.userDataDir}`,\n '',\n 'Install/config command:',\n ` MCP_SCRAPER_API_KEY=sk_live_your_key mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile ${result.profile.name}`,\n '',\n 'Fully exit Claude Code and start a new Claude terminal after applying config. Re-run sync-profile after signing into new sites in normal Chrome.',\n ].join('\\n'), false)\n })\n\n browser.command('sync-profile <name>')\n .description('Refresh a managed local browser profile from its recorded source Chrome profile.')\n .option('--output-dir <path>', 'Managed profile base directory')\n .option('--browser-executable <path>', 'Chrome executable path for local launches')\n .option('--json', 'Print machine-readable JSON')\n .action(async (name: string, opts) => {\n const result = await syncImportedChromeProfile(name, {\n outputDir: opts.outputDir,\n browserExecutablePath: opts.browserExecutable,\n })\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n writeOutput([\n `Synced Chrome profile: ${result.profile.name}`,\n `Source: ${result.sourceProfile.email || result.sourceProfile.displayName || result.sourceProfile.chromeProfileDirectory} (${result.sourceProfile.chromeProfileDirectory})`,\n `Managed user data dir: ${result.profile.userDataDir}`,\n 'Restart any local browser sessions that were using this profile.',\n ].join('\\n'), false)\n })\n\n const agent = program.command('agent').description('Generate AI-agent install configs and workflow prompts.')\n agent.command('install <host>')\n .description('Print or apply install/config instructions for codex, claude/claude-code, or claude-desktop.')\n .option('--api-key <key>', 'API key to place in generated config')\n .option('--package <spec>', 'npm package spec', 'mcp-scraper@latest')\n .option('--browser-mode <mode>', 'Browser mode: hosted or local', 'hosted')\n .option('--browser-profile <name>', 'Default browser profile for browser_open sessions. In local mode this is a managed MCP Scraper profile name; in hosted mode it is a Kernel profile name.')\n .option('--browser-executable <path>', 'Chrome executable path for local browser mode')\n .option('--save-browser-profile-changes', 'Persist cookies/local storage back to the named browser profile when sessions close')\n .option('--apply', 'Apply the config to the local client when supported. For Claude Code, this upserts the user-scope mcp-scraper server.')\n .option('--json', 'Print machine-readable JSON')\n .action(async (hostInput: AgentHost, opts) => {\n const host = normalizeAgentHost(hostInput)\n const browserMode = String(opts.browserMode ?? 'hosted') as BrowserMode\n if (!['hosted', 'local'].includes(browserMode)) throw new Error('Unknown browser mode. Use: hosted or local')\n const apiKey = opts.apiKey ?? process.env.MCP_SCRAPER_API_KEY\n if (opts.apply) {\n if (host !== 'claude') throw new Error('--apply is currently supported for Claude Code only. Use host \"claude\" or \"claude-code\".')\n if (!apiKey?.trim()) {\n throw new Error('MCP_SCRAPER_API_KEY is required for --apply. Set it in the environment or pass --api-key.')\n }\n\n const configOptions = {\n apiKey,\n packageSpec: opts.package,\n browserMode,\n browserProfileName: opts.browserProfile,\n browserProfileSaveChanges: opts.saveBrowserProfileChanges,\n browserExecutablePath: opts.browserExecutable,\n }\n const remove = await runLocalCommand('claude', claudeMcpRemoveArgs())\n const add = await runLocalCommand('claude', claudeMcpAddArgs(configOptions))\n if (add.code !== 0) {\n const reason = maskSecrets([add.stderr, add.stdout].filter(Boolean).join('\\n').trim())\n throw new Error([\n 'Claude Code MCP registration failed.',\n reason || 'No error output returned.',\n 'Make sure Claude Code is installed and the `claude` command is on PATH.',\n ].join('\\n'))\n }\n const list = await runLocalCommand('claude', ['mcp', 'list'])\n const result = {\n host: 'claude',\n applied: true,\n replacedExisting: remove.code === 0,\n command: 'npx',\n args: ['-y', '-p', opts.package, 'mcp-scraper-combined'],\n nextStep: 'Fully exit Claude Code, start a new Claude terminal, then run: claude mcp list',\n list: maskSecrets([list.stdout, list.stderr].filter(Boolean).join('\\n').trim()),\n }\n if (opts.json) {\n writeOutput(result, true)\n return\n }\n writeOutput([\n 'Applied Claude Code MCP config: mcp-scraper',\n remove.code === 0 ? 'Replaced existing mcp-scraper entry.' : 'No existing mcp-scraper entry found; added a new one.',\n 'Command: npx -y -p ' + opts.package + ' mcp-scraper-combined',\n browserMode === 'local' && opts.browserProfile ? `Local browser profile: ${opts.browserProfile}` : '',\n '',\n 'Next step: fully exit Claude Code, start a new Claude terminal, then run:',\n ' claude mcp list',\n '',\n result.list ? `Current Claude MCP list:\\n${result.list}` : '',\n ].filter(Boolean).join('\\n'), false)\n return\n }\n const text = renderAgentInstall(host, {\n apiKey: opts.apiKey,\n packageSpec: opts.package,\n browserMode,\n browserProfileName: opts.browserProfile,\n browserProfileSaveChanges: opts.saveBrowserProfileChanges,\n browserExecutablePath: opts.browserExecutable,\n })\n writeOutput(opts.json ? { host, text } : text, opts.json)\n })\n\n agent.command('prompt [name]')\n .description('Print an agent prompt template.')\n .option('--json', 'Print machine-readable JSON')\n .action((name: string | undefined, opts) => {\n if (!name) {\n writeOutput(opts.json ? { prompts: listPrompts() } : listPrompts().join('\\n'), opts.json)\n return\n }\n const text = renderPrompt(name)\n writeOutput(opts.json ? { name, text } : text, opts.json)\n })\n\n const workflow = program.command('workflow').description('Run named SEO workflows.')\n workflow.command('list')\n .description('List available workflows.')\n .option('--json', 'Print machine-readable JSON')\n .action((opts) => {\n const rows = listWorkflowDefinitions()\n if (opts.json) writeOutput({ workflows: rows }, true)\n else writeOutput(rows.map(row => `${row.id}\\t${row.title}\\n ${row.description}`).join('\\n'), false)\n })\n\n workflow.command('run <id>')\n .description('Run a workflow and save local artifacts.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .option('--keyword <keyword>', 'Agent packet keyword')\n .option('--domain <domain>', 'Target domain')\n .option('--url <url>', 'Target page URL')\n .option('--location <location>', 'Target location')\n .option('--max-results <n>', 'Maximum SERP or Maps results')\n .option('--max-questions <n>', 'Maximum PAA questions')\n .option('--extract-top <n>', 'Top result pages or citation pages to extract')\n .option('--depth <n>', 'PAA expansion depth')\n .option('--no-serp', 'Skip SERP evidence for agent packet')\n .option('--no-paa', 'Skip PAA evidence for agent packet')\n .option('--query <query>', 'Business category or workflow query')\n .option('--state <state>', 'US state')\n .option('--min-pop <n>', 'Minimum city population')\n .option('--max-cities <n>', 'Maximum selected cities')\n .option('--per-city <n>', 'Maps results per city')\n .option('--concurrency <n>', 'City search concurrency')\n .option('--proxy-mode <mode>', 'Proxy mode: location, configured, or none')\n .option('--hydrate-top <n>', 'Profiles to hydrate per city for competitive audits')\n .option('--reviews <n>', 'Review cards to collect per hydrated profile')\n .option('--no-return-partial', 'Fail instead of writing partial artifacts')\n .action(async (id: string, opts) => {\n const summary = await runWorkflow(id, workflowInput(id, opts), {\n apiKey: opts.apiKey,\n apiUrl: opts.apiUrl,\n outputDir: opts.outputDir,\n })\n if (opts.json) writeOutput(summary, true)\n else {\n writeOutput([\n `${summary.title}: ${summary.status}`,\n summary.summary,\n summary.reportPath ? `Report: ${summary.reportPath}` : '',\n summary.warnings.length ? `Warnings:\\n${summary.warnings.map(w => `- ${w}`).join('\\n')}` : '',\n ].filter(Boolean).join('\\n'), false)\n }\n })\n\n const report = program.command('report').description('List and open local workflow reports.')\n report.command('list')\n .description('List recent workflow reports.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const reports = await listWorkflowReports(opts.outputDir)\n writeOutput(opts.json ? { reports } : reports.map(r => `${r.startedAt}\\t${r.workflow}\\t${r.status}\\t${r.reportPath ?? r.manifestPath}`).join('\\n'), opts.json)\n })\n report.command('path [id]')\n .description('Print a report path. Defaults to last.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id = 'last', opts) => {\n const found = await findWorkflowReport(id, opts.outputDir)\n if (!found?.reportPath) throw new Error(`No report found for \"${id}\"`)\n writeOutput(opts.json ? { path: found.reportPath, run: found } : found.reportPath, opts.json)\n })\n report.command('open [id]')\n .description('Open a report. Defaults to last.')\n .option('--output-dir <path>', 'Workflow output directory')\n .option('--json', 'Print machine-readable JSON instead of opening')\n .action(async (id = 'last', opts) => {\n if (opts.json) {\n const found = await findWorkflowReport(id, opts.outputDir)\n if (!found?.reportPath) throw new Error(`No report found for \"${id}\"`)\n writeOutput({ path: found.reportPath, run: found }, true)\n return\n }\n const path = await openWorkflowReport(id, opts.outputDir)\n writeOutput(`Opened: ${path}`, false)\n })\n\n const schedule = program.command('schedule').description('Create and manage hosted workflow schedules.')\n addWorkflowInputOptions(schedule.command('create <workflowId>')\n .description('Create a recurring hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--name <name>', 'Schedule name')\n .option('--daily', 'Run daily')\n .option('--weekly', 'Run weekly')\n .option('--monthly', 'Run monthly')\n .option('--timezone <tz>', 'Schedule timezone', 'UTC')\n .option('--webhook <url>', 'HTTPS webhook URL')\n .option('--next-run-at <iso>', 'First run time as an ISO timestamp')\n .option('--json', 'Print machine-readable JSON'))\n .action(async (workflowId: string, opts) => {\n const result = await apiRequest('/workflows/schedules', 'POST', opts, {\n workflowId,\n name: opts.name,\n input: workflowInput(workflowId, opts),\n cadence: cadenceOpt(opts),\n timezone: opts.timezone,\n webhookUrl: opts.webhook,\n nextRunAt: opts.nextRunAt,\n })\n writeOutput(result, opts.json)\n })\n\n schedule.command('list')\n .description('List hosted workflow schedules.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ schedules: Array<Record<string, unknown>> }>('/workflows/schedules', 'GET', opts)\n if (opts.json) writeOutput(result, true)\n else writeOutput(result.schedules.map(scheduleRow => `${scheduleRow.id}\\t${scheduleRow.status}\\t${scheduleRow.workflow_id}\\t${scheduleRow.next_run_at ?? ''}`).join('\\n'), false)\n })\n\n schedule.command('pause <id>')\n .description('Pause a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'PATCH', opts, { status: 'paused' }), opts.json))\n\n schedule.command('resume <id>')\n .description('Resume a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'PATCH', opts, { status: 'active' }), opts.json))\n\n schedule.command('delete <id>')\n .description('Delete a hosted workflow schedule.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}`, 'DELETE', opts), opts.json))\n\n schedule.command('run <id>')\n .description('Run a hosted workflow schedule now.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/schedules/${id}/run`, 'POST', opts, {}), opts.json))\n\n const runs = program.command('runs').description('Inspect and download hosted workflow runs.')\n runs.command('list')\n .description('List hosted workflow runs.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (opts) => {\n const result = await apiRequest<{ runs: Array<Record<string, unknown>> }>('/workflows/runs', 'GET', opts)\n if (opts.json) writeOutput(result, true)\n else writeOutput(result.runs.map(run => `${run.id}\\t${run.status}\\t${run.workflow_id}\\t${run.queued_at}`).join('\\n'), false)\n })\n\n runs.command('status <id>')\n .description('Show a hosted workflow run.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => writeOutput(await apiRequest(`/workflows/runs/${id}`, 'GET', opts), opts.json))\n\n runs.command('download <id>')\n .description('Download hosted workflow run artifacts.')\n .option('--api-key <key>', 'MCP Scraper API key')\n .option('--api-url <url>', 'MCP Scraper API URL', 'https://mcpscraper.dev')\n .option('--output-dir <path>', 'Download directory')\n .option('--json', 'Print machine-readable JSON')\n .action(async (id: string, opts) => {\n const result = await apiRequest<{ run: { id: string; artifacts?: Array<{ id: string; label: string; path: string }> } }>(`/workflows/runs/${id}`, 'GET', opts)\n const { apiUrl, apiKey } = apiOptions(opts)\n const outDir = join(opts.outputDir ?? workflowOutputBaseDir(), 'workflow-downloads', id)\n await mkdir(outDir, { recursive: true })\n const downloaded: string[] = []\n for (const artifact of result.run.artifacts ?? []) {\n const res = await fetch(`${apiUrl}/workflows/runs/${id}/artifacts/${artifact.id}`, { headers: { 'x-api-key': apiKey } })\n if (!res.ok) throw new Error(`Failed to download ${artifact.label}: HTTP ${res.status}`)\n const file = join(outDir, basename(artifact.path))\n await writeFile(file, Buffer.from(await res.arrayBuffer()))\n downloaded.push(file)\n }\n writeOutput(opts.json ? { runId: id, files: downloaded } : downloaded.join('\\n'), opts.json)\n })\n\n return program\n}\n\nexport async function runHumanCli(argv = process.argv): Promise<void> {\n await buildHumanCli().parseAsync(argv)\n}\n","export type AgentHost = 'codex' | 'claude' | 'claude-code' | 'claude-desktop'\nexport type BrowserMode = 'hosted' | 'local'\n\nexport interface AgentConfigOptions {\n apiKey?: string\n packageSpec?: string\n browserMode?: BrowserMode\n browserProfileName?: string\n browserProfileSaveChanges?: boolean\n browserExecutablePath?: string\n}\n\nfunction apiKeyValue(options: AgentConfigOptions): string {\n return options.apiKey?.trim() || 'sk_live_your_key'\n}\n\nfunction packageSpec(options: AgentConfigOptions): string {\n return options.packageSpec?.trim() || 'mcp-scraper@latest'\n}\n\nexport function combinedNpxArgs(options: AgentConfigOptions = {}): string[] {\n return ['-y', '-p', packageSpec(options), 'mcp-scraper-combined']\n}\n\nfunction envConfig(options: AgentConfigOptions): Record<string, string> {\n const env: Record<string, string> = { MCP_SCRAPER_API_KEY: apiKeyValue(options) }\n const profileName = options.browserProfileName?.trim()\n if (options.browserMode === 'local') {\n env.MCP_SCRAPER_BROWSER_MODE = 'local'\n if (profileName) env.MCP_SCRAPER_BROWSER_PROFILE = profileName\n const executablePath = options.browserExecutablePath?.trim()\n if (executablePath) env.MCP_SCRAPER_BROWSER_EXECUTABLE = executablePath\n } else {\n if (profileName) env.BROWSER_AGENT_PROFILE_NAME = profileName\n if (options.browserProfileSaveChanges === true) env.BROWSER_AGENT_PROFILE_SAVE_CHANGES = 'true'\n }\n return env\n}\n\nfunction tomlInlineTable(value: Record<string, string>): string {\n const entries = Object.entries(value).map(([key, item]) => `${key} = ${JSON.stringify(item)}`)\n return `{ ${entries.join(', ')} }`\n}\n\nexport function renderCodexConfig(options: AgentConfigOptions = {}): string {\n return [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n `args = ${JSON.stringify(combinedNpxArgs(options))}`,\n `env = ${tomlInlineTable(envConfig(options))}`,\n ].join('\\n')\n}\n\nexport function renderClaudeCommand(options: AgentConfigOptions = {}): string {\n const env = Object.entries(envConfig(options)).map(([key, value]) => ` --env ${key}=${value}`)\n return [\n 'claude mcp add mcp-scraper --scope user',\n ...env,\n ` -- npx ${combinedNpxArgs(options).join(' ')}`,\n ].join(' \\\\\\n')\n}\n\nexport function claudeMcpRemoveArgs(): string[] {\n return ['mcp', 'remove', 'mcp-scraper', '-s', 'user']\n}\n\nexport function claudeMcpAddArgs(options: AgentConfigOptions = {}): string[] {\n const args = ['mcp', 'add', 'mcp-scraper', '--scope', 'user']\n for (const [key, value] of Object.entries(envConfig(options))) {\n args.push('--env', `${key}=${value}`)\n }\n args.push('--', 'npx', ...combinedNpxArgs(options))\n return args\n}\n\nexport function normalizeAgentHost(host: string): AgentHost {\n if (host === 'claude-code') return 'claude'\n if (host === 'claude' || host === 'codex' || host === 'claude-desktop') return host\n throw new Error('Unknown host \"' + host + '\". Use: codex, claude, claude-code, or claude-desktop')\n}\n\nexport function renderClaudeDesktopConfig(options: AgentConfigOptions = {}): string {\n return JSON.stringify({\n mcpServers: {\n 'mcp-scraper': {\n command: 'npx',\n args: combinedNpxArgs(options),\n env: envConfig(options),\n },\n },\n }, null, 2)\n}\n\nexport function renderAgentInstall(host: AgentHost, options: AgentConfigOptions = {}): string {\n const normalizedHost = normalizeAgentHost(host)\n const restart = 'Restart the MCP client so it starts a fresh npx process.'\n const applyCommand = `MCP_SCRAPER_API_KEY=${apiKeyValue(options)} npx -y -p mcp-scraper@latest mcp-scraper-cli agent install claude --apply`\n if (normalizedHost === 'codex') {\n return [\n '# Codex MCP config',\n renderCodexConfig(options),\n '',\n restart,\n ].join('\\n')\n }\n if (normalizedHost === 'claude') {\n return [\n '# Claude Code command',\n renderClaudeCommand(options),\n '',\n '# One-command Claude Code setup',\n applyCommand,\n '',\n restart,\n ].join('\\n')\n }\n return [\n '# Claude Desktop config',\n renderClaudeDesktopConfig(options),\n '',\n 'Desktop Extension: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n restart,\n ].join('\\n')\n}\n","import { access, mkdir, readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { PACKAGE_VERSION } from '../version.js'\nimport { combinedNpxArgs } from './agent-config.js'\n\nexport type DoctorStatus = 'pass' | 'warn' | 'fail' | 'skip'\n\nexport interface DoctorCheck {\n id: string\n label: string\n status: DoctorStatus\n detail: string\n fix?: string\n}\n\nexport interface DoctorOptions {\n apiKey?: string\n apiUrl?: string\n outputDir?: string\n fetchImpl?: typeof fetch\n}\n\nexport interface DoctorOutput {\n ok: boolean\n version: string\n npmLatest: string | null\n checks: DoctorCheck[]\n recommendedConfig: {\n command: 'npx'\n args: string[]\n env: Record<string, string>\n }\n}\n\nfunction status(ok: boolean, warn = false): DoctorStatus {\n if (ok) return 'pass'\n return warn ? 'warn' : 'fail'\n}\n\nfunction parseMajor(version: string): number {\n return Number(version.replace(/^v/, '').split('.')[0] ?? 0)\n}\n\nasync function readKeyFile(): Promise<string | null> {\n const path = process.env.MCP_SCRAPER_KEY_PATH?.trim() || join(homedir(), '.mcp-scraper-key')\n try {\n const value = (await readFile(path, 'utf8')).trim()\n return value || null\n } catch {\n return null\n }\n}\n\nasync function npmLatest(fetchImpl: typeof fetch): Promise<string | null> {\n try {\n const res = await fetchImpl('https://registry.npmjs.org/mcp-scraper/latest', {\n signal: AbortSignal.timeout(5_000),\n })\n if (!res.ok) return null\n const data = await res.json() as { version?: string }\n return data.version ?? null\n } catch {\n return null\n }\n}\n\nexport async function runDoctor(options: DoctorOptions = {}): Promise<DoctorOutput> {\n const fetchImpl = options.fetchImpl ?? fetch\n const apiUrl = (options.apiUrl ?? process.env.MCP_SCRAPER_API_URL ?? 'https://mcpscraper.dev').replace(/\\/$/, '')\n const outputDir = options.outputDir ?? process.env.MCP_SCRAPER_OUTPUT_DIR ?? join(homedir(), 'Downloads', 'mcp-scraper')\n const configuredKey = options.apiKey?.trim() || process.env.MCP_SCRAPER_API_KEY?.trim() || await readKeyFile()\n const latest = await npmLatest(fetchImpl)\n\n const checks: DoctorCheck[] = []\n const nodeMajor = parseMajor(process.version)\n checks.push({\n id: 'node',\n label: 'Node.js',\n status: status(nodeMajor >= 20),\n detail: process.version,\n fix: nodeMajor >= 20 ? undefined : 'Install Node.js 20 or newer.',\n })\n\n checks.push({\n id: 'package_version',\n label: 'Local package',\n status: latest && latest !== PACKAGE_VERSION ? 'warn' : 'pass',\n detail: latest ? `local ${PACKAGE_VERSION}, npm latest ${latest}` : `local ${PACKAGE_VERSION}, npm latest unavailable`,\n fix: latest && latest !== PACKAGE_VERSION ? 'Use mcp-scraper@latest and restart the MCP client.' : undefined,\n })\n\n checks.push({\n id: 'api_key',\n label: 'API key',\n status: configuredKey ? 'pass' : 'warn',\n detail: configuredKey ? 'configured' : 'not configured',\n fix: configuredKey ? undefined : 'Set MCP_SCRAPER_API_KEY or pass --api-key.',\n })\n\n try {\n await mkdir(outputDir, { recursive: true })\n await access(outputDir)\n checks.push({ id: 'output_dir', label: 'Output directory', status: 'pass', detail: outputDir })\n } catch (err) {\n checks.push({\n id: 'output_dir',\n label: 'Output directory',\n status: 'fail',\n detail: outputDir,\n fix: err instanceof Error ? err.message : 'Create a writable output directory.',\n })\n }\n\n if (configuredKey) {\n try {\n const res = await fetchImpl(`${apiUrl}/me`, {\n headers: { 'x-api-key': configuredKey },\n signal: AbortSignal.timeout(8_000),\n })\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: res.ok ? 'pass' : 'fail',\n detail: `${apiUrl}/me returned ${res.status}`,\n fix: res.ok ? undefined : 'Verify the API key and account status.',\n })\n } catch (err) {\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: 'fail',\n detail: err instanceof Error ? err.message : String(err),\n fix: 'Check network access and MCP_SCRAPER_API_URL.',\n })\n }\n } else {\n checks.push({\n id: 'api_reachability',\n label: 'Hosted API',\n status: 'skip',\n detail: 'skipped because no API key is configured',\n })\n }\n\n checks.push({\n id: 'mcp_config',\n label: 'MCP command',\n status: 'pass',\n detail: `npx ${combinedNpxArgs().join(' ')}`,\n fix: 'Restart the MCP client after package updates.',\n })\n\n return {\n ok: checks.every(check => check.status === 'pass' || check.status === 'skip'),\n version: PACKAGE_VERSION,\n npmLatest: latest,\n checks,\n recommendedConfig: {\n command: 'npx',\n args: combinedNpxArgs(),\n env: { MCP_SCRAPER_API_KEY: configuredKey ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key' },\n },\n }\n}\n\nexport function renderDoctor(output: DoctorOutput): string {\n const icon: Record<DoctorStatus, string> = { pass: 'PASS', warn: 'WARN', fail: 'FAIL', skip: 'SKIP' }\n const lines = [\n `mcp-scraper doctor v${output.version}`,\n '',\n ...output.checks.map(check => {\n const fix = check.fix ? `\\n Fix: ${check.fix}` : ''\n return `[${icon[check.status]}] ${check.label}: ${check.detail}${fix}`\n }),\n '',\n `Recommended MCP command: npx ${output.recommendedConfig.args.join(' ')}`,\n ]\n return lines.join('\\n')\n}\n\n","export const AGENT_PROMPTS: Record<string, string> = {\n 'agent-packet': [\n '# MCP Scraper Agent Packet Prompt',\n '',\n 'Use MCP Scraper as the evidence layer. Run the agent-packet workflow for the target keyword/domain, then treat `evidence.json`, `sources.csv`, and `competitors.csv` as source of truth.',\n '',\n 'Do not invent citations. If a recommendation is not supported by the packet, mark it as an assumption. Turn the evidence into a concise SEO brief, an implementation task list, and content recommendations tied to source rows.',\n ].join('\\n'),\n 'local-competitive-audit': [\n '# MCP Scraper Local Competitive Audit Prompt',\n '',\n 'Run the local-competitive-audit workflow for the niche and markets. Use the city summary, competitor CSV, and review-insight CSV to identify market difficulty, review themes, GBP category patterns, and weak competitors.',\n '',\n 'Ground recommendations in Maps rank position, review count, star rating, categories, profile details, and review topics. Do not overstate heuristic opportunity scores.',\n ].join('\\n'),\n 'directory-workflow': [\n '# MCP Scraper Directory Workflow Prompt',\n '',\n 'Use directory_workflow when the user wants cities selected by population and Google Maps candidates per city. Keep query and location separate. Preserve result_position, source_location, review stars/count, categories, and profile URLs for downstream CSV or directory use.',\n ].join('\\n'),\n 'map-comparison': [\n '# MCP Scraper Maps Comparison Prompt',\n '',\n 'Run the map-comparison workflow when the user wants to compare local Maps competitors in a city or across selected markets. Use `maps-results.csv`, `map-comparison.csv`, and `profile-insights.csv` as source of truth.',\n '',\n 'Ground recommendations in result_position, review_stars, review_count, category, website presence, review topics, and profile attributes. Treat review gaps and missing websites as opportunity signals, not guaranteed ranking factors.',\n ].join('\\n'),\n 'serp-comparison': [\n '# MCP Scraper SERP Comparison Prompt',\n '',\n 'Run the serp-comparison workflow when the user wants to know why competitors outrank a page or what the SERP rewards. Use organic results, extracted page headings, PAA questions, and AI Overview citations before making recommendations.',\n '',\n 'Tie each recommendation to `content-gaps.csv`, `page-comparison.csv`, `paa-questions.csv`, or `ai-overview-citations.csv`. Do not invent missing sections or citations.',\n ].join('\\n'),\n 'paa-expansion-brief': [\n '# MCP Scraper PAA Expansion Brief Prompt',\n '',\n 'Run the paa-expansion-brief workflow when the user wants to figure out what to write from People Also Ask expansion. Use `section-map.csv` to structure the brief and `paa-questions.csv` for exact customer-language headings.',\n '',\n 'Answer the highest-priority questions directly, preserve source URLs when present, and separate evidence-backed sections from assumptions.',\n ].join('\\n'),\n 'ai-overview-language': [\n '# MCP Scraper AI Overview Language Prompt',\n '',\n 'Run the ai-overview-language workflow when the user wants to know how to phrase content for AI Overview inclusion. Use `claim-patterns.csv`, `language-guidance.csv`, `ai-overview-citations.csv`, and PAA follow-ups as evidence.',\n '',\n 'Recommend concise answer blocks, criteria/step language, citation hooks, and follow-up sections. Do not claim the target will be cited; frame the output as evidence-based language guidance.',\n ].join('\\n'),\n 'ai-citation-monitor': [\n '# MCP Scraper AI Citation Monitor Prompt',\n '',\n 'Use search_serp and harvest_paa to check whether the target brand/domain appears in AI Overview citations, organic results, People Also Ask sources, local pack, forums, and videos. Save evidence before summarizing trends or gaps.',\n ].join('\\n'),\n 'serp-brief': [\n '# MCP Scraper SERP Brief Prompt',\n '',\n 'Use live SERP, PAA, AI Overview, forum, video, and source evidence to create a writer brief. Tie each recommended section to evidence rows and identify missing proof, entities, comparisons, and customer questions.',\n ].join('\\n'),\n}\n\nexport function listPrompts(): string[] {\n return Object.keys(AGENT_PROMPTS).sort()\n}\n\nexport function renderPrompt(name: string): string {\n const prompt = AGENT_PROMPTS[name]\n if (!prompt) throw new Error(`Unknown prompt \"${name}\". Available: ${listPrompts().join(', ')}`)\n return prompt\n}\n","#!/usr/bin/env node\nimport { runHumanCli } from '../src/cli/human-cli.js'\n\nrunHumanCli().catch((err) => {\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n})\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,SAAAA,QAAO,iBAAiB;AACjC,SAAS,UAAU,QAAAC,aAAY;;;ACS/B,SAAS,YAAY,SAAqC;AACxD,SAAO,QAAQ,QAAQ,KAAK,KAAK;AACnC;AAEA,SAAS,YAAY,SAAqC;AACxD,SAAO,QAAQ,aAAa,KAAK,KAAK;AACxC;AAEO,SAAS,gBAAgB,UAA8B,CAAC,GAAa;AAC1E,SAAO,CAAC,MAAM,MAAM,YAAY,OAAO,GAAG,sBAAsB;AAClE;AAEA,SAAS,UAAU,SAAqD;AACtE,QAAM,MAA8B,EAAE,qBAAqB,YAAY,OAAO,EAAE;AAChF,QAAM,cAAc,QAAQ,oBAAoB,KAAK;AACrD,MAAI,QAAQ,gBAAgB,SAAS;AACnC,QAAI,2BAA2B;AAC/B,QAAI,YAAa,KAAI,8BAA8B;AACnD,UAAM,iBAAiB,QAAQ,uBAAuB,KAAK;AAC3D,QAAI,eAAgB,KAAI,iCAAiC;AAAA,EAC3D,OAAO;AACL,QAAI,YAAa,KAAI,6BAA6B;AAClD,QAAI,QAAQ,8BAA8B,KAAM,KAAI,qCAAqC;AAAA,EAC3F;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAuC;AAC9D,QAAM,UAAU,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,MAAM,GAAG,GAAG,MAAM,KAAK,UAAU,IAAI,CAAC,EAAE;AAC7F,SAAO,KAAK,QAAQ,KAAK,IAAI,CAAC;AAChC;AAEO,SAAS,kBAAkB,UAA8B,CAAC,GAAW;AAC1E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,UAAU,KAAK,UAAU,gBAAgB,OAAO,CAAC,CAAC;AAAA,IAClD,SAAS,gBAAgB,UAAU,OAAO,CAAC,CAAC;AAAA,EAC9C,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,oBAAoB,UAA8B,CAAC,GAAW;AAC5E,QAAM,MAAM,OAAO,QAAQ,UAAU,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,WAAW,GAAG,IAAI,KAAK,EAAE;AAC9F,SAAO;AAAA,IACL;AAAA,IACA,GAAG;AAAA,IACH,YAAY,gBAAgB,OAAO,EAAE,KAAK,GAAG,CAAC;AAAA,EAChD,EAAE,KAAK,OAAO;AAChB;AAEO,SAAS,sBAAgC;AAC9C,SAAO,CAAC,OAAO,UAAU,eAAe,MAAM,MAAM;AACtD;AAEO,SAAS,iBAAiB,UAA8B,CAAC,GAAa;AAC3E,QAAM,OAAO,CAAC,OAAO,OAAO,eAAe,WAAW,MAAM;AAC5D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,OAAO,CAAC,GAAG;AAC7D,SAAK,KAAK,SAAS,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,EACtC;AACA,OAAK,KAAK,MAAM,OAAO,GAAG,gBAAgB,OAAO,CAAC;AAClD,SAAO;AACT;AAEO,SAAS,mBAAmB,MAAyB;AAC1D,MAAI,SAAS,cAAe,QAAO;AACnC,MAAI,SAAS,YAAY,SAAS,WAAW,SAAS,iBAAkB,QAAO;AAC/E,QAAM,IAAI,MAAM,mBAAmB,OAAO,uDAAuD;AACnG;AAEO,SAAS,0BAA0B,UAA8B,CAAC,GAAW;AAClF,SAAO,KAAK,UAAU;AAAA,IACpB,YAAY;AAAA,MACV,eAAe;AAAA,QACb,SAAS;AAAA,QACT,MAAM,gBAAgB,OAAO;AAAA,QAC7B,KAAK,UAAU,OAAO;AAAA,MACxB;AAAA,IACF;AAAA,EACF,GAAG,MAAM,CAAC;AACZ;AAEO,SAAS,mBAAmB,MAAiB,UAA8B,CAAC,GAAW;AAC5F,QAAM,iBAAiB,mBAAmB,IAAI;AAC9C,QAAM,UAAU;AAChB,QAAM,eAAe,uBAAuB,YAAY,OAAO,CAAC;AAChE,MAAI,mBAAmB,SAAS;AAC9B,WAAO;AAAA,MACL;AAAA,MACA,kBAAkB,OAAO;AAAA,MACzB;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACA,MAAI,mBAAmB,UAAU;AAC/B,WAAO;AAAA,MACL;AAAA,MACA,oBAAoB,OAAO;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACA,SAAO;AAAA,IACL;AAAA,IACA,0BAA0B,OAAO;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;;;AC3HA,SAAS,QAAQ,OAAO,gBAAgB;AACxC,SAAS,eAAe;AACxB,SAAS,YAAY;AAiCrB,SAAS,OAAO,IAAa,OAAO,OAAqB;AACvD,MAAI,GAAI,QAAO;AACf,SAAO,OAAO,SAAS;AACzB;AAEA,SAAS,WAAW,SAAyB;AAC3C,SAAO,OAAO,QAAQ,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC;AAC5D;AAEA,eAAe,cAAsC;AACnD,QAAM,OAAO,QAAQ,IAAI,sBAAsB,KAAK,KAAK,KAAK,QAAQ,GAAG,kBAAkB;AAC3F,MAAI;AACF,UAAM,SAAS,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK;AAClD,WAAO,SAAS;AAAA,EAClB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,UAAU,WAAiD;AACxE,MAAI;AACF,UAAM,MAAM,MAAM,UAAU,iDAAiD;AAAA,MAC3E,QAAQ,YAAY,QAAQ,GAAK;AAAA,IACnC,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,QAAO;AACpB,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,KAAK,WAAW;AAAA,EACzB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,UAAU,UAAyB,CAAC,GAA0B;AAClF,QAAM,YAAY,QAAQ,aAAa;AACvC,QAAM,UAAU,QAAQ,UAAU,QAAQ,IAAI,uBAAuB,0BAA0B,QAAQ,OAAO,EAAE;AAChH,QAAM,YAAY,QAAQ,aAAa,QAAQ,IAAI,0BAA0B,KAAK,QAAQ,GAAG,aAAa,aAAa;AACvH,QAAM,gBAAgB,QAAQ,QAAQ,KAAK,KAAK,QAAQ,IAAI,qBAAqB,KAAK,KAAK,MAAM,YAAY;AAC7G,QAAM,SAAS,MAAM,UAAU,SAAS;AAExC,QAAM,SAAwB,CAAC;AAC/B,QAAM,YAAY,WAAW,QAAQ,OAAO;AAC5C,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ,OAAO,aAAa,EAAE;AAAA,IAC9B,QAAQ,QAAQ;AAAA,IAChB,KAAK,aAAa,KAAK,SAAY;AAAA,EACrC,CAAC;AAED,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ,UAAU,WAAW,kBAAkB,SAAS;AAAA,IACxD,QAAQ,SAAS,SAAS,eAAe,gBAAgB,MAAM,KAAK,SAAS,eAAe;AAAA,IAC5F,KAAK,UAAU,WAAW,kBAAkB,uDAAuD;AAAA,EACrG,CAAC;AAED,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ,gBAAgB,SAAS;AAAA,IACjC,QAAQ,gBAAgB,eAAe;AAAA,IACvC,KAAK,gBAAgB,SAAY;AAAA,EACnC,CAAC;AAED,MAAI;AACF,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,UAAM,OAAO,SAAS;AACtB,WAAO,KAAK,EAAE,IAAI,cAAc,OAAO,oBAAoB,QAAQ,QAAQ,QAAQ,UAAU,CAAC;AAAA,EAChG,SAAS,KAAK;AACZ,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,KAAK,eAAe,QAAQ,IAAI,UAAU;AAAA,IAC5C,CAAC;AAAA,EACH;AAEA,MAAI,eAAe;AACjB,QAAI;AACF,YAAM,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO;AAAA,QAC1C,SAAS,EAAE,aAAa,cAAc;AAAA,QACtC,QAAQ,YAAY,QAAQ,GAAK;AAAA,MACnC,CAAC;AACD,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ,IAAI,KAAK,SAAS;AAAA,QAC1B,QAAQ,GAAG,MAAM,gBAAgB,IAAI,MAAM;AAAA,QAC3C,KAAK,IAAI,KAAK,SAAY;AAAA,MAC5B,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,aAAO,KAAK;AAAA,QACV,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACvD,KAAK;AAAA,MACP,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AACL,WAAO,KAAK;AAAA,MACV,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO,KAAK;AAAA,IACV,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,OAAO,gBAAgB,EAAE,KAAK,GAAG,CAAC;AAAA,IAC1C,KAAK;AAAA,EACP,CAAC;AAED,SAAO;AAAA,IACL,IAAI,OAAO,MAAM,WAAS,MAAM,WAAW,UAAU,MAAM,WAAW,MAAM;AAAA,IAC5E,SAAS;AAAA,IACT,WAAW;AAAA,IACX;AAAA,IACA,mBAAmB;AAAA,MACjB,SAAS;AAAA,MACT,MAAM,gBAAgB;AAAA,MACtB,KAAK,EAAE,qBAAqB,gBAAgB,yBAAyB,mBAAmB;AAAA,IAC1F;AAAA,EACF;AACF;AAEO,SAAS,aAAa,QAA8B;AACzD,QAAM,OAAqC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,QAAQ,MAAM,OAAO;AACpG,QAAM,QAAQ;AAAA,IACZ,uBAAuB,OAAO,OAAO;AAAA,IACrC;AAAA,IACA,GAAG,OAAO,OAAO,IAAI,WAAS;AAC5B,YAAM,MAAM,MAAM,MAAM;AAAA,WAAc,MAAM,GAAG,KAAK;AACpD,aAAO,IAAI,KAAK,MAAM,MAAM,CAAC,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,GAAG,GAAG;AAAA,IACtE,CAAC;AAAA,IACD;AAAA,IACA,gCAAgC,OAAO,kBAAkB,KAAK,KAAK,GAAG,CAAC;AAAA,EACzE;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACnLO,IAAM,gBAAwC;AAAA,EACnD,gBAAgB;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,2BAA2B;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,sBAAsB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,kBAAkB;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,mBAAmB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,uBAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,wBAAwB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,uBAAuB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AAAA,EACX,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,cAAwB;AACtC,SAAO,OAAO,KAAK,aAAa,EAAE,KAAK;AACzC;AAEO,SAAS,aAAa,MAAsB;AACjD,QAAM,SAAS,cAAc,IAAI;AACjC,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,mBAAmB,IAAI,iBAAiB,YAAY,EAAE,KAAK,IAAI,CAAC,EAAE;AAC/F,SAAO;AACT;;;AHhDA,SAAS,UAAU,OAAoC;AACrD,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,GAAI,QAAO;AAClE,QAAM,SAAS,OAAO,KAAK;AAC3B,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAEA,SAAS,WAAW,OAAqC;AACvD,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,UAAW,QAAO;AACvC,MAAI,UAAU,OAAQ,QAAO;AAC7B,MAAI,UAAU,QAAS,QAAO;AAC9B,SAAO;AACT;AAEA,SAAS,aAAa,OAAyD;AAC7E,SAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS,CAAC;AAC5F;AAEA,SAAS,cAAc,IAAY,MAAwD;AACzF,MAAI,OAAO,kBAAkB,OAAO,qBAAqB,OAAO,wBAAwB;AACtF,WAAO,aAAa;AAAA,MAClB,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK;AAAA,MACb,KAAK,KAAK;AAAA,MACV,UAAU,KAAK;AAAA,MACf,YAAY,UAAU,KAAK,UAAU;AAAA,MACrC,cAAc,UAAU,KAAK,YAAY;AAAA,MACzC,YAAY,UAAU,KAAK,UAAU;AAAA,MACrC,aAAa,KAAK,SAAS,QAAQ,QAAQ;AAAA,MAC3C,YAAY,KAAK,QAAQ,QAAQ,QAAQ;AAAA,MACzC,mBAAmB,WAAW,KAAK,iBAAiB;AAAA,MACpD,eAAe,KAAK,kBAAkB,QAAQ,QAAQ;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,uBAAuB;AAChC,WAAO,aAAa;AAAA,MAClB,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,cAAc,UAAU,KAAK,YAAY;AAAA,MACzC,OAAO,UAAU,KAAK,KAAK;AAAA,MAC3B,eAAe,KAAK,kBAAkB,QAAQ,QAAQ;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,eAAe,OAAO,6BAA6B,OAAO,kBAAkB;AACrF,WAAO,aAAa;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,eAAe,UAAU,KAAK,UAAU,KAAK,aAAa;AAAA,MAC1D,WAAW,UAAU,KAAK,SAAS;AAAA,MACnC,mBAAmB,UAAU,KAAK,WAAW,KAAK,qBAAqB,KAAK,UAAU;AAAA,MACtF,aAAa,UAAU,KAAK,WAAW;AAAA,MACvC,WAAW,KAAK;AAAA,MAChB,YAAY,OAAO,6BAA6B,OAAO,mBAAmB,UAAU,KAAK,UAAU,IAAI;AAAA,MACvG,YAAY,OAAO,6BAA6B,OAAO,mBAAmB,UAAU,KAAK,WAAW,KAAK,UAAU,IAAI;AAAA,MACvH,eAAe,KAAK,kBAAkB,QAAQ,QAAQ;AAAA,IACxD,CAAC;AAAA,EACH;AAEA,SAAO,aAAa,IAAI;AAC1B;AAEA,SAAS,YAAY,MAAe,MAAiC;AACnE,MAAI,MAAM;AACR,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC3D,WAAW,OAAO,SAAS,UAAU;AACnC,YAAQ,OAAO,MAAM,GAAG,IAAI;AAAA,CAAI;AAAA,EAClC,OAAO;AACL,YAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,EAC3D;AACF;AAEA,SAAS,YAAY,OAAuB;AAC1C,SAAO,MAAM,QAAQ,sBAAsB,QAAQ;AACrD;AAEA,SAAS,gBAAgB,SAAiB,MAA2E;AACnH,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,MAAM,SAAS,MAAM,EAAE,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AACxE,UAAM,SAAmB,CAAC;AAC1B,UAAM,SAAmB,CAAC;AAC1B,QAAI,UAAU;AACd,UAAM,OAAO,CAAC,WAA6D;AACzE,UAAI,QAAS;AACb,gBAAU;AACV,cAAQ,MAAM;AAAA,IAChB;AACA,UAAM,OAAO,GAAG,QAAQ,WAAS,OAAO,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC;AAChE,UAAM,OAAO,GAAG,QAAQ,WAAS,OAAO,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC;AAChE,UAAM,GAAG,SAAS,SAAO;AACvB,WAAK,EAAE,MAAM,KAAK,QAAQ,IAAI,QAAQ,IAAI,QAAQ,CAAC;AAAA,IACrD,CAAC;AACD,UAAM,GAAG,SAAS,UAAQ;AACxB,WAAK;AAAA,QACH,MAAM,OAAO,SAAS,WAAW,OAAO;AAAA,QACxC,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAAA,QAC7C,QAAQ,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAAA,MAC/C,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,WAAW,MAA+D;AACjF,MAAI,KAAK,MAAO,QAAO;AACvB,MAAI,KAAK,QAAS,QAAO;AACzB,SAAO;AACT;AAEA,SAAS,WAAW,MAAmE;AACrF,QAAM,SAAS,OAAO,KAAK,UAAU,QAAQ,IAAI,uBAAuB,EAAE,EAAE,KAAK;AACjF,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,kFAAkF;AAC/G,SAAO;AAAA,IACL,QAAQ,OAAO,KAAK,UAAU,QAAQ,IAAI,uBAAuB,wBAAwB,EAAE,QAAQ,OAAO,EAAE;AAAA,IAC5G;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,KAAsB;AAC7C,QAAM,UAAU,QAAQ,aAAa,WACjC,SACA,QAAQ,aAAa,UACnB,QACA;AACN,QAAM,OAAO,QAAQ,aAAa,UAAU,CAAC,MAAM,SAAS,IAAI,GAAG,IAAI,CAAC,GAAG;AAC3E,MAAI;AACF,UAAM,QAAQ,MAAM,SAAS,MAAM,EAAE,UAAU,MAAM,OAAO,SAAS,CAAC;AACtE,UAAM,MAAM;AACZ,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,WAAc,MAAc,QAAgB,MAA+B,MAA4B;AACpH,QAAM,EAAE,QAAQ,OAAO,IAAI,WAAW,IAAI;AAC1C,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,IAAI,IAAI;AAAA,IAC1C;AAAA,IACA,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,IACA,MAAM,QAAQ,OAAO,SAAY,KAAK,UAAU,IAAI;AAAA,EACtD,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,UAAU,OAAQ,KAA6B,UAAU,WAC1D,KAA2B,QAC5B,2BAA2B,IAAI,MAAM;AACzC,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,SAA2B;AAC1D,SAAO,QACJ,OAAO,uBAAuB,sBAAsB,EACpD,OAAO,qBAAqB,eAAe,EAC3C,OAAO,eAAe,iBAAiB,EACvC,OAAO,yBAAyB,iBAAiB,EACjD,OAAO,qBAAqB,8BAA8B,EAC1D,OAAO,uBAAuB,uBAAuB,EACrD,OAAO,qBAAqB,+CAA+C,EAC3E,OAAO,eAAe,qBAAqB,EAC3C,OAAO,aAAa,qCAAqC,EACzD,OAAO,YAAY,oCAAoC,EACvD,OAAO,mBAAmB,qCAAqC,EAC/D,OAAO,mBAAmB,UAAU,EACpC,OAAO,iBAAiB,yBAAyB,EACjD,OAAO,oBAAoB,yBAAyB,EACpD,OAAO,kBAAkB,uBAAuB,EAChD,OAAO,qBAAqB,yBAAyB,EACrD,OAAO,uBAAuB,2CAA2C,EACzE,OAAO,qBAAqB,qDAAqD,EACjF,OAAO,iBAAiB,8CAA8C,EACtE,OAAO,uBAAuB,2CAA2C;AAC9E;AAEO,SAAS,gBAAyB;AACvC,QAAM,UAAU,IAAI,QAAQ;AAC5B,UACG,KAAK,iBAAiB,EACtB,YAAY,qFAAqF,EACjG,QAAQ,eAAe;AAE1B,UAAQ,QAAQ,QAAQ,EACrB,YAAY,4FAA4F,EACxG,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,uBAAuB,0BAA0B,EACxD,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,UAAU,EAAE,QAAQ,KAAK,QAAQ,QAAQ,KAAK,QAAQ,WAAW,KAAK,UAAU,CAAC;AACtG,gBAAY,KAAK,OAAO,SAAS,aAAa,MAAM,GAAG,KAAK,IAAI;AAChE,QAAI,CAAC,OAAO,GAAI,SAAQ,WAAW;AAAA,EACrC,CAAC;AAEH,QAAM,UAAU,QAAQ,QAAQ,SAAS,EAAE,YAAY,2CAA2C;AAClG,QAAM,qBAAqB,QAAQ,QAAQ,aAAa,EAAE,YAAY,uCAAuC;AAE7G,qBAAmB,QAAQ,MAAM,EAC9B,YAAY,sDAAsD,EAClE,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,WAAqD,oBAAoB,QAAQ,MAAM,CAAC,CAAC;AAC9G,QAAI,KAAK,KAAM,aAAY,OAAO,aAAa,IAAI;AAAA,SAC9C;AACH,YAAM,UAAU,OAAO,aAAa;AACpC,kBAAY;AAAA,QACV,kBAAkB,OAAO,aAAa,iBAAiB,SAAS;AAAA,QAChE,gBAAgB,OAAO,aAAa,uBAAuB,SAAS;AAAA,QACpE,2BAA2B,SAAS,eAAe,UAAU;AAAA,QAC7D,oBAAoB,SAAS,oBAAoB,8CAA8C;AAAA,MACjG,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,IACrB;AAAA,EACF,CAAC;AAEH,qBAAmB,QAAQ,UAAU,EAClC,YAAY,iEAAiE,EAC7E,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,aAAa,kDAAkD,EACtE,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,WAA2F,0CAA0C,QAAQ,MAAM,CAAC,CAAC;AAC1K,QAAI,KAAK,MAAM;AACb,kBAAY,QAAQ,IAAI;AACxB;AAAA,IACF;AACA,UAAM,SAAS,KAAK,SAAS,SAAS,gBAAgB,OAAO,YAAY;AACzE,gBAAY;AAAA,MACV,2BAA2B,OAAO,OAAO,eAAe,UAAU;AAAA,MAClE,SAAS,oBAAoB,OAAO,YAAY,KAAK,iBAAiB,OAAO,YAAY;AAAA,MACzF,OAAO,aAAa;AAAA,IACtB,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EACrB,CAAC;AAEH,QAAM,UAAU,QAAQ,QAAQ,SAAS,EAAE,YAAY,yDAAyD;AAChH,UAAQ,QAAQ,UAAU,EACvB,YAAY,yEAAyE,EACrF,OAAO,mBAAmB,0DAA0D,EACpF,OAAO,0BAA0B,4BAA4B,EAC7D,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,WAAW,MAAM,wBAAwB,KAAK,aAAa,KAAK,KAAK;AAC3E,QAAI,KAAK,MAAM;AACb,kBAAY,EAAE,SAAS,GAAG,IAAI;AAC9B;AAAA,IACF;AACA,QAAI,CAAC,SAAS,QAAQ;AACpB,kBAAY,sCAAsC,KAAK;AACvD;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,GAAG,SAAS,IAAI,aAAW;AAAA,QACzB,GAAG,QAAQ,SAAS,YAAY,IAAK,QAAQ,sBAAsB,IAAK,QAAQ,WAAW;AAAA,QAC3F,6BAA6B,QAAQ,4BAA4B;AAAA,QACjE,wBAAwB,QAAQ,iBAAiB;AAAA,MACnD,EAAE,KAAK,IAAI,CAAC;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,gBAAY,MAAM,KAAK,IAAI,GAAG,KAAK;AAAA,EACrC,CAAC;AAEH,UAAQ,QAAQ,eAAe,EAC5B,YAAY,8EAA8E,EAC1F,OAAO,mBAAmB,0DAA0D,EACpF,OAAO,iBAAiB,0CAA0C,EAClE,OAAO,gCAAgC,4DAA4D,EACnG,OAAO,0BAA0B,mCAAmC,EACpE,OAAO,uBAAuB,gCAAgC,EAC9D,OAAO,+BAA+B,2CAA2C,EACjF,OAAO,eAAe,6CAA6C,EACnE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,oBAAoB;AAAA,MACvC,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,wBAAwB,KAAK;AAAA,MAC7B,mBAAmB,KAAK;AAAA,MACxB,WAAW,KAAK;AAAA,MAChB,uBAAuB,KAAK;AAAA,MAC5B,WAAW,KAAK;AAAA,IAClB,CAAC;AACD,QAAI,KAAK,MAAM;AACb,kBAAY,QAAQ,IAAI;AACxB;AAAA,IACF;AACA,gBAAY;AAAA,MACV,4BAA4B,OAAO,QAAQ,IAAI;AAAA,MAC/C,WAAW,OAAO,cAAc,SAAS,OAAO,cAAc,eAAe,OAAO,cAAc,sBAAsB,KAAK,OAAO,cAAc,sBAAsB;AAAA,MACxK,0BAA0B,OAAO,QAAQ,WAAW;AAAA,MACpD;AAAA,MACA;AAAA,MACA,8HAA8H,OAAO,QAAQ,IAAI;AAAA,MACjJ;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EACrB,CAAC;AAEH,UAAQ,QAAQ,qBAAqB,EAClC,YAAY,kFAAkF,EAC9F,OAAO,uBAAuB,gCAAgC,EAC9D,OAAO,+BAA+B,2CAA2C,EACjF,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,MAAc,SAAS;AACpC,UAAM,SAAS,MAAM,0BAA0B,MAAM;AAAA,MACnD,WAAW,KAAK;AAAA,MAChB,uBAAuB,KAAK;AAAA,IAC9B,CAAC;AACD,QAAI,KAAK,MAAM;AACb,kBAAY,QAAQ,IAAI;AACxB;AAAA,IACF;AACA,gBAAY;AAAA,MACV,0BAA0B,OAAO,QAAQ,IAAI;AAAA,MAC7C,WAAW,OAAO,cAAc,SAAS,OAAO,cAAc,eAAe,OAAO,cAAc,sBAAsB,KAAK,OAAO,cAAc,sBAAsB;AAAA,MACxK,0BAA0B,OAAO,QAAQ,WAAW;AAAA,MACpD;AAAA,IACF,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EACrB,CAAC;AAEH,QAAM,QAAQ,QAAQ,QAAQ,OAAO,EAAE,YAAY,yDAAyD;AAC5G,QAAM,QAAQ,gBAAgB,EAC3B,YAAY,8FAA8F,EAC1G,OAAO,mBAAmB,sCAAsC,EAChE,OAAO,oBAAoB,oBAAoB,oBAAoB,EACnE,OAAO,yBAAyB,iCAAiC,QAAQ,EACzE,OAAO,4BAA4B,0JAA0J,EAC7L,OAAO,+BAA+B,+CAA+C,EACrF,OAAO,kCAAkC,qFAAqF,EAC9H,OAAO,WAAW,uHAAuH,EACzI,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,WAAsB,SAAS;AAC5C,UAAM,OAAO,mBAAmB,SAAS;AACzC,UAAM,cAAc,OAAO,KAAK,eAAe,QAAQ;AACvD,QAAI,CAAC,CAAC,UAAU,OAAO,EAAE,SAAS,WAAW,EAAG,OAAM,IAAI,MAAM,4CAA4C;AAC5G,UAAM,SAAS,KAAK,UAAU,QAAQ,IAAI;AAC1C,QAAI,KAAK,OAAO;AACd,UAAI,SAAS,SAAU,OAAM,IAAI,MAAM,0FAA0F;AACjI,UAAI,CAAC,QAAQ,KAAK,GAAG;AACnB,cAAM,IAAI,MAAM,2FAA2F;AAAA,MAC7G;AAEA,YAAM,gBAAgB;AAAA,QACpB;AAAA,QACA,aAAa,KAAK;AAAA,QAClB;AAAA,QACA,oBAAoB,KAAK;AAAA,QACzB,2BAA2B,KAAK;AAAA,QAChC,uBAAuB,KAAK;AAAA,MAC9B;AACA,YAAM,SAAS,MAAM,gBAAgB,UAAU,oBAAoB,CAAC;AACpE,YAAM,MAAM,MAAM,gBAAgB,UAAU,iBAAiB,aAAa,CAAC;AAC3E,UAAI,IAAI,SAAS,GAAG;AAClB,cAAM,SAAS,YAAY,CAAC,IAAI,QAAQ,IAAI,MAAM,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,CAAC;AACrF,cAAM,IAAI,MAAM;AAAA,UACd;AAAA,UACA,UAAU;AAAA,UACV;AAAA,QACF,EAAE,KAAK,IAAI,CAAC;AAAA,MACd;AACA,YAAM,OAAO,MAAM,gBAAgB,UAAU,CAAC,OAAO,MAAM,CAAC;AAC5D,YAAM,SAAS;AAAA,QACb,MAAM;AAAA,QACN,SAAS;AAAA,QACT,kBAAkB,OAAO,SAAS;AAAA,QAClC,SAAS;AAAA,QACT,MAAM,CAAC,MAAM,MAAM,KAAK,SAAS,sBAAsB;AAAA,QACvD,UAAU;AAAA,QACV,MAAM,YAAY,CAAC,KAAK,QAAQ,KAAK,MAAM,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,CAAC;AAAA,MAChF;AACA,UAAI,KAAK,MAAM;AACb,oBAAY,QAAQ,IAAI;AACxB;AAAA,MACF;AACA,kBAAY;AAAA,QACV;AAAA,QACA,OAAO,SAAS,IAAI,yCAAyC;AAAA,QAC7D,wBAAwB,KAAK,UAAU;AAAA,QACvC,gBAAgB,WAAW,KAAK,iBAAiB,0BAA0B,KAAK,cAAc,KAAK;AAAA,QACnG;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,EAA6B,OAAO,IAAI,KAAK;AAAA,MAC7D,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,GAAG,KAAK;AACnC;AAAA,IACF;AACA,UAAM,OAAO,mBAAmB,MAAM;AAAA,MACpC,QAAQ,KAAK;AAAA,MACb,aAAa,KAAK;AAAA,MAClB;AAAA,MACA,oBAAoB,KAAK;AAAA,MACzB,2BAA2B,KAAK;AAAA,MAChC,uBAAuB,KAAK;AAAA,IAC9B,CAAC;AACD,gBAAY,KAAK,OAAO,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,EAC1D,CAAC;AAEH,QAAM,QAAQ,eAAe,EAC1B,YAAY,iCAAiC,EAC7C,OAAO,UAAU,6BAA6B,EAC9C,OAAO,CAAC,MAA0B,SAAS;AAC1C,QAAI,CAAC,MAAM;AACT,kBAAY,KAAK,OAAO,EAAE,SAAS,YAAY,EAAE,IAAI,YAAY,EAAE,KAAK,IAAI,GAAG,KAAK,IAAI;AACxF;AAAA,IACF;AACA,UAAM,OAAO,aAAa,IAAI;AAC9B,gBAAY,KAAK,OAAO,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AAAA,EAC1D,CAAC;AAEH,QAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE,YAAY,0BAA0B;AACnF,WAAS,QAAQ,MAAM,EACpB,YAAY,2BAA2B,EACvC,OAAO,UAAU,6BAA6B,EAC9C,OAAO,CAAC,SAAS;AAChB,UAAM,OAAO,wBAAwB;AACrC,QAAI,KAAK,KAAM,aAAY,EAAE,WAAW,KAAK,GAAG,IAAI;AAAA,QAC/C,aAAY,KAAK,IAAI,SAAO,GAAG,IAAI,EAAE,IAAK,IAAI,KAAK;AAAA,IAAO,IAAI,WAAW,EAAE,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EACrG,CAAC;AAEH,WAAS,QAAQ,UAAU,EACxB,YAAY,0CAA0C,EACtD,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,UAAU,6BAA6B,EAC9C,OAAO,uBAAuB,sBAAsB,EACpD,OAAO,qBAAqB,eAAe,EAC3C,OAAO,eAAe,iBAAiB,EACvC,OAAO,yBAAyB,iBAAiB,EACjD,OAAO,qBAAqB,8BAA8B,EAC1D,OAAO,uBAAuB,uBAAuB,EACrD,OAAO,qBAAqB,+CAA+C,EAC3E,OAAO,eAAe,qBAAqB,EAC3C,OAAO,aAAa,qCAAqC,EACzD,OAAO,YAAY,oCAAoC,EACvD,OAAO,mBAAmB,qCAAqC,EAC/D,OAAO,mBAAmB,UAAU,EACpC,OAAO,iBAAiB,yBAAyB,EACjD,OAAO,oBAAoB,yBAAyB,EACpD,OAAO,kBAAkB,uBAAuB,EAChD,OAAO,qBAAqB,yBAAyB,EACrD,OAAO,uBAAuB,2CAA2C,EACzE,OAAO,qBAAqB,qDAAqD,EACjF,OAAO,iBAAiB,8CAA8C,EACtE,OAAO,uBAAuB,2CAA2C,EACzE,OAAO,OAAO,IAAY,SAAS;AAClC,UAAM,UAAU,MAAM,YAAY,IAAI,cAAc,IAAI,IAAI,GAAG;AAAA,MAC7D,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,IAClB,CAAC;AACD,QAAI,KAAK,KAAM,aAAY,SAAS,IAAI;AAAA,SACnC;AACH,kBAAY;AAAA,QACV,GAAG,QAAQ,KAAK,KAAK,QAAQ,MAAM;AAAA,QACnC,QAAQ;AAAA,QACR,QAAQ,aAAa,WAAW,QAAQ,UAAU,KAAK;AAAA,QACvD,QAAQ,SAAS,SAAS;AAAA,EAAc,QAAQ,SAAS,IAAI,OAAK,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KAAK;AAAA,MAC7F,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,IACrC;AAAA,EACF,CAAC;AAEH,QAAM,SAAS,QAAQ,QAAQ,QAAQ,EAAE,YAAY,uCAAuC;AAC5F,SAAO,QAAQ,MAAM,EAClB,YAAY,+BAA+B,EAC3C,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,UAAU,MAAM,oBAAoB,KAAK,SAAS;AACxD,gBAAY,KAAK,OAAO,EAAE,QAAQ,IAAI,QAAQ,IAAI,OAAK,GAAG,EAAE,SAAS,IAAK,EAAE,QAAQ,IAAK,EAAE,MAAM,IAAK,EAAE,cAAc,EAAE,YAAY,EAAE,EAAE,KAAK,IAAI,GAAG,KAAK,IAAI;AAAA,EAC/J,CAAC;AACH,SAAO,QAAQ,WAAW,EACvB,YAAY,wCAAwC,EACpD,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,KAAK,QAAQ,SAAS;AACnC,UAAM,QAAQ,MAAM,mBAAmB,IAAI,KAAK,SAAS;AACzD,QAAI,CAAC,OAAO,WAAY,OAAM,IAAI,MAAM,wBAAwB,EAAE,GAAG;AACrE,gBAAY,KAAK,OAAO,EAAE,MAAM,MAAM,YAAY,KAAK,MAAM,IAAI,MAAM,YAAY,KAAK,IAAI;AAAA,EAC9F,CAAC;AACH,SAAO,QAAQ,WAAW,EACvB,YAAY,kCAAkC,EAC9C,OAAO,uBAAuB,2BAA2B,EACzD,OAAO,UAAU,gDAAgD,EACjE,OAAO,OAAO,KAAK,QAAQ,SAAS;AACnC,QAAI,KAAK,MAAM;AACb,YAAM,QAAQ,MAAM,mBAAmB,IAAI,KAAK,SAAS;AACzD,UAAI,CAAC,OAAO,WAAY,OAAM,IAAI,MAAM,wBAAwB,EAAE,GAAG;AACrE,kBAAY,EAAE,MAAM,MAAM,YAAY,KAAK,MAAM,GAAG,IAAI;AACxD;AAAA,IACF;AACA,UAAM,OAAO,MAAM,mBAAmB,IAAI,KAAK,SAAS;AACxD,gBAAY,WAAW,IAAI,IAAI,KAAK;AAAA,EACtC,CAAC;AAEH,QAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE,YAAY,8CAA8C;AACvG,0BAAwB,SAAS,QAAQ,qBAAqB,EAC3D,YAAY,8CAA8C,EAC1D,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,iBAAiB,eAAe,EACvC,OAAO,WAAW,WAAW,EAC7B,OAAO,YAAY,YAAY,EAC/B,OAAO,aAAa,aAAa,EACjC,OAAO,mBAAmB,qBAAqB,KAAK,EACpD,OAAO,mBAAmB,mBAAmB,EAC7C,OAAO,uBAAuB,oCAAoC,EAClE,OAAO,UAAU,6BAA6B,CAAC,EAC/C,OAAO,OAAO,YAAoB,SAAS;AAC1C,UAAM,SAAS,MAAM,WAAW,wBAAwB,QAAQ,MAAM;AAAA,MACpE;AAAA,MACA,MAAM,KAAK;AAAA,MACX,OAAO,cAAc,YAAY,IAAI;AAAA,MACrC,SAAS,WAAW,IAAI;AAAA,MACxB,UAAU,KAAK;AAAA,MACf,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,IAClB,CAAC;AACD,gBAAY,QAAQ,KAAK,IAAI;AAAA,EAC/B,CAAC;AAEH,WAAS,QAAQ,MAAM,EACpB,YAAY,iCAAiC,EAC7C,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,WAA0D,wBAAwB,OAAO,IAAI;AAClH,QAAI,KAAK,KAAM,aAAY,QAAQ,IAAI;AAAA,QAClC,aAAY,OAAO,UAAU,IAAI,iBAAe,GAAG,YAAY,EAAE,IAAK,YAAY,MAAM,IAAK,YAAY,WAAW,IAAK,YAAY,eAAe,EAAE,EAAE,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EAClL,CAAC;AAEH,WAAS,QAAQ,YAAY,EAC1B,YAAY,mCAAmC,EAC/C,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS,YAAY,MAAM,WAAW,wBAAwB,EAAE,IAAI,SAAS,MAAM,EAAE,QAAQ,SAAS,CAAC,GAAG,KAAK,IAAI,CAAC;AAEjJ,WAAS,QAAQ,aAAa,EAC3B,YAAY,oCAAoC,EAChD,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS,YAAY,MAAM,WAAW,wBAAwB,EAAE,IAAI,SAAS,MAAM,EAAE,QAAQ,SAAS,CAAC,GAAG,KAAK,IAAI,CAAC;AAEjJ,WAAS,QAAQ,aAAa,EAC3B,YAAY,oCAAoC,EAChD,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS,YAAY,MAAM,WAAW,wBAAwB,EAAE,IAAI,UAAU,IAAI,GAAG,KAAK,IAAI,CAAC;AAE5H,WAAS,QAAQ,UAAU,EACxB,YAAY,qCAAqC,EACjD,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS,YAAY,MAAM,WAAW,wBAAwB,EAAE,QAAQ,QAAQ,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC;AAElI,QAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,YAAY,4CAA4C;AAC7F,OAAK,QAAQ,MAAM,EAChB,YAAY,4BAA4B,EACxC,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,SAAS;AACtB,UAAM,SAAS,MAAM,WAAqD,mBAAmB,OAAO,IAAI;AACxG,QAAI,KAAK,KAAM,aAAY,QAAQ,IAAI;AAAA,QAClC,aAAY,OAAO,KAAK,IAAI,SAAO,GAAG,IAAI,EAAE,IAAK,IAAI,MAAM,IAAK,IAAI,WAAW,IAAK,IAAI,SAAS,EAAE,EAAE,KAAK,IAAI,GAAG,KAAK;AAAA,EAC7H,CAAC;AAEH,OAAK,QAAQ,aAAa,EACvB,YAAY,6BAA6B,EACzC,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS,YAAY,MAAM,WAAW,mBAAmB,EAAE,IAAI,OAAO,IAAI,GAAG,KAAK,IAAI,CAAC;AAEpH,OAAK,QAAQ,eAAe,EACzB,YAAY,yCAAyC,EACrD,OAAO,mBAAmB,qBAAqB,EAC/C,OAAO,mBAAmB,uBAAuB,wBAAwB,EACzE,OAAO,uBAAuB,oBAAoB,EAClD,OAAO,UAAU,6BAA6B,EAC9C,OAAO,OAAO,IAAY,SAAS;AAClC,UAAM,SAAS,MAAM,WAAoG,mBAAmB,EAAE,IAAI,OAAO,IAAI;AAC7J,UAAM,EAAE,QAAQ,OAAO,IAAI,WAAW,IAAI;AAC1C,UAAM,SAASC,MAAK,KAAK,aAAa,sBAAsB,GAAG,sBAAsB,EAAE;AACvF,UAAMC,OAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACvC,UAAM,aAAuB,CAAC;AAC9B,eAAW,YAAY,OAAO,IAAI,aAAa,CAAC,GAAG;AACjD,YAAM,MAAM,MAAM,MAAM,GAAG,MAAM,mBAAmB,EAAE,cAAc,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,OAAO,EAAE,CAAC;AACvH,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,sBAAsB,SAAS,KAAK,UAAU,IAAI,MAAM,EAAE;AACvF,YAAM,OAAOD,MAAK,QAAQ,SAAS,SAAS,IAAI,CAAC;AACjD,YAAM,UAAU,MAAM,OAAO,KAAK,MAAM,IAAI,YAAY,CAAC,CAAC;AAC1D,iBAAW,KAAK,IAAI;AAAA,IACtB;AACA,gBAAY,KAAK,OAAO,EAAE,OAAO,IAAI,OAAO,WAAW,IAAI,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI;AAAA,EAC7F,CAAC;AAEH,SAAO;AACT;AAEA,eAAsB,YAAY,OAAO,QAAQ,MAAqB;AACpE,QAAM,cAAc,EAAE,WAAW,IAAI;AACvC;;;AI1nBA,YAAY,EAAE,MAAM,CAAC,QAAQ;AAC3B,UAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAC9D,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["mkdir","join","join","mkdir"]}
|
|
@@ -824,7 +824,7 @@ var LocalBrowserAgentService = class {
|
|
|
824
824
|
};
|
|
825
825
|
|
|
826
826
|
// src/version.ts
|
|
827
|
-
var PACKAGE_VERSION = "0.2.
|
|
827
|
+
var PACKAGE_VERSION = "0.2.24";
|
|
828
828
|
|
|
829
829
|
// src/mcp/browser-agent-tool-schemas.ts
|
|
830
830
|
var import_zod = require("zod");
|
|
@@ -5002,10 +5002,9 @@ function renderInstallTerminal(options) {
|
|
|
5002
5002
|
|____/ \____|_| \_\/_/ \_\_| |_____|_| \_\
|
|
5003
5003
|
`;
|
|
5004
5004
|
const claudeCommand = [
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
].join(" \\\n");
|
|
5005
|
+
`MCP_SCRAPER_API_KEY=${apiKeyValue} npx -y -p mcp-scraper@latest \\`,
|
|
5006
|
+
" mcp-scraper-cli agent install claude --apply"
|
|
5007
|
+
].join("\n");
|
|
5009
5008
|
const codexConfig = [
|
|
5010
5009
|
"[mcp_servers.mcp-scraper]",
|
|
5011
5010
|
'command = "npx"',
|
|
@@ -5018,33 +5017,41 @@ function renderInstallTerminal(options) {
|
|
|
5018
5017
|
colorize(ascii, "amber", color),
|
|
5019
5018
|
`${colorize("MCP Scraper Agent", "cyan", color)} . v${options.version} . mcpscraper.dev`,
|
|
5020
5019
|
"1/1 install surfaces ready",
|
|
5021
|
-
colorize("Newest:
|
|
5020
|
+
colorize("Newest: local Chrome profile mode for browser_open, browser_profile_import/sync, and one-server MCP installs.", "lime", color),
|
|
5022
5021
|
"",
|
|
5023
|
-
`${colorize("Tools", "cyan", color)} ${colorize("(
|
|
5022
|
+
`${colorize("Tools", "cyan", color)} ${colorize("(43 MCP tools)", "muted", color)}`,
|
|
5024
5023
|
toolRow("search", ["harvest_paa", "search_serp", "maps_search", "maps_place_intel"], color),
|
|
5025
5024
|
toolRow("extract", ["extract_url", "map_site_urls", "extract_site", "directory_workflow"], color),
|
|
5026
5025
|
toolRow("build", ["rank_tracker_blueprint", "cron plan", "database prompt"], color),
|
|
5027
5026
|
toolRow("media", ["youtube_harvest", "youtube_transcribe", "facebook_ad_search", "facebook_page_intel", "facebook_ad_transcribe", "facebook_video_transcribe"], color),
|
|
5028
|
-
toolRow("browser", ["browser_open", "browser_screenshot", "browser_read", "browser_locate", "browser_replay_mark", "browser_replay_annotate"], color),
|
|
5027
|
+
toolRow("browser", ["browser_open", "browser_profile_import", "browser_profile_sync", "browser_screenshot", "browser_read", "browser_locate", "browser_replay_mark", "browser_replay_annotate"], color),
|
|
5029
5028
|
toolRow("account", ["credits_info", "local reports", "MCP resources"], color),
|
|
5030
5029
|
`${colorize("Workflows", "cyan", color)} ${colorize("(MCP + CLI + API)", "muted", color)}`,
|
|
5031
5030
|
toolRow("route", ["workflow_list", "workflow_suggest", "workflow_run", "workflow_step", "workflow_status", "workflow_artifact_read"], color),
|
|
5032
5031
|
toolRow("seo", ["directory", "agent-packet", "local audit", "map/serp comparison", "PAA/AIO briefs", "scheduled runs"], color),
|
|
5033
5032
|
"",
|
|
5034
5033
|
colorize("Usage tips:", "amber", color),
|
|
5034
|
+
"Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.",
|
|
5035
5035
|
"Run mcp-scraper-combined in a human terminal to print this card; MCP clients get the same command as a silent stdio server.",
|
|
5036
5036
|
"Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install",
|
|
5037
|
+
"Local Chrome mode: mcp-scraper-cli browser import-chrome --email you@example.com --name chrome-default",
|
|
5038
|
+
"Then: mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile chrome-default",
|
|
5037
5039
|
"Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.",
|
|
5038
5040
|
"For MCP clients, use mcp-scraper-combined so one install can mix SERP, Maps, browser, reports, and saved MCP resources.",
|
|
5039
5041
|
"If you hit the concurrency limit, add an extra slot for $5/month with mcp-scraper-cli billing concurrency checkout.",
|
|
5040
5042
|
"",
|
|
5041
|
-
`${colorize("Ready.", "lime", color)} Install the combined MCP server with one
|
|
5043
|
+
`${colorize("Ready.", "lime", color)} Install the combined MCP server with one command:`,
|
|
5042
5044
|
"",
|
|
5043
5045
|
colorize("Setup doctor", "amber", color),
|
|
5044
5046
|
"npx -y -p mcp-scraper@latest mcp-scraper-cli doctor",
|
|
5045
5047
|
"",
|
|
5046
|
-
colorize("
|
|
5048
|
+
colorize("Local Chrome profile setup", "amber", color),
|
|
5049
|
+
"npx -y -p mcp-scraper@latest mcp-scraper-cli browser profiles --email you@example.com",
|
|
5050
|
+
"npx -y -p mcp-scraper@latest mcp-scraper-cli browser import-chrome --email you@example.com --name chrome-default",
|
|
5051
|
+
"",
|
|
5052
|
+
colorize("Claude Code one-command setup", "amber", color),
|
|
5047
5053
|
claudeCommand,
|
|
5054
|
+
"Then fully exit Claude Code and open a new Claude terminal. Check with: claude mcp list",
|
|
5048
5055
|
"",
|
|
5049
5056
|
colorize("Codex config", "amber", color),
|
|
5050
5057
|
codexConfig,
|