seo 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -3
- package/dist/cli.js.map +1 -1
- package/dist/{dist-Dik5MNDk.js → dist-BnpsvtXl.js} +1 -1
- package/dist/{dist-pwGymked.js → dist-DoPZlCJq.js} +4 -4
- package/dist/dist-DoPZlCJq.js.map +1 -0
- package/dist/{esm-DieyhVZ-.js → esm-D12ZCG_1.js} +2 -2
- package/dist/{esm-DieyhVZ-.js.map → esm-D12ZCG_1.js.map} +1 -1
- package/dist/index.d.ts +42 -42
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +15 -7
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
- package/dist/dist-pwGymked.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire as __seoCreateRequire } from 'node:module'; const require = __seoCreateRequire(import.meta.url);
|
|
2
|
-
import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-
|
|
2
|
+
import { i as __toESM, n as version, r as __commonJSMin, t as load } from "./esm-D12ZCG_1.js";
|
|
3
3
|
import { createHash, randomUUID, sign } from "node:crypto";
|
|
4
4
|
import { ZodOptional, z } from "zod";
|
|
5
5
|
import { arch, homedir, platform, tmpdir, totalmem } from "node:os";
|
|
@@ -42378,8 +42378,15 @@ async function runAiAnswers(input, headers, deps, more) {
|
|
|
42378
42378
|
const keys = dataForSeoKeys(headers);
|
|
42379
42379
|
const domain = registrableDomain(input.site)?.domain;
|
|
42380
42380
|
if (!domain) throw new CommandError("INVALID_INPUT", `ai_answers needs a site with a domain, not "${input.site}".`);
|
|
42381
|
+
const given = [...new Set((input.questions ?? []).map((q) => q.trim()).filter(Boolean))];
|
|
42382
|
+
if (given.length > 10) throw new CommandError("INVALID_INPUT", `ai_answers takes up to 10 questions, not ${given.length}.`);
|
|
42381
42383
|
const range = dateWindow({}, QUESTION_DAYS);
|
|
42382
|
-
|
|
42384
|
+
let questions;
|
|
42385
|
+
if (given.length) questions = given.map((query) => ({
|
|
42386
|
+
query,
|
|
42387
|
+
impressions: null
|
|
42388
|
+
}));
|
|
42389
|
+
else questions = ((await aiQueriesReport({
|
|
42383
42390
|
site: input.site,
|
|
42384
42391
|
...range
|
|
42385
42392
|
}, deps.searchAnalytics)).items ?? []).filter((item) => item.askable).slice(0, 10);
|
|
@@ -42396,7 +42403,7 @@ async function runAiAnswers(input, headers, deps, more) {
|
|
|
42396
42403
|
}))));
|
|
42397
42404
|
const cost = usd(answers.reduce((sum, row) => sum + row.cost_usd, 0));
|
|
42398
42405
|
const count = (result) => answers.filter((row) => row.result === result).length;
|
|
42399
|
-
const notes = [questions.length ? `The top ${questions.length} askable questions in Search Console’s AI-shaped queries for ${range.startDate} to ${range.endDate}, by impressions. No calls were made for other questions.` : `No askable questions in Search Console’s AI-shaped queries for ${range.startDate} to ${range.endDate}, so no answers were checked and nothing was spent.`, ...questions.length ? [
|
|
42406
|
+
const notes = [given.length ? `The ${given.length} questions you gave, asked as written. Impressions are blank because they don't come from Search Console.` : questions.length ? `The top ${questions.length} askable questions in Search Console’s AI-shaped queries for ${range.startDate} to ${range.endDate}, by impressions. No calls were made for other questions.` : `No askable questions in Search Console’s AI-shaped queries for ${range.startDate} to ${range.endDate}, so no answers were checked and nothing was spent.`, ...questions.length ? [
|
|
42400
42407
|
`Cited ${count("cited")}, mentioned ${count("mentioned")}, neither ${count("neither")}, no answer shown ${count("no_answer")}, unavailable ${count("unavailable")}. DataForSEO cost: $${cost}.`,
|
|
42401
42408
|
"Each row is one sample of an answer that changes from run to run, not a ranking.",
|
|
42402
42409
|
`cited: the answer lists or links a page on ${domain} or a subdomain. mentioned: no such source, but the answer text names ${[domain, ...site.terms].join(" or ")}, a text match. no_answer: the engine showed no AI answer for the question. model: the model DataForSEO reports for the answer, when it reports one.`,
|
|
@@ -42417,7 +42424,7 @@ async function runAiAnswers(input, headers, deps, more) {
|
|
|
42417
42424
|
action: "ai_answers",
|
|
42418
42425
|
site: input.site,
|
|
42419
42426
|
country: input.country,
|
|
42420
|
-
questionsFrom: {
|
|
42427
|
+
questionsFrom: given.length ? { section: "given" } : {
|
|
42421
42428
|
section: "ai-queries",
|
|
42422
42429
|
...range
|
|
42423
42430
|
},
|
|
@@ -45564,7 +45571,7 @@ const RESEARCH_ACTIONS = [
|
|
|
45564
45571
|
"ai_answers"
|
|
45565
45572
|
];
|
|
45566
45573
|
const RESEARCH_PROVIDERS = ["dataforseo", "ahrefs"];
|
|
45567
|
-
const RESEARCH_HELP = `keyword_metrics (keywords: volume, difficulty, CPC), ranked_keywords (target: keywords a domain or URL ranks for), serp (keywords, up to 5: the ranking pages), competitors (target: domains that share keywords), backlinks (target: referring domains), ai_answers (DataForSEO only; target: the site.
|
|
45574
|
+
const RESEARCH_HELP = `keyword_metrics (keywords: volume, difficulty, CPC), ranked_keywords (target: keywords a domain or URL ranks for), serp (keywords, up to 5: the ranking pages), competitors (target: domains that share keywords), backlinks (target: referring domains), ai_answers (DataForSEO only; target: the site. Without keywords it takes the site’s top 10 chat-style and long questions from Search Console’s AI-shaped queries itself. With up to 10 questions in keywords it asks those instead, and the target can be any domain, such as a competitor's. It asks ChatGPT search, Google AI Mode and Google AI Overviews each one and says whether the answer cites or mentions the site. DataForSEO’s live prices are $0.012 a question, so up to about $0.12 a run: tell the person before running it). Rows with a domain, and the target, get a free Ahrefs domain_rating column. Numbers are provider estimates, not Search Console data.`;
|
|
45568
45575
|
const GENERIC_PLATFORMS = [
|
|
45569
45576
|
"youtube.com",
|
|
45570
45577
|
"facebook.com",
|
|
@@ -46520,10 +46527,11 @@ const SHARED_TOOLS = [
|
|
|
46520
46527
|
if (input.action === "ai_answers") {
|
|
46521
46528
|
if (input.provider !== "dataforseo") throw new CommandError("INVALID_INPUT", "ai_answers uses dataforseo.");
|
|
46522
46529
|
return runAiAnswers({
|
|
46523
|
-
site: await surface.resolveSite(input.target),
|
|
46530
|
+
site: input.keywords.length ? input.target : await surface.resolveSite(input.target),
|
|
46524
46531
|
country: input.country,
|
|
46525
46532
|
detail: input.detail,
|
|
46526
|
-
offset: input.offset
|
|
46533
|
+
offset: input.offset,
|
|
46534
|
+
questions: input.keywords
|
|
46527
46535
|
}, await surface.keys(), surface.deps, more);
|
|
46528
46536
|
}
|
|
46529
46537
|
return runResearch(input, await surface.keys(), {
|