@pseolint/core 0.4.3 → 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 +4 -0
- package/dist/auditor.d.ts.map +1 -1
- package/dist/auditor.js +629 -64
- 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/console.d.ts.map +1 -1
- package/dist/formatters/console.js +13 -0
- package/dist/formatters/console.js.map +1 -1
- package/dist/formatters/markdown.d.ts.map +1 -1
- package/dist/formatters/markdown.js +20 -2
- 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/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/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/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/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.map +1 -1
- package/dist/site-classifier.js +1 -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 +135 -2
- package/dist/types.d.ts.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,67 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Stratified URL sampler. Two modes:
|
|
4
|
+
* - No `template`: stratified sample across all template clusters in `urls`,
|
|
5
|
+
* proportional to sqrt(cluster size). Good for "give me N representative
|
|
6
|
+
* URLs from this entire sitemap."
|
|
7
|
+
* - With `template`: restrict to URLs matching the named template, then
|
|
8
|
+
* simple random sample of size `n`. Good for "give me 5 examples from the
|
|
9
|
+
* /city/ template specifically."
|
|
10
|
+
*/
|
|
11
|
+
export declare const sampleTemplateTool: {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
inputSchema: z.ZodType<{
|
|
15
|
+
urls: string[];
|
|
16
|
+
n: number;
|
|
17
|
+
template?: string | undefined;
|
|
18
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
19
|
+
urls: string[];
|
|
20
|
+
n: number;
|
|
21
|
+
template?: string | undefined;
|
|
22
|
+
}, unknown>>;
|
|
23
|
+
outputSchema: z.ZodType<{
|
|
24
|
+
sample: string[];
|
|
25
|
+
sampledFrom: number;
|
|
26
|
+
template: null;
|
|
27
|
+
} | {
|
|
28
|
+
sample: string[];
|
|
29
|
+
sampledFrom: number;
|
|
30
|
+
template: string;
|
|
31
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
32
|
+
sample: string[];
|
|
33
|
+
sampledFrom: number;
|
|
34
|
+
template: null;
|
|
35
|
+
} | {
|
|
36
|
+
sample: string[];
|
|
37
|
+
sampledFrom: number;
|
|
38
|
+
template: string;
|
|
39
|
+
}, unknown>>;
|
|
40
|
+
toAiTool(): import("ai").Tool<{
|
|
41
|
+
urls: string[];
|
|
42
|
+
n: number;
|
|
43
|
+
template?: string | undefined;
|
|
44
|
+
}, import("./types.js").ToolResult<{
|
|
45
|
+
sample: string[];
|
|
46
|
+
sampledFrom: number;
|
|
47
|
+
template: null;
|
|
48
|
+
} | {
|
|
49
|
+
sample: string[];
|
|
50
|
+
sampledFrom: number;
|
|
51
|
+
template: string;
|
|
52
|
+
}>>;
|
|
53
|
+
run(input: {
|
|
54
|
+
urls: string[];
|
|
55
|
+
n: number;
|
|
56
|
+
template?: string | undefined;
|
|
57
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
58
|
+
sample: string[];
|
|
59
|
+
sampledFrom: number;
|
|
60
|
+
template: null;
|
|
61
|
+
} | {
|
|
62
|
+
sample: string[];
|
|
63
|
+
sampledFrom: number;
|
|
64
|
+
template: string;
|
|
65
|
+
}>>;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=sample-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-template.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/sample-template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8B7B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { stratifiedSample } from "../../stratified-sample.js";
|
|
3
|
+
import { normalizePathToTemplate } from "../../site-classifier.js";
|
|
4
|
+
import { defineTool } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Match the same normalizer that `detect_templates` uses so a template key
|
|
7
|
+
* produced by one tool is usable as the `template` filter on the other.
|
|
8
|
+
* `stratified-sample.ts` ships a different (stricter) normalizer for its
|
|
9
|
+
* cluster-aware sampling, but for orchestrator handoff we need
|
|
10
|
+
* detect_templates ↔ sample_template to agree on keys.
|
|
11
|
+
*/
|
|
12
|
+
function urlToTemplateKey(url) {
|
|
13
|
+
try {
|
|
14
|
+
return normalizePathToTemplate(new URL(url).pathname || "/");
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
const path = url.split("?")[0].split("#")[0];
|
|
18
|
+
return normalizePathToTemplate(path.startsWith("/") ? path : `/${path}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const inputSchema = z.object({
|
|
22
|
+
urls: z.array(z.string()).min(1).describe("URL pool to sample from."),
|
|
23
|
+
n: z
|
|
24
|
+
.number()
|
|
25
|
+
.int()
|
|
26
|
+
.positive()
|
|
27
|
+
.max(500)
|
|
28
|
+
.describe("Sample size. Capped at 500 to bound LLM input tokens."),
|
|
29
|
+
template: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("When provided, restrict sampling to URLs matching this template (as produced by detect_templates / inferUrlTemplate). When omitted, samples stratified across all detected templates."),
|
|
33
|
+
});
|
|
34
|
+
const outputSchema = z.object({
|
|
35
|
+
sample: z.array(z.string()),
|
|
36
|
+
sampledFrom: z.number().int().nonnegative(),
|
|
37
|
+
template: z.string().nullable(),
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Stratified URL sampler. Two modes:
|
|
41
|
+
* - No `template`: stratified sample across all template clusters in `urls`,
|
|
42
|
+
* proportional to sqrt(cluster size). Good for "give me N representative
|
|
43
|
+
* URLs from this entire sitemap."
|
|
44
|
+
* - With `template`: restrict to URLs matching the named template, then
|
|
45
|
+
* simple random sample of size `n`. Good for "give me 5 examples from the
|
|
46
|
+
* /city/ template specifically."
|
|
47
|
+
*/
|
|
48
|
+
export const sampleTemplateTool = defineTool({
|
|
49
|
+
name: "sample_template",
|
|
50
|
+
description: "Sample URLs from a list. Without `template`, returns N URLs stratified across all detected templates (good for 'representative sample of this sitemap'). With `template`, restricts to URLs matching that template (good for 'give me 5 example pages from the /city/ template'). Capped at n=500 to keep LLM context manageable.",
|
|
51
|
+
inputSchema,
|
|
52
|
+
outputSchema,
|
|
53
|
+
async execute({ urls, n, template }) {
|
|
54
|
+
if (template === undefined) {
|
|
55
|
+
const sample = stratifiedSample(urls, n);
|
|
56
|
+
return { sample, sampledFrom: urls.length, template: null };
|
|
57
|
+
}
|
|
58
|
+
const matching = urls.filter((u) => urlToTemplateKey(u) === template);
|
|
59
|
+
if (matching.length === 0) {
|
|
60
|
+
return { sample: [], sampledFrom: 0, template };
|
|
61
|
+
}
|
|
62
|
+
if (matching.length <= n) {
|
|
63
|
+
return { sample: matching, sampledFrom: matching.length, template };
|
|
64
|
+
}
|
|
65
|
+
// Simple shuffle-then-take (deterministic enough for orchestrator use; the
|
|
66
|
+
// LLM picks N, our job is to produce N distinct URLs from the cluster).
|
|
67
|
+
const shuffled = [...matching];
|
|
68
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
69
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
70
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
71
|
+
}
|
|
72
|
+
return { sample: shuffled.slice(0, n), sampledFrom: matching.length, template };
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=sample-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sample-template.js","sourceRoot":"","sources":["../../../src/ai/tools/sample-template.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ZodType } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Tool execution context. The AI SDK passes this as the second argument to
|
|
4
|
+
* `execute` — we surface only the fields tools care about (currently just
|
|
5
|
+
* the abort signal). Tools that don't need it can ignore the context.
|
|
6
|
+
*/
|
|
7
|
+
export interface ToolExecuteContext {
|
|
8
|
+
/**
|
|
9
|
+
* Aborted when the orchestrator session aborts. Tools that perform I/O
|
|
10
|
+
* (fetch_page, query_serp, ask_ai_engine, etc.) should thread this into
|
|
11
|
+
* their underlying fetch calls so in-flight network work cancels
|
|
12
|
+
* promptly when the session ends.
|
|
13
|
+
*/
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Tool definition consumed by `defineTool`. Each orchestrator tool exposes a
|
|
18
|
+
* Zod-typed input + output schema, a description (used by the LLM to decide
|
|
19
|
+
* when to call the tool), and an `execute` function.
|
|
20
|
+
*
|
|
21
|
+
* The `name` field doubles as the registry key — `orchestratorTools[name]`
|
|
22
|
+
* resolves to the AI-SDK tool object generated from this definition.
|
|
23
|
+
*/
|
|
24
|
+
export interface ToolDefinition<I, O> {
|
|
25
|
+
name: string;
|
|
26
|
+
description: string;
|
|
27
|
+
inputSchema: ZodType<I>;
|
|
28
|
+
outputSchema: ZodType<O>;
|
|
29
|
+
execute: (input: I, ctx?: ToolExecuteContext) => Promise<O>;
|
|
30
|
+
}
|
|
31
|
+
/** Successful tool result wrapped in a discriminated union for LLM consumption. */
|
|
32
|
+
export interface ToolOk<O> {
|
|
33
|
+
ok: true;
|
|
34
|
+
data: O;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Tool error result. Errors are returned as data, not thrown — the orchestrator
|
|
38
|
+
* loop must keep going. Throwing here would terminate the AI-SDK stream and
|
|
39
|
+
* lose partial session progress.
|
|
40
|
+
*/
|
|
41
|
+
export interface ToolErr {
|
|
42
|
+
ok: false;
|
|
43
|
+
error: string;
|
|
44
|
+
errorCode: "INPUT_VALIDATION" | "OUTPUT_VALIDATION" | "EXECUTE_ERROR";
|
|
45
|
+
}
|
|
46
|
+
export type ToolResult<O> = ToolOk<O> | ToolErr;
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a tool definition in:
|
|
49
|
+
* - input validation (delegated to AI SDK + duplicated in `.run` for tests)
|
|
50
|
+
* - output validation (catches tool bugs that produce malformed outputs)
|
|
51
|
+
* - error capture (turns thrown exceptions into `{ ok: false, error }` payloads)
|
|
52
|
+
*
|
|
53
|
+
* Returns an object exposing both `.toAiTool()` (for the orchestrator) and
|
|
54
|
+
* `.run()` (for direct test invocation). The AI SDK tool() and our test runner
|
|
55
|
+
* share the same error shape so tests assert exactly what the LLM will see.
|
|
56
|
+
*/
|
|
57
|
+
export declare function defineTool<I, O>(def: ToolDefinition<I, O>): {
|
|
58
|
+
name: string;
|
|
59
|
+
description: string;
|
|
60
|
+
inputSchema: ZodType<I, unknown, import("zod/v4/core").$ZodTypeInternals<I, unknown>>;
|
|
61
|
+
outputSchema: ZodType<O, unknown, import("zod/v4/core").$ZodTypeInternals<O, unknown>>;
|
|
62
|
+
/**
|
|
63
|
+
* AI SDK tool object — pass into `streamText({ tools: { name: t.toAiTool() } })`.
|
|
64
|
+
* The SDK invokes `execute(input, { abortSignal, toolCallId, ... })`; we
|
|
65
|
+
* lift `abortSignal` into our `ToolExecuteContext.signal` so I/O tools
|
|
66
|
+
* can cancel in-flight fetches when the session aborts.
|
|
67
|
+
*/
|
|
68
|
+
toAiTool(): import("ai").Tool<I, ToolResult<O>>;
|
|
69
|
+
/** Direct invocation for unit tests. Validates input + output. Optional `ctx` for signal-aware tests. */
|
|
70
|
+
run(input: I, ctx?: ToolExecuteContext): Promise<ToolResult<O>>;
|
|
71
|
+
};
|
|
72
|
+
export type DefinedTool<I, O> = ReturnType<typeof defineTool<I, O>>;
|
|
73
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAEnC;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7D;AAED,mFAAmF;AACnF,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,CAAC,CAAC;CACT;AAED;;;;GAIG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,kBAAkB,GAAG,mBAAmB,GAAG,eAAe,CAAC;CACvE;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;;;;;IAyBtD;;;;;OAKG;;IASH,yGAAyG;eACxF,CAAC,QAAQ,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;EAYxE;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,IAAI,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { tool } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a tool definition in:
|
|
4
|
+
* - input validation (delegated to AI SDK + duplicated in `.run` for tests)
|
|
5
|
+
* - output validation (catches tool bugs that produce malformed outputs)
|
|
6
|
+
* - error capture (turns thrown exceptions into `{ ok: false, error }` payloads)
|
|
7
|
+
*
|
|
8
|
+
* Returns an object exposing both `.toAiTool()` (for the orchestrator) and
|
|
9
|
+
* `.run()` (for direct test invocation). The AI SDK tool() and our test runner
|
|
10
|
+
* share the same error shape so tests assert exactly what the LLM will see.
|
|
11
|
+
*/
|
|
12
|
+
export function defineTool(def) {
|
|
13
|
+
async function executeWithCapture(input, ctx) {
|
|
14
|
+
let output;
|
|
15
|
+
try {
|
|
16
|
+
output = await def.execute(input, ctx);
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
20
|
+
return { ok: false, error: `tool ${def.name} threw: ${message}`, errorCode: "EXECUTE_ERROR" };
|
|
21
|
+
}
|
|
22
|
+
const parsed = def.outputSchema.safeParse(output);
|
|
23
|
+
if (!parsed.success) {
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
error: `tool ${def.name} produced invalid output: ${parsed.error.message}`,
|
|
27
|
+
errorCode: "OUTPUT_VALIDATION",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return { ok: true, data: parsed.data };
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
name: def.name,
|
|
34
|
+
description: def.description,
|
|
35
|
+
inputSchema: def.inputSchema,
|
|
36
|
+
outputSchema: def.outputSchema,
|
|
37
|
+
/**
|
|
38
|
+
* AI SDK tool object — pass into `streamText({ tools: { name: t.toAiTool() } })`.
|
|
39
|
+
* The SDK invokes `execute(input, { abortSignal, toolCallId, ... })`; we
|
|
40
|
+
* lift `abortSignal` into our `ToolExecuteContext.signal` so I/O tools
|
|
41
|
+
* can cancel in-flight fetches when the session aborts.
|
|
42
|
+
*/
|
|
43
|
+
toAiTool() {
|
|
44
|
+
return tool({
|
|
45
|
+
description: def.description,
|
|
46
|
+
inputSchema: def.inputSchema,
|
|
47
|
+
execute: async (input, options) => executeWithCapture(input, { signal: options?.abortSignal }),
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
/** Direct invocation for unit tests. Validates input + output. Optional `ctx` for signal-aware tests. */
|
|
51
|
+
async run(input, ctx) {
|
|
52
|
+
const inputParsed = def.inputSchema.safeParse(input);
|
|
53
|
+
if (!inputParsed.success) {
|
|
54
|
+
return {
|
|
55
|
+
ok: false,
|
|
56
|
+
error: `tool ${def.name} got invalid input: ${inputParsed.error.message}`,
|
|
57
|
+
errorCode: "INPUT_VALIDATION",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return executeWithCapture(inputParsed.data, ctx);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/ai/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAqD1B;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAO,GAAyB;IACxD,KAAK,UAAU,kBAAkB,CAAC,KAAQ,EAAE,GAAwB;QAClE,IAAI,MAAS,CAAC;QACd,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,CAAC,IAAI,WAAW,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;QAChG,CAAC;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,QAAQ,GAAG,CAAC,IAAI,6BAA6B,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;gBAC1E,SAAS,EAAE,mBAAmB;aAC/B,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAED,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;QAC9B;;;;;WAKG;QACH,QAAQ;YACN,OAAO,IAAI,CAAC;gBACV,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,OAAO,EAAE,KAAK,EAAE,KAAQ,EAAE,OAAuC,EAAE,EAAE,CACnE,kBAAkB,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;aAC9D,CAAC,CAAC;QACL,CAAC;QACD,yGAAyG;QACzG,KAAK,CAAC,GAAG,CAAC,KAAQ,EAAE,GAAwB;YAC1C,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACrD,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;gBACzB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,KAAK,EAAE,QAAQ,GAAG,CAAC,IAAI,uBAAuB,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE;oBACzE,SAAS,EAAE,kBAAkB;iBAC9B,CAAC;YACJ,CAAC;YACD,OAAO,kBAAkB,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const validateJsonLdTool: {
|
|
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
|
+
url: string;
|
|
12
|
+
blocks: {
|
|
13
|
+
index: number;
|
|
14
|
+
types: string[];
|
|
15
|
+
hasContext: boolean;
|
|
16
|
+
missingRequired: string[];
|
|
17
|
+
ok: boolean;
|
|
18
|
+
}[];
|
|
19
|
+
totalBlocks: number;
|
|
20
|
+
okBlocks: number;
|
|
21
|
+
}, unknown, z.core.$ZodTypeInternals<{
|
|
22
|
+
url: string;
|
|
23
|
+
blocks: {
|
|
24
|
+
index: number;
|
|
25
|
+
types: string[];
|
|
26
|
+
hasContext: boolean;
|
|
27
|
+
missingRequired: string[];
|
|
28
|
+
ok: boolean;
|
|
29
|
+
}[];
|
|
30
|
+
totalBlocks: number;
|
|
31
|
+
okBlocks: number;
|
|
32
|
+
}, unknown>>;
|
|
33
|
+
toAiTool(): import("ai").Tool<{
|
|
34
|
+
pageId: string;
|
|
35
|
+
}, import("./types.js").ToolResult<{
|
|
36
|
+
url: string;
|
|
37
|
+
blocks: {
|
|
38
|
+
index: number;
|
|
39
|
+
types: string[];
|
|
40
|
+
hasContext: boolean;
|
|
41
|
+
missingRequired: string[];
|
|
42
|
+
ok: boolean;
|
|
43
|
+
}[];
|
|
44
|
+
totalBlocks: number;
|
|
45
|
+
okBlocks: number;
|
|
46
|
+
}>>;
|
|
47
|
+
run(input: {
|
|
48
|
+
pageId: string;
|
|
49
|
+
}, ctx?: import("./types.js").ToolExecuteContext): Promise<import("./types.js").ToolResult<{
|
|
50
|
+
url: string;
|
|
51
|
+
blocks: {
|
|
52
|
+
index: number;
|
|
53
|
+
types: string[];
|
|
54
|
+
hasContext: boolean;
|
|
55
|
+
missingRequired: string[];
|
|
56
|
+
ok: boolean;
|
|
57
|
+
}[];
|
|
58
|
+
totalBlocks: number;
|
|
59
|
+
okBlocks: number;
|
|
60
|
+
}>>;
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=validate-jsonld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-jsonld.d.ts","sourceRoot":"","sources":["../../../src/ai/tools/validate-jsonld.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgDxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyC7B,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseHtmlPage } from "../../parser.js";
|
|
3
|
+
import { resolvePage } from "../orchestrator/page-cache.js";
|
|
4
|
+
import { defineTool } from "./types.js";
|
|
5
|
+
const inputSchema = z.object({
|
|
6
|
+
pageId: z.string().describe("Page reference returned by fetch_page."),
|
|
7
|
+
});
|
|
8
|
+
const REQUIRED_PROPERTIES_BY_TYPE = {
|
|
9
|
+
Article: ["headline", "datePublished", "author"],
|
|
10
|
+
NewsArticle: ["headline", "datePublished", "author"],
|
|
11
|
+
BlogPosting: ["headline", "datePublished", "author"],
|
|
12
|
+
Product: ["name"],
|
|
13
|
+
FAQPage: ["mainEntity"],
|
|
14
|
+
HowTo: ["name", "step"],
|
|
15
|
+
Recipe: ["name", "recipeIngredient", "recipeInstructions"],
|
|
16
|
+
Event: ["name", "startDate", "location"],
|
|
17
|
+
Organization: ["name"],
|
|
18
|
+
LocalBusiness: ["name", "address"],
|
|
19
|
+
Person: ["name"],
|
|
20
|
+
BreadcrumbList: ["itemListElement"],
|
|
21
|
+
VideoObject: ["name", "description", "thumbnailUrl", "uploadDate"],
|
|
22
|
+
};
|
|
23
|
+
const outputSchema = z.object({
|
|
24
|
+
url: z.string(),
|
|
25
|
+
blocks: z.array(z.object({
|
|
26
|
+
index: z.number().int().nonnegative(),
|
|
27
|
+
types: z.array(z.string()),
|
|
28
|
+
hasContext: z.boolean(),
|
|
29
|
+
missingRequired: z.array(z.string()),
|
|
30
|
+
ok: z.boolean(),
|
|
31
|
+
})),
|
|
32
|
+
totalBlocks: z.number().int().nonnegative(),
|
|
33
|
+
okBlocks: z.number().int().nonnegative(),
|
|
34
|
+
});
|
|
35
|
+
function typesOf(block) {
|
|
36
|
+
if (typeof block !== "object" || block === null)
|
|
37
|
+
return [];
|
|
38
|
+
const t = block["@type"];
|
|
39
|
+
if (typeof t === "string")
|
|
40
|
+
return [t];
|
|
41
|
+
if (Array.isArray(t))
|
|
42
|
+
return t.filter((x) => typeof x === "string");
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
export const validateJsonLdTool = defineTool({
|
|
46
|
+
name: "validate_jsonld",
|
|
47
|
+
description: "Validate JSON-LD blocks on a previously-fetched page against Schema.org required-property expectations (Article needs headline/datePublished/author; FAQPage needs mainEntity; Product needs name; Event needs name/startDate/location; etc.). Reports per-block missing fields. Use this to inform `add_jsonld` patch proposals.",
|
|
48
|
+
inputSchema,
|
|
49
|
+
outputSchema,
|
|
50
|
+
async execute({ pageId }) {
|
|
51
|
+
const entry = resolvePage(pageId);
|
|
52
|
+
const parsed = parseHtmlPage(entry.html, entry.url);
|
|
53
|
+
const blocks = parsed.jsonLd.map((block, index) => {
|
|
54
|
+
if (typeof block !== "object" || block === null) {
|
|
55
|
+
return { index, types: [], hasContext: false, missingRequired: [], ok: false };
|
|
56
|
+
}
|
|
57
|
+
const obj = block;
|
|
58
|
+
const types = typesOf(block);
|
|
59
|
+
const hasContext = obj["@context"] !== undefined;
|
|
60
|
+
const missing = new Set();
|
|
61
|
+
for (const t of types) {
|
|
62
|
+
const required = REQUIRED_PROPERTIES_BY_TYPE[t] ?? [];
|
|
63
|
+
for (const prop of required) {
|
|
64
|
+
if (obj[prop] === undefined)
|
|
65
|
+
missing.add(prop);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
index,
|
|
70
|
+
types,
|
|
71
|
+
hasContext,
|
|
72
|
+
missingRequired: Array.from(missing).sort(),
|
|
73
|
+
ok: hasContext && missing.size === 0 && types.length > 0,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
url: parsed.url,
|
|
78
|
+
blocks,
|
|
79
|
+
totalBlocks: blocks.length,
|
|
80
|
+
okBlocks: blocks.filter((b) => b.ok).length,
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=validate-jsonld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-jsonld.js","sourceRoot":"","sources":["../../../src/ai/tools/validate-jsonld.ts"],"names":[],"mappings":"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"}
|
package/dist/auditor.d.ts
CHANGED
|
@@ -10,5 +10,9 @@ import { type SiteClassification } from "./site-classifier.js";
|
|
|
10
10
|
* preserved by reference.
|
|
11
11
|
*/
|
|
12
12
|
export declare function applyScoringProfileOverrides(findings: RuleResult[], classification: SiteClassification | undefined): RuleResult[];
|
|
13
|
+
export declare function parseSitemapUrlsWithLastmod(xml: string): Array<{
|
|
14
|
+
url: string;
|
|
15
|
+
lastmod?: string;
|
|
16
|
+
}>;
|
|
13
17
|
export declare function auditSource(source: string, options?: AuditOptions): Promise<AuditSummary>;
|
|
14
18
|
//# sourceMappingURL=auditor.d.ts.map
|
package/dist/auditor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auditor.d.ts","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auditor.d.ts","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"AA8DA,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EAaZ,UAAU,EAGX,MAAM,YAAY,CAAC;AAQpB,OAAO,EAAgB,KAAK,kBAAkB,EAAiB,MAAM,sBAAsB,CAAC;AA8xB5F;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,UAAU,EAAE,EACtB,cAAc,EAAE,kBAAkB,GAAG,SAAS,GAC7C,UAAU,EAAE,CAed;AA8VD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBjG;AA2fD,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA68B/F"}
|