@pseolint/core 0.4.1 → 0.5.3
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 +264 -169
- package/dist/ai/manifest/diff.d.ts +78 -0
- package/dist/ai/manifest/diff.d.ts.map +1 -0
- package/dist/ai/manifest/diff.js +139 -0
- package/dist/ai/manifest/diff.js.map +1 -0
- package/dist/ai/manifest/index.d.ts +18 -0
- package/dist/ai/manifest/index.d.ts.map +1 -0
- package/dist/ai/manifest/index.js +15 -0
- package/dist/ai/manifest/index.js.map +1 -0
- package/dist/ai/manifest/validate-manifest.d.ts +37 -0
- package/dist/ai/manifest/validate-manifest.d.ts.map +1 -0
- package/dist/ai/manifest/validate-manifest.js +67 -0
- package/dist/ai/manifest/validate-manifest.js.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts +15 -0
- package/dist/ai/manifest/validators/domain-patches.d.ts.map +1 -0
- package/dist/ai/manifest/validators/domain-patches.js +110 -0
- package/dist/ai/manifest/validators/domain-patches.js.map +1 -0
- package/dist/ai/manifest/validators/index.d.ts +5 -0
- package/dist/ai/manifest/validators/index.d.ts.map +1 -0
- package/dist/ai/manifest/validators/index.js +4 -0
- package/dist/ai/manifest/validators/index.js.map +1 -0
- package/dist/ai/manifest/validators/page-changes.d.ts +36 -0
- package/dist/ai/manifest/validators/page-changes.d.ts.map +1 -0
- package/dist/ai/manifest/validators/page-changes.js +221 -0
- package/dist/ai/manifest/validators/page-changes.js.map +1 -0
- package/dist/ai/manifest/validators/types.d.ts +17 -0
- package/dist/ai/manifest/validators/types.d.ts.map +1 -0
- package/dist/ai/manifest/validators/types.js +5 -0
- package/dist/ai/manifest/validators/types.js.map +1 -0
- package/dist/ai/orchestrate.d.ts +74 -0
- package/dist/ai/orchestrate.d.ts.map +1 -0
- package/dist/ai/orchestrate.js +54 -0
- package/dist/ai/orchestrate.js.map +1 -0
- package/dist/ai/orchestrator/budget.d.ts +57 -0
- package/dist/ai/orchestrator/budget.d.ts.map +1 -0
- package/dist/ai/orchestrator/budget.js +114 -0
- package/dist/ai/orchestrator/budget.js.map +1 -0
- package/dist/ai/orchestrator/finish-tool.d.ts +568 -0
- package/dist/ai/orchestrator/finish-tool.d.ts.map +1 -0
- package/dist/ai/orchestrator/finish-tool.js +114 -0
- package/dist/ai/orchestrator/finish-tool.js.map +1 -0
- package/dist/ai/orchestrator/index.d.ts +25 -0
- package/dist/ai/orchestrator/index.d.ts.map +1 -0
- package/dist/ai/orchestrator/index.js +21 -0
- package/dist/ai/orchestrator/index.js.map +1 -0
- package/dist/ai/orchestrator/log.d.ts +24 -0
- package/dist/ai/orchestrator/log.d.ts.map +1 -0
- package/dist/ai/orchestrator/log.js +48 -0
- package/dist/ai/orchestrator/log.js.map +1 -0
- package/dist/ai/orchestrator/page-cache.d.ts +64 -0
- package/dist/ai/orchestrator/page-cache.d.ts.map +1 -0
- package/dist/ai/orchestrator/page-cache.js +127 -0
- package/dist/ai/orchestrator/page-cache.js.map +1 -0
- package/dist/ai/orchestrator/prompt.d.ts +16 -0
- package/dist/ai/orchestrator/prompt.d.ts.map +1 -0
- package/dist/ai/orchestrator/prompt.js +52 -0
- package/dist/ai/orchestrator/prompt.js.map +1 -0
- package/dist/ai/orchestrator/runner.d.ts +65 -0
- package/dist/ai/orchestrator/runner.d.ts.map +1 -0
- package/dist/ai/orchestrator/runner.js +223 -0
- package/dist/ai/orchestrator/runner.js.map +1 -0
- package/dist/ai/orchestrator/session.d.ts +44 -0
- package/dist/ai/orchestrator/session.d.ts.map +1 -0
- package/dist/ai/orchestrator/session.js +64 -0
- package/dist/ai/orchestrator/session.js.map +1 -0
- package/dist/ai/orchestrator/types.d.ts +99 -0
- package/dist/ai/orchestrator/types.d.ts.map +1 -0
- package/dist/ai/orchestrator/types.js +8 -0
- package/dist/ai/orchestrator/types.js.map +1 -0
- package/dist/ai/probes/cache.d.ts +12 -0
- package/dist/ai/probes/cache.d.ts.map +1 -0
- package/dist/ai/probes/cache.js +46 -0
- package/dist/ai/probes/cache.js.map +1 -0
- package/dist/ai/tools/ask-ai-engine.d.ts +77 -0
- package/dist/ai/tools/ask-ai-engine.d.ts.map +1 -0
- package/dist/ai/tools/ask-ai-engine.js +253 -0
- package/dist/ai/tools/ask-ai-engine.js.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts +71 -0
- package/dist/ai/tools/check-domain-crawler-access.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-crawler-access.js +76 -0
- package/dist/ai/tools/check-domain-crawler-access.js.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts +70 -0
- package/dist/ai/tools/check-domain-llms-txt.d.ts.map +1 -0
- package/dist/ai/tools/check-domain-llms-txt.js +75 -0
- package/dist/ai/tools/check-domain-llms-txt.js.map +1 -0
- package/dist/ai/tools/check-indexability.d.ts +58 -0
- package/dist/ai/tools/check-indexability.d.ts.map +1 -0
- package/dist/ai/tools/check-indexability.js +64 -0
- package/dist/ai/tools/check-indexability.js.map +1 -0
- package/dist/ai/tools/check-robots.d.ts +68 -0
- package/dist/ai/tools/check-robots.d.ts.map +1 -0
- package/dist/ai/tools/check-robots.js +90 -0
- package/dist/ai/tools/check-robots.js.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts +54 -0
- package/dist/ai/tools/check-rule-answer-first.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-answer-first.js +50 -0
- package/dist/ai/tools/check-rule-answer-first.js.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts +66 -0
- package/dist/ai/tools/check-rule-canonical-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js +51 -0
- package/dist/ai/tools/check-rule-canonical-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts +58 -0
- package/dist/ai/tools/check-rule-citable-facts.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-citable-facts.js +41 -0
- package/dist/ai/tools/check-rule-citable-facts.js.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts +58 -0
- package/dist/ai/tools/check-rule-content-modularity.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-content-modularity.js +45 -0
- package/dist/ai/tools/check-rule-content-modularity.js.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts +54 -0
- package/dist/ai/tools/check-rule-faq-coverage.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-faq-coverage.js +39 -0
- package/dist/ai/tools/check-rule-faq-coverage.js.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts +54 -0
- package/dist/ai/tools/check-rule-freshness-signals.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-freshness-signals.js +45 -0
- package/dist/ai/tools/check-rule-freshness-signals.js.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts +54 -0
- package/dist/ai/tools/check-rule-json-ld-valid.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js +44 -0
- package/dist/ai/tools/check-rule-json-ld-valid.js.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts +54 -0
- package/dist/ai/tools/check-rule-missing-author.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-missing-author.js +45 -0
- package/dist/ai/tools/check-rule-missing-author.js.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts +82 -0
- package/dist/ai/tools/check-rule-near-duplicate.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-near-duplicate.js +63 -0
- package/dist/ai/tools/check-rule-near-duplicate.js.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts +50 -0
- package/dist/ai/tools/check-rule-required-fields.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-required-fields.js +38 -0
- package/dist/ai/tools/check-rule-required-fields.js.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts +54 -0
- package/dist/ai/tools/check-rule-schema-consistency.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-schema-consistency.js +44 -0
- package/dist/ai/tools/check-rule-schema-consistency.js.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts +54 -0
- package/dist/ai/tools/check-rule-summary-bait.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-summary-bait.js +39 -0
- package/dist/ai/tools/check-rule-summary-bait.js.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts +66 -0
- package/dist/ai/tools/check-rule-thin-content.d.ts.map +1 -0
- package/dist/ai/tools/check-rule-thin-content.js +58 -0
- package/dist/ai/tools/check-rule-thin-content.js.map +1 -0
- package/dist/ai/tools/detect-templates.d.ts +60 -0
- package/dist/ai/tools/detect-templates.d.ts.map +1 -0
- package/dist/ai/tools/detect-templates.js +43 -0
- package/dist/ai/tools/detect-templates.js.map +1 -0
- package/dist/ai/tools/fetch-page.d.ts +70 -0
- package/dist/ai/tools/fetch-page.d.ts.map +1 -0
- package/dist/ai/tools/fetch-page.js +93 -0
- package/dist/ai/tools/fetch-page.js.map +1 -0
- package/dist/ai/tools/fetch-sitemap.d.ts +60 -0
- package/dist/ai/tools/fetch-sitemap.d.ts.map +1 -0
- package/dist/ai/tools/fetch-sitemap.js +116 -0
- package/dist/ai/tools/fetch-sitemap.js.map +1 -0
- package/dist/ai/tools/index.d.ts +1555 -0
- package/dist/ai/tools/index.d.ts.map +1 -0
- package/dist/ai/tools/index.js +119 -0
- package/dist/ai/tools/index.js.map +1 -0
- package/dist/ai/tools/parse-page.d.ts +94 -0
- package/dist/ai/tools/parse-page.d.ts.map +1 -0
- package/dist/ai/tools/parse-page.js +108 -0
- package/dist/ai/tools/parse-page.js.map +1 -0
- package/dist/ai/tools/query-serp.d.ts +113 -0
- package/dist/ai/tools/query-serp.d.ts.map +1 -0
- package/dist/ai/tools/query-serp.js +131 -0
- package/dist/ai/tools/query-serp.js.map +1 -0
- package/dist/ai/tools/sample-template.d.ts +67 -0
- package/dist/ai/tools/sample-template.d.ts.map +1 -0
- package/dist/ai/tools/sample-template.js +75 -0
- package/dist/ai/tools/sample-template.js.map +1 -0
- package/dist/ai/tools/types.d.ts +73 -0
- package/dist/ai/tools/types.d.ts.map +1 -0
- package/dist/ai/tools/types.js +64 -0
- package/dist/ai/tools/types.js.map +1 -0
- package/dist/ai/tools/validate-jsonld.d.ts +62 -0
- package/dist/ai/tools/validate-jsonld.d.ts.map +1 -0
- package/dist/ai/tools/validate-jsonld.js +84 -0
- package/dist/ai/tools/validate-jsonld.js.map +1 -0
- package/dist/auditor.d.ts +16 -1
- package/dist/auditor.d.ts.map +1 -1
- package/dist/auditor.js +862 -88
- package/dist/auditor.js.map +1 -1
- package/dist/backpressure.d.ts.map +1 -1
- package/dist/backpressure.js +10 -3
- package/dist/backpressure.js.map +1 -1
- package/dist/enrich-findings.d.ts.map +1 -1
- package/dist/enrich-findings.js +15 -1
- package/dist/enrich-findings.js.map +1 -1
- package/dist/formatters/bucket-findings.d.ts +43 -0
- package/dist/formatters/bucket-findings.d.ts.map +1 -0
- package/dist/formatters/bucket-findings.js +110 -0
- package/dist/formatters/bucket-findings.js.map +1 -0
- package/dist/formatters/console.d.ts.map +1 -1
- package/dist/formatters/console.js +116 -34
- package/dist/formatters/console.js.map +1 -1
- package/dist/formatters/fixplan.d.ts +13 -0
- package/dist/formatters/fixplan.d.ts.map +1 -0
- package/dist/formatters/fixplan.js +328 -0
- package/dist/formatters/fixplan.js.map +1 -0
- package/dist/formatters/html.d.ts.map +1 -1
- package/dist/formatters/html.js +27 -0
- package/dist/formatters/html.js.map +1 -1
- package/dist/formatters/index.d.ts +2 -0
- package/dist/formatters/index.d.ts.map +1 -1
- package/dist/formatters/index.js +1 -0
- package/dist/formatters/index.js.map +1 -1
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +97 -9
- package/dist/formatters/markdown.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/page-filter.d.ts +64 -6
- package/dist/page-filter.d.ts.map +1 -1
- package/dist/page-filter.js +124 -3
- package/dist/page-filter.js.map +1 -1
- package/dist/rule-references.d.ts.map +1 -1
- package/dist/rule-references.js +5 -0
- package/dist/rule-references.js.map +1 -1
- package/dist/rules/aeo/answer-first.d.ts.map +1 -1
- package/dist/rules/aeo/answer-first.js +17 -3
- package/dist/rules/aeo/answer-first.js.map +1 -1
- package/dist/rules/aeo/citable-facts.d.ts.map +1 -1
- package/dist/rules/aeo/citable-facts.js +12 -1
- package/dist/rules/aeo/citable-facts.js.map +1 -1
- package/dist/rules/aeo/content-modularity.d.ts.map +1 -1
- package/dist/rules/aeo/content-modularity.js +3 -0
- package/dist/rules/aeo/content-modularity.js.map +1 -1
- package/dist/rules/aeo/crawler-access.d.ts.map +1 -1
- package/dist/rules/aeo/crawler-access.js +6 -0
- package/dist/rules/aeo/crawler-access.js.map +1 -1
- package/dist/rules/aeo/faq-coverage.d.ts.map +1 -1
- package/dist/rules/aeo/faq-coverage.js +4 -0
- package/dist/rules/aeo/faq-coverage.js.map +1 -1
- package/dist/rules/aeo/freshness-signals.d.ts.map +1 -1
- package/dist/rules/aeo/freshness-signals.js +9 -2
- package/dist/rules/aeo/freshness-signals.js.map +1 -1
- package/dist/rules/aeo/llms-txt.d.ts.map +1 -1
- package/dist/rules/aeo/llms-txt.js +6 -1
- package/dist/rules/aeo/llms-txt.js.map +1 -1
- package/dist/rules/aeo/summary-bait.d.ts.map +1 -1
- package/dist/rules/aeo/summary-bait.js +5 -2
- package/dist/rules/aeo/summary-bait.js.map +1 -1
- package/dist/rules/content/heading-structure.d.ts +21 -0
- package/dist/rules/content/heading-structure.d.ts.map +1 -0
- package/dist/rules/content/heading-structure.js +56 -0
- package/dist/rules/content/heading-structure.js.map +1 -0
- package/dist/rules/content/image-alt-text.d.ts +18 -0
- package/dist/rules/content/image-alt-text.d.ts.map +1 -0
- package/dist/rules/content/image-alt-text.js +77 -0
- package/dist/rules/content/image-alt-text.js.map +1 -0
- package/dist/rules/content/missing-author.d.ts.map +1 -1
- package/dist/rules/content/missing-author.js +10 -2
- package/dist/rules/content/missing-author.js.map +1 -1
- package/dist/rules/content/title-uniqueness.d.ts +18 -0
- package/dist/rules/content/title-uniqueness.d.ts.map +1 -0
- package/dist/rules/content/title-uniqueness.js +70 -0
- package/dist/rules/content/title-uniqueness.js.map +1 -0
- package/dist/rules/links/host-section-divergence.d.ts +3 -0
- package/dist/rules/links/host-section-divergence.d.ts.map +1 -0
- package/dist/rules/links/host-section-divergence.js +158 -0
- package/dist/rules/links/host-section-divergence.js.map +1 -0
- package/dist/rules/links/link-depth.d.ts +12 -1
- package/dist/rules/links/link-depth.d.ts.map +1 -1
- package/dist/rules/links/link-depth.js +25 -12
- package/dist/rules/links/link-depth.js.map +1 -1
- package/dist/rules/scope.d.ts.map +1 -1
- package/dist/rules/scope.js +5 -0
- package/dist/rules/scope.js.map +1 -1
- package/dist/rules/spam/doorway-pattern.d.ts.map +1 -1
- package/dist/rules/spam/doorway-pattern.js +27 -4
- package/dist/rules/spam/doorway-pattern.js.map +1 -1
- package/dist/rules/spam/publication-velocity.d.ts +1 -1
- package/dist/rules/spam/publication-velocity.d.ts.map +1 -1
- package/dist/rules/spam/publication-velocity.js +9 -4
- package/dist/rules/spam/publication-velocity.js.map +1 -1
- package/dist/rules/spam/template-coverage.js +1 -1
- package/dist/rules/spam/template-coverage.js.map +1 -1
- package/dist/rules/spam/template-diversity.js +1 -1
- package/dist/rules/spam/template-diversity.js.map +1 -1
- package/dist/rules/spam/thin-content.d.ts.map +1 -1
- package/dist/rules/spam/thin-content.js +9 -1
- package/dist/rules/spam/thin-content.js.map +1 -1
- package/dist/rules/tech/hreflang-consistency.d.ts.map +1 -1
- package/dist/rules/tech/hreflang-consistency.js +33 -4
- package/dist/rules/tech/hreflang-consistency.js.map +1 -1
- package/dist/rules/tech/og-completeness.d.ts +11 -0
- package/dist/rules/tech/og-completeness.d.ts.map +1 -1
- package/dist/rules/tech/og-completeness.js +22 -23
- package/dist/rules/tech/og-completeness.js.map +1 -1
- package/dist/ruleset-version.d.ts +8 -0
- package/dist/ruleset-version.d.ts.map +1 -0
- package/dist/ruleset-version.js +8 -0
- package/dist/ruleset-version.js.map +1 -0
- package/dist/scrape-strategy.d.ts +42 -0
- package/dist/scrape-strategy.d.ts.map +1 -0
- package/dist/scrape-strategy.js +101 -0
- package/dist/scrape-strategy.js.map +1 -0
- package/dist/site-classifier.d.ts +1 -1
- package/dist/site-classifier.d.ts.map +1 -1
- package/dist/site-classifier.js +217 -0
- package/dist/site-classifier.js.map +1 -1
- package/dist/state.d.ts +36 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +3 -1
- package/dist/state.js.map +1 -1
- package/dist/stratified-sample.d.ts +9 -1
- package/dist/stratified-sample.d.ts.map +1 -1
- package/dist/stratified-sample.js +23 -6
- package/dist/stratified-sample.js.map +1 -1
- package/dist/types.d.ts +179 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/url-normalize.d.ts.map +1 -1
- package/dist/url-normalize.js +13 -1
- package/dist/url-normalize.js.map +1 -1
- package/package.json +90 -90
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-content-modularity.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-content-modularity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwBxB,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBzC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { contentModularityRule } from "../../rules/aeo/content-modularity.js";
|
|
4
|
+
import { resolvePages } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageIds: z.array(z.string()).min(1).max(50).describe("Page references from fetch_page."),
|
|
8
|
+
maxParagraphWords: z.number().int().positive().max(2000).optional(),
|
|
9
|
+
minSelfContainedRatio: z.number().min(0).max(1).optional(),
|
|
10
|
+
});
|
|
11
|
+
const outputSchema = z.object({
|
|
12
|
+
findings: z.array(z.object({
|
|
13
|
+
ruleId: z.literal("aeo/content-modularity"),
|
|
14
|
+
severity: z.enum(["info", "warning", "error", "critical"]),
|
|
15
|
+
message: z.string(),
|
|
16
|
+
pageUrl: z.string().optional(),
|
|
17
|
+
fix: z.string().optional(),
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
export const checkRuleContentModularityTool = defineTool({
|
|
21
|
+
name: "check_rule_content_modularity",
|
|
22
|
+
description: "Check whether paragraphs are modular (short, self-contained, lift-able as standalone snippets). AI engines prefer to quote discrete blocks. Default thresholds: paragraphs <= 200 words, >= 70% self-contained.",
|
|
23
|
+
inputSchema,
|
|
24
|
+
outputSchema,
|
|
25
|
+
async execute({ pageIds, maxParagraphWords, minSelfContainedRatio }) {
|
|
26
|
+
const entries = resolvePages(pageIds);
|
|
27
|
+
const parsed = entries.map((e) => parseHtmlPage(e.html, e.url));
|
|
28
|
+
const opts = {};
|
|
29
|
+
if (maxParagraphWords !== undefined)
|
|
30
|
+
opts.maxParagraphWords = maxParagraphWords;
|
|
31
|
+
if (minSelfContainedRatio !== undefined)
|
|
32
|
+
opts.minSelfContainedRatio = minSelfContainedRatio;
|
|
33
|
+
const findings = contentModularityRule(parsed, opts);
|
|
34
|
+
return {
|
|
35
|
+
findings: findings.map((f) => ({
|
|
36
|
+
ruleId: "aeo/content-modularity",
|
|
37
|
+
severity: f.severity,
|
|
38
|
+
message: f.message,
|
|
39
|
+
pageUrl: f.pageUrl,
|
|
40
|
+
fix: f.fix,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=check-rule-content-modularity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-content-modularity.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-content-modularity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACxF,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;IACnE,qBAAqB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC3D,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC;QAC3C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC,CACH;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,UAAU,CAAC;IACvD,IAAI,EAAE,+BAA+B;IACrC,WAAW,EACT,iNAAiN;IACnN,WAAW;IACX,YAAY;IACZ,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE;QACjE,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,MAAM,IAAI,GAAmE,EAAE,CAAC;QAChF,IAAI,iBAAiB,KAAK,SAAS;YAAE,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAChF,IAAI,qBAAqB,KAAK,SAAS;YAAE,IAAI,CAAC,qBAAqB,GAAG,qBAAqB,CAAC;QAC5F,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrD,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,MAAM,EAAE,wBAAiC;gBACzC,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkRuleFaqCoverageTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: z.ZodType<{
|
|
6
|
+
pageIds: string[];
|
|
7
|
+
minQuestionHeadings?: number | undefined;
|
|
8
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
9
|
+
pageIds: string[];
|
|
10
|
+
minQuestionHeadings?: number | undefined;
|
|
11
|
+
}, unknown>>;
|
|
12
|
+
outputSchema: z.ZodType<{
|
|
13
|
+
findings: {
|
|
14
|
+
ruleId: "aeo/faq-coverage";
|
|
15
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
16
|
+
message: string;
|
|
17
|
+
pageUrl?: string | undefined;
|
|
18
|
+
fix?: string | undefined;
|
|
19
|
+
}[];
|
|
20
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
21
|
+
findings: {
|
|
22
|
+
ruleId: "aeo/faq-coverage";
|
|
23
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
24
|
+
message: string;
|
|
25
|
+
pageUrl?: string | undefined;
|
|
26
|
+
fix?: string | undefined;
|
|
27
|
+
}[];
|
|
28
|
+
}, unknown>>;
|
|
29
|
+
toAiTool(): import("ai").Tool<{
|
|
30
|
+
pageIds: string[];
|
|
31
|
+
minQuestionHeadings?: number | undefined;
|
|
32
|
+
}, import("./types.js").ToolResult<{
|
|
33
|
+
findings: {
|
|
34
|
+
ruleId: "aeo/faq-coverage";
|
|
35
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
36
|
+
message: string;
|
|
37
|
+
pageUrl?: string | undefined;
|
|
38
|
+
fix?: string | undefined;
|
|
39
|
+
}[];
|
|
40
|
+
}>>;
|
|
41
|
+
run(input: {
|
|
42
|
+
pageIds: string[];
|
|
43
|
+
minQuestionHeadings?: number | undefined;
|
|
44
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
45
|
+
findings: {
|
|
46
|
+
ruleId: "aeo/faq-coverage";
|
|
47
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
48
|
+
message: string;
|
|
49
|
+
pageUrl?: string | undefined;
|
|
50
|
+
fix?: string | undefined;
|
|
51
|
+
}[];
|
|
52
|
+
}>>;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=check-rule-faq-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-faq-coverage.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-faq-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBnC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { faqCoverageRule } from "../../rules/aeo/faq-coverage.js";
|
|
4
|
+
import { resolvePages } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageIds: z.array(z.string()).min(1).max(50).describe("Page references from fetch_page."),
|
|
8
|
+
minQuestionHeadings: z.number().int().nonnegative().max(20).optional(),
|
|
9
|
+
});
|
|
10
|
+
const outputSchema = z.object({
|
|
11
|
+
findings: z.array(z.object({
|
|
12
|
+
ruleId: z.literal("aeo/faq-coverage"),
|
|
13
|
+
severity: z.enum(["info", "warning", "error", "critical"]),
|
|
14
|
+
message: z.string(),
|
|
15
|
+
pageUrl: z.string().optional(),
|
|
16
|
+
fix: z.string().optional(),
|
|
17
|
+
})),
|
|
18
|
+
});
|
|
19
|
+
export const checkRuleFaqCoverageTool = defineTool({
|
|
20
|
+
name: "check_rule_faq_coverage",
|
|
21
|
+
description: "Check whether FAQ-style pages have visible question headings that AI engines can quote. Pass pageIds for a sample of '/faq/*' or '/questions/*' URLs; returns warnings for pages that look like they should have Q&A structure but don't.",
|
|
22
|
+
inputSchema,
|
|
23
|
+
outputSchema,
|
|
24
|
+
async execute({ pageIds, minQuestionHeadings }) {
|
|
25
|
+
const entries = resolvePages(pageIds);
|
|
26
|
+
const parsed = entries.map((e) => parseHtmlPage(e.html, e.url));
|
|
27
|
+
const findings = faqCoverageRule(parsed, minQuestionHeadings !== undefined ? { minQuestionHeadings } : undefined);
|
|
28
|
+
return {
|
|
29
|
+
findings: findings.map((f) => ({
|
|
30
|
+
ruleId: "aeo/faq-coverage",
|
|
31
|
+
severity: f.severity,
|
|
32
|
+
message: f.message,
|
|
33
|
+
pageUrl: f.pageUrl,
|
|
34
|
+
fix: f.fix,
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=check-rule-faq-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-faq-coverage.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-faq-coverage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACxF,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CACvE,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;QACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC,CACH;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,UAAU,CAAC;IACjD,IAAI,EAAE,yBAAyB;IAC/B,WAAW,EACT,2OAA2O;IAC7O,WAAW;IACX,YAAY;IACZ,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE;QAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,eAAe,CAC9B,MAAM,EACN,mBAAmB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,SAAS,CACxE,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,MAAM,EAAE,kBAA2B;gBACnC,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkRuleFreshnessSignalsTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: z.ZodType<{
|
|
6
|
+
pageIds: string[];
|
|
7
|
+
maxStaleDays?: number | undefined;
|
|
8
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
9
|
+
pageIds: string[];
|
|
10
|
+
maxStaleDays?: number | undefined;
|
|
11
|
+
}, unknown>>;
|
|
12
|
+
outputSchema: z.ZodType<{
|
|
13
|
+
findings: {
|
|
14
|
+
ruleId: "aeo/freshness-signals";
|
|
15
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
16
|
+
message: string;
|
|
17
|
+
pageUrl?: string | undefined;
|
|
18
|
+
fix?: string | undefined;
|
|
19
|
+
}[];
|
|
20
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
21
|
+
findings: {
|
|
22
|
+
ruleId: "aeo/freshness-signals";
|
|
23
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
24
|
+
message: string;
|
|
25
|
+
pageUrl?: string | undefined;
|
|
26
|
+
fix?: string | undefined;
|
|
27
|
+
}[];
|
|
28
|
+
}, unknown>>;
|
|
29
|
+
toAiTool(): import("ai").Tool<{
|
|
30
|
+
pageIds: string[];
|
|
31
|
+
maxStaleDays?: number | undefined;
|
|
32
|
+
}, import("./types.js").ToolResult<{
|
|
33
|
+
findings: {
|
|
34
|
+
ruleId: "aeo/freshness-signals";
|
|
35
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
36
|
+
message: string;
|
|
37
|
+
pageUrl?: string | undefined;
|
|
38
|
+
fix?: string | undefined;
|
|
39
|
+
}[];
|
|
40
|
+
}>>;
|
|
41
|
+
run(input: {
|
|
42
|
+
pageIds: string[];
|
|
43
|
+
maxStaleDays?: number | undefined;
|
|
44
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
45
|
+
findings: {
|
|
46
|
+
ruleId: "aeo/freshness-signals";
|
|
47
|
+
severity: "info" | "warning" | "error" | "critical";
|
|
48
|
+
message: string;
|
|
49
|
+
pageUrl?: string | undefined;
|
|
50
|
+
fix?: string | undefined;
|
|
51
|
+
}[];
|
|
52
|
+
}>>;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=check-rule-freshness-signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-freshness-signals.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-freshness-signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6BxB,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBxC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { freshnessSignalsRule } from "../../rules/aeo/freshness-signals.js";
|
|
4
|
+
import { resolvePages } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageIds: z.array(z.string()).min(1).max(50).describe("Page references from fetch_page."),
|
|
8
|
+
maxStaleDays: z
|
|
9
|
+
.number()
|
|
10
|
+
.int()
|
|
11
|
+
.positive()
|
|
12
|
+
.max(3650)
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Max days since last update before flagging as stale. Default 180."),
|
|
15
|
+
});
|
|
16
|
+
const outputSchema = z.object({
|
|
17
|
+
findings: z.array(z.object({
|
|
18
|
+
ruleId: z.literal("aeo/freshness-signals"),
|
|
19
|
+
severity: z.enum(["info", "warning", "error", "critical"]),
|
|
20
|
+
message: z.string(),
|
|
21
|
+
pageUrl: z.string().optional(),
|
|
22
|
+
fix: z.string().optional(),
|
|
23
|
+
})),
|
|
24
|
+
});
|
|
25
|
+
export const checkRuleFreshnessSignalsTool = defineTool({
|
|
26
|
+
name: "check_rule_freshness_signals",
|
|
27
|
+
description: "Check pages for visible or structured freshness signals (datePublished / dateModified in JSON-LD, <time> elements, 'Updated YYYY' text). Flags pages older than maxStaleDays and pages missing any freshness signal.",
|
|
28
|
+
inputSchema,
|
|
29
|
+
outputSchema,
|
|
30
|
+
async execute({ pageIds, maxStaleDays }) {
|
|
31
|
+
const entries = resolvePages(pageIds);
|
|
32
|
+
const parsed = entries.map((e) => parseHtmlPage(e.html, e.url));
|
|
33
|
+
const findings = freshnessSignalsRule(parsed, maxStaleDays !== undefined ? { maxStaleDays } : undefined);
|
|
34
|
+
return {
|
|
35
|
+
findings: findings.map((f) => ({
|
|
36
|
+
ruleId: "aeo/freshness-signals",
|
|
37
|
+
severity: f.severity,
|
|
38
|
+
message: f.message,
|
|
39
|
+
pageUrl: f.pageUrl,
|
|
40
|
+
fix: f.fix,
|
|
41
|
+
})),
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=check-rule-freshness-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-freshness-signals.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-freshness-signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACxF,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,GAAG,CAAC,IAAI,CAAC;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,mEAAmE,CAAC;CACjF,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC;QAC1C,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC1D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC,CACH;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,UAAU,CAAC;IACtD,IAAI,EAAE,8BAA8B;IACpC,WAAW,EACT,sNAAsN;IACxN,WAAW;IACX,YAAY;IACZ,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE;QACrC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,MAAM,QAAQ,GAAG,oBAAoB,CACnC,MAAM,EACN,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAC1D,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,MAAM,EAAE,uBAAgC;gBACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkRuleJsonLdValidTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: z.ZodType<{
|
|
6
|
+
pageId: string;
|
|
7
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
8
|
+
pageId: string;
|
|
9
|
+
}, unknown>>;
|
|
10
|
+
outputSchema: z.ZodType<{
|
|
11
|
+
jsonLdBlockCount: number;
|
|
12
|
+
hasParseError: boolean;
|
|
13
|
+
findings: {
|
|
14
|
+
ruleId: "schema/json-ld-valid";
|
|
15
|
+
severity: "error";
|
|
16
|
+
message: string;
|
|
17
|
+
fix?: string | undefined;
|
|
18
|
+
}[];
|
|
19
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
20
|
+
jsonLdBlockCount: number;
|
|
21
|
+
hasParseError: boolean;
|
|
22
|
+
findings: {
|
|
23
|
+
ruleId: "schema/json-ld-valid";
|
|
24
|
+
severity: "error";
|
|
25
|
+
message: string;
|
|
26
|
+
fix?: string | undefined;
|
|
27
|
+
}[];
|
|
28
|
+
}, unknown>>;
|
|
29
|
+
toAiTool(): import("ai").Tool<{
|
|
30
|
+
pageId: string;
|
|
31
|
+
}, import("./types.js").ToolResult<{
|
|
32
|
+
jsonLdBlockCount: number;
|
|
33
|
+
hasParseError: boolean;
|
|
34
|
+
findings: {
|
|
35
|
+
ruleId: "schema/json-ld-valid";
|
|
36
|
+
severity: "error";
|
|
37
|
+
message: string;
|
|
38
|
+
fix?: string | undefined;
|
|
39
|
+
}[];
|
|
40
|
+
}>>;
|
|
41
|
+
run(input: {
|
|
42
|
+
pageId: string;
|
|
43
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
44
|
+
jsonLdBlockCount: number;
|
|
45
|
+
hasParseError: boolean;
|
|
46
|
+
findings: {
|
|
47
|
+
ruleId: "schema/json-ld-valid";
|
|
48
|
+
severity: "error";
|
|
49
|
+
message: string;
|
|
50
|
+
fix?: string | undefined;
|
|
51
|
+
}[];
|
|
52
|
+
}>>;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=check-rule-json-ld-valid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-json-ld-valid.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-json-ld-valid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { jsonLdValidRule } from "../../rules/schema/json-ld-valid.js";
|
|
4
|
+
import { resolvePage } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageId: z.string().describe("Page reference returned by fetch_page."),
|
|
8
|
+
});
|
|
9
|
+
const outputSchema = z.object({
|
|
10
|
+
jsonLdBlockCount: z.number().int().nonnegative(),
|
|
11
|
+
hasParseError: z.boolean(),
|
|
12
|
+
findings: z.array(z.object({
|
|
13
|
+
ruleId: z.literal("schema/json-ld-valid"),
|
|
14
|
+
severity: z.literal("error"),
|
|
15
|
+
message: z.string(),
|
|
16
|
+
fix: z.string().optional(),
|
|
17
|
+
})),
|
|
18
|
+
});
|
|
19
|
+
export const checkRuleJsonLdValidTool = defineTool({
|
|
20
|
+
name: "check_rule_json_ld_valid",
|
|
21
|
+
description: "Validate JSON-LD blocks on a previously-fetched page for parse errors, missing @context, and invalid @type values. Reports one finding per malformed block. For Schema.org-spec compliance (required properties per type), use validate_jsonld.",
|
|
22
|
+
inputSchema,
|
|
23
|
+
outputSchema,
|
|
24
|
+
async execute({ pageId }) {
|
|
25
|
+
const entry = resolvePage(pageId);
|
|
26
|
+
const parsed = parseHtmlPage(entry.html, entry.url);
|
|
27
|
+
const hasParseError = parsed.jsonLd.some((e) => typeof e === "object" &&
|
|
28
|
+
e !== null &&
|
|
29
|
+
"__parseError" in e &&
|
|
30
|
+
e.__parseError === true);
|
|
31
|
+
const findings = jsonLdValidRule([parsed]);
|
|
32
|
+
return {
|
|
33
|
+
jsonLdBlockCount: parsed.jsonLd.length,
|
|
34
|
+
hasParseError,
|
|
35
|
+
findings: findings.map((f) => ({
|
|
36
|
+
ruleId: "schema/json-ld-valid",
|
|
37
|
+
severity: "error",
|
|
38
|
+
message: f.message,
|
|
39
|
+
fix: f.fix,
|
|
40
|
+
})),
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=check-rule-json-ld-valid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-json-ld-valid.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-json-ld-valid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAChD,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE;IAC1B,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC;QACzC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC,CACH;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,UAAU,CAAC;IACjD,IAAI,EAAE,0BAA0B;IAChC,WAAW,EACT,iPAAiP;IACnP,WAAW;IACX,YAAY;IACZ,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE;QACtB,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,KAAK,QAAQ;YACrB,CAAC,KAAK,IAAI;YACV,cAAc,IAAI,CAAC;YAClB,CAA6B,CAAC,YAAY,KAAK,IAAI,CACvD,CAAC;QACF,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAE3C,OAAO;YACL,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YACtC,aAAa;YACb,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7B,MAAM,EAAE,sBAA+B;gBACvC,QAAQ,EAAE,OAAgB;gBAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,GAAG,EAAE,CAAC,CAAC,GAAG;aACX,CAAC,CAAC;SACJ,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkRuleMissingAuthorTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: z.ZodType<{
|
|
6
|
+
pageId: string;
|
|
7
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
8
|
+
pageId: string;
|
|
9
|
+
}, unknown>>;
|
|
10
|
+
outputSchema: z.ZodType<{
|
|
11
|
+
hasAuthorSignal: boolean;
|
|
12
|
+
finding: {
|
|
13
|
+
ruleId: "content/missing-author";
|
|
14
|
+
severity: "warning";
|
|
15
|
+
confidence: "high" | "medium" | "low" | "speculative";
|
|
16
|
+
message: string;
|
|
17
|
+
fix?: string | undefined;
|
|
18
|
+
} | null;
|
|
19
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
20
|
+
hasAuthorSignal: boolean;
|
|
21
|
+
finding: {
|
|
22
|
+
ruleId: "content/missing-author";
|
|
23
|
+
severity: "warning";
|
|
24
|
+
confidence: "high" | "medium" | "low" | "speculative";
|
|
25
|
+
message: string;
|
|
26
|
+
fix?: string | undefined;
|
|
27
|
+
} | null;
|
|
28
|
+
}, unknown>>;
|
|
29
|
+
toAiTool(): import("ai").Tool<{
|
|
30
|
+
pageId: string;
|
|
31
|
+
}, import("./types.js").ToolResult<{
|
|
32
|
+
hasAuthorSignal: boolean;
|
|
33
|
+
finding: {
|
|
34
|
+
ruleId: "content/missing-author";
|
|
35
|
+
severity: "warning";
|
|
36
|
+
confidence: "high" | "medium" | "low" | "speculative";
|
|
37
|
+
message: string;
|
|
38
|
+
fix?: string | undefined;
|
|
39
|
+
} | null;
|
|
40
|
+
}>>;
|
|
41
|
+
run(input: {
|
|
42
|
+
pageId: string;
|
|
43
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
44
|
+
hasAuthorSignal: boolean;
|
|
45
|
+
finding: {
|
|
46
|
+
ruleId: "content/missing-author";
|
|
47
|
+
severity: "warning";
|
|
48
|
+
confidence: "high" | "medium" | "low" | "speculative";
|
|
49
|
+
message: string;
|
|
50
|
+
fix?: string | undefined;
|
|
51
|
+
} | null;
|
|
52
|
+
}>>;
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=check-rule-missing-author.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-missing-author.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-missing-author.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuBxB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBrC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { missingAuthorRule } from "../../rules/content/missing-author.js";
|
|
4
|
+
import { resolvePage } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageId: z.string().describe("Page reference returned by fetch_page."),
|
|
8
|
+
});
|
|
9
|
+
const outputSchema = z.object({
|
|
10
|
+
hasAuthorSignal: z.boolean(),
|
|
11
|
+
finding: z
|
|
12
|
+
.object({
|
|
13
|
+
ruleId: z.literal("content/missing-author"),
|
|
14
|
+
severity: z.literal("warning"),
|
|
15
|
+
confidence: z.enum(["high", "medium", "low", "speculative"]),
|
|
16
|
+
message: z.string(),
|
|
17
|
+
fix: z.string().optional(),
|
|
18
|
+
})
|
|
19
|
+
.nullable(),
|
|
20
|
+
});
|
|
21
|
+
export const checkRuleMissingAuthorTool = defineTool({
|
|
22
|
+
name: "check_rule_missing_author",
|
|
23
|
+
description: "Check if a previously-fetched page has any author attribution signal (meta[name=author], JSON-LD author, visible byline, rel=author link). Returns a warning finding when none are present. Severity is `warning` (not `error`) because docs/product/marketing pages legitimately ship without bylines — this matters most on blog/news content.",
|
|
24
|
+
inputSchema,
|
|
25
|
+
outputSchema,
|
|
26
|
+
async execute({ pageId }) {
|
|
27
|
+
const entry = resolvePage(pageId);
|
|
28
|
+
const parsed = parseHtmlPage(entry.html, entry.url);
|
|
29
|
+
const findings = missingAuthorRule([parsed]);
|
|
30
|
+
const finding = findings[0];
|
|
31
|
+
return {
|
|
32
|
+
hasAuthorSignal: findings.length === 0,
|
|
33
|
+
finding: finding
|
|
34
|
+
? {
|
|
35
|
+
ruleId: "content/missing-author",
|
|
36
|
+
severity: "warning",
|
|
37
|
+
confidence: finding.confidence ?? "medium",
|
|
38
|
+
message: finding.message,
|
|
39
|
+
fix: finding.fix,
|
|
40
|
+
}
|
|
41
|
+
: null,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=check-rule-missing-author.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-missing-author.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-missing-author.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE;IAC5B,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC;QAC3C,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QAC9B,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAC5D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,UAAU,CAAC;IACnD,IAAI,EAAE,2BAA2B;IACjC,WAAW,EACT,kVAAkV;IACpV,WAAW;IACX,YAAY;IACZ,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE;QACtB,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAE5B,OAAO;YACL,eAAe,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;YACtC,OAAO,EAAE,OAAO;gBACd,CAAC,CAAC;oBACE,MAAM,EAAE,wBAAiC;oBACzC,QAAQ,EAAE,SAAkB;oBAC5B,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ;oBAC1C,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,GAAG,EAAE,OAAO,CAAC,GAAG;iBACjB;gBACH,CAAC,CAAC,IAAI;SACT,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const checkRuleNearDuplicateTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: z.ZodType<{
|
|
6
|
+
pageIds: string[];
|
|
7
|
+
threshold?: number | undefined;
|
|
8
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
9
|
+
pageIds: string[];
|
|
10
|
+
threshold?: number | undefined;
|
|
11
|
+
}, unknown>>;
|
|
12
|
+
outputSchema: z.ZodType<{
|
|
13
|
+
pairCount: number;
|
|
14
|
+
pairs: {
|
|
15
|
+
leftUrl: string;
|
|
16
|
+
rightUrl: string;
|
|
17
|
+
similarity: number;
|
|
18
|
+
}[];
|
|
19
|
+
findings: {
|
|
20
|
+
ruleId: "spam/near-duplicate";
|
|
21
|
+
severity: "critical";
|
|
22
|
+
message: string;
|
|
23
|
+
pageUrl: string;
|
|
24
|
+
similarity: number;
|
|
25
|
+
relatedUrls?: string[] | undefined;
|
|
26
|
+
}[];
|
|
27
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
28
|
+
pairCount: number;
|
|
29
|
+
pairs: {
|
|
30
|
+
leftUrl: string;
|
|
31
|
+
rightUrl: string;
|
|
32
|
+
similarity: number;
|
|
33
|
+
}[];
|
|
34
|
+
findings: {
|
|
35
|
+
ruleId: "spam/near-duplicate";
|
|
36
|
+
severity: "critical";
|
|
37
|
+
message: string;
|
|
38
|
+
pageUrl: string;
|
|
39
|
+
similarity: number;
|
|
40
|
+
relatedUrls?: string[] | undefined;
|
|
41
|
+
}[];
|
|
42
|
+
}, unknown>>;
|
|
43
|
+
toAiTool(): import("ai").Tool<{
|
|
44
|
+
pageIds: string[];
|
|
45
|
+
threshold?: number | undefined;
|
|
46
|
+
}, import("./types.js").ToolResult<{
|
|
47
|
+
pairCount: number;
|
|
48
|
+
pairs: {
|
|
49
|
+
leftUrl: string;
|
|
50
|
+
rightUrl: string;
|
|
51
|
+
similarity: number;
|
|
52
|
+
}[];
|
|
53
|
+
findings: {
|
|
54
|
+
ruleId: "spam/near-duplicate";
|
|
55
|
+
severity: "critical";
|
|
56
|
+
message: string;
|
|
57
|
+
pageUrl: string;
|
|
58
|
+
similarity: number;
|
|
59
|
+
relatedUrls?: string[] | undefined;
|
|
60
|
+
}[];
|
|
61
|
+
}>>;
|
|
62
|
+
run(input: {
|
|
63
|
+
pageIds: string[];
|
|
64
|
+
threshold?: number | undefined;
|
|
65
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
66
|
+
pairCount: number;
|
|
67
|
+
pairs: {
|
|
68
|
+
leftUrl: string;
|
|
69
|
+
rightUrl: string;
|
|
70
|
+
similarity: number;
|
|
71
|
+
}[];
|
|
72
|
+
findings: {
|
|
73
|
+
ruleId: "spam/near-duplicate";
|
|
74
|
+
severity: "critical";
|
|
75
|
+
message: string;
|
|
76
|
+
pageUrl: string;
|
|
77
|
+
similarity: number;
|
|
78
|
+
relatedUrls?: string[] | undefined;
|
|
79
|
+
}[];
|
|
80
|
+
}>>;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=check-rule-near-duplicate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-near-duplicate.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-near-duplicate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BrC,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { nearDuplicateRule } from "../../rules/spam/near-duplicate.js";
|
|
4
|
+
import { resolvePages } from "../orchestrator/page-cache.js";
|
|
5
|
+
import { defineTool } from "./types.js";
|
|
6
|
+
const inputSchema = z.object({
|
|
7
|
+
pageIds: z
|
|
8
|
+
.array(z.string())
|
|
9
|
+
.min(2)
|
|
10
|
+
.max(50)
|
|
11
|
+
.describe("Page references from fetch_page. Min 2, max 50 to bound O(n^2) work."),
|
|
12
|
+
threshold: z
|
|
13
|
+
.number()
|
|
14
|
+
.min(0)
|
|
15
|
+
.max(1)
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Minimum simhash similarity (0-1) to flag as near-duplicate. Default 0.85."),
|
|
18
|
+
});
|
|
19
|
+
const outputSchema = z.object({
|
|
20
|
+
pairCount: z.number().int().nonnegative(),
|
|
21
|
+
pairs: z.array(z.object({
|
|
22
|
+
leftUrl: z.string(),
|
|
23
|
+
rightUrl: z.string(),
|
|
24
|
+
similarity: z.number().min(0).max(1),
|
|
25
|
+
})),
|
|
26
|
+
findings: z.array(z.object({
|
|
27
|
+
ruleId: z.literal("spam/near-duplicate"),
|
|
28
|
+
severity: z.literal("critical"),
|
|
29
|
+
message: z.string(),
|
|
30
|
+
pageUrl: z.string(),
|
|
31
|
+
relatedUrls: z.array(z.string()).optional(),
|
|
32
|
+
similarity: z.number().min(0).max(1),
|
|
33
|
+
})),
|
|
34
|
+
});
|
|
35
|
+
const DEFAULT_THRESHOLD = 0.85;
|
|
36
|
+
export const checkRuleNearDuplicateTool = defineTool({
|
|
37
|
+
name: "check_rule_near_duplicate",
|
|
38
|
+
description: "Detect near-duplicate page pairs across a sample (simhash + Hamming distance). Pass an array of pageIds (min 2, max 50). Returns each pair above the similarity threshold (default 0.85) plus a critical finding per pair. Use after sample_template + fetch_page to check whether template-instance pages are differentiated enough.",
|
|
39
|
+
inputSchema,
|
|
40
|
+
outputSchema,
|
|
41
|
+
async execute({ pageIds, threshold = DEFAULT_THRESHOLD }) {
|
|
42
|
+
const entries = resolvePages(pageIds);
|
|
43
|
+
const parsed = entries.map((e) => parseHtmlPage(e.html, e.url));
|
|
44
|
+
const { findings, pairs } = nearDuplicateRule(parsed, threshold);
|
|
45
|
+
return {
|
|
46
|
+
pairCount: pairs.length,
|
|
47
|
+
pairs: pairs.map((p) => ({
|
|
48
|
+
leftUrl: p.leftUrl,
|
|
49
|
+
rightUrl: p.rightUrl,
|
|
50
|
+
similarity: p.similarity,
|
|
51
|
+
})),
|
|
52
|
+
findings: findings.map((f) => ({
|
|
53
|
+
ruleId: "spam/near-duplicate",
|
|
54
|
+
severity: "critical",
|
|
55
|
+
message: f.message,
|
|
56
|
+
pageUrl: f.pageUrl ?? "",
|
|
57
|
+
relatedUrls: f.relatedUrls,
|
|
58
|
+
similarity: f.similarity ?? 0,
|
|
59
|
+
})),
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=check-rule-near-duplicate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rule-near-duplicate.js","sourceRoot":"","sources":["../../../src/ai/tools/check-rule-near-duplicate.ts"],"names":[],"mappings":"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"}
|