@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.
Files changed (321) hide show
  1. package/README.md +264 -169
  2. package/dist/ai/manifest/diff.d.ts +78 -0
  3. package/dist/ai/manifest/diff.d.ts.map +1 -0
  4. package/dist/ai/manifest/diff.js +139 -0
  5. package/dist/ai/manifest/diff.js.map +1 -0
  6. package/dist/ai/manifest/index.d.ts +18 -0
  7. package/dist/ai/manifest/index.d.ts.map +1 -0
  8. package/dist/ai/manifest/index.js +15 -0
  9. package/dist/ai/manifest/index.js.map +1 -0
  10. package/dist/ai/manifest/validate-manifest.d.ts +37 -0
  11. package/dist/ai/manifest/validate-manifest.d.ts.map +1 -0
  12. package/dist/ai/manifest/validate-manifest.js +67 -0
  13. package/dist/ai/manifest/validate-manifest.js.map +1 -0
  14. package/dist/ai/manifest/validators/domain-patches.d.ts +15 -0
  15. package/dist/ai/manifest/validators/domain-patches.d.ts.map +1 -0
  16. package/dist/ai/manifest/validators/domain-patches.js +110 -0
  17. package/dist/ai/manifest/validators/domain-patches.js.map +1 -0
  18. package/dist/ai/manifest/validators/index.d.ts +5 -0
  19. package/dist/ai/manifest/validators/index.d.ts.map +1 -0
  20. package/dist/ai/manifest/validators/index.js +4 -0
  21. package/dist/ai/manifest/validators/index.js.map +1 -0
  22. package/dist/ai/manifest/validators/page-changes.d.ts +36 -0
  23. package/dist/ai/manifest/validators/page-changes.d.ts.map +1 -0
  24. package/dist/ai/manifest/validators/page-changes.js +221 -0
  25. package/dist/ai/manifest/validators/page-changes.js.map +1 -0
  26. package/dist/ai/manifest/validators/types.d.ts +17 -0
  27. package/dist/ai/manifest/validators/types.d.ts.map +1 -0
  28. package/dist/ai/manifest/validators/types.js +5 -0
  29. package/dist/ai/manifest/validators/types.js.map +1 -0
  30. package/dist/ai/orchestrate.d.ts +74 -0
  31. package/dist/ai/orchestrate.d.ts.map +1 -0
  32. package/dist/ai/orchestrate.js +54 -0
  33. package/dist/ai/orchestrate.js.map +1 -0
  34. package/dist/ai/orchestrator/budget.d.ts +57 -0
  35. package/dist/ai/orchestrator/budget.d.ts.map +1 -0
  36. package/dist/ai/orchestrator/budget.js +114 -0
  37. package/dist/ai/orchestrator/budget.js.map +1 -0
  38. package/dist/ai/orchestrator/finish-tool.d.ts +568 -0
  39. package/dist/ai/orchestrator/finish-tool.d.ts.map +1 -0
  40. package/dist/ai/orchestrator/finish-tool.js +114 -0
  41. package/dist/ai/orchestrator/finish-tool.js.map +1 -0
  42. package/dist/ai/orchestrator/index.d.ts +25 -0
  43. package/dist/ai/orchestrator/index.d.ts.map +1 -0
  44. package/dist/ai/orchestrator/index.js +21 -0
  45. package/dist/ai/orchestrator/index.js.map +1 -0
  46. package/dist/ai/orchestrator/log.d.ts +24 -0
  47. package/dist/ai/orchestrator/log.d.ts.map +1 -0
  48. package/dist/ai/orchestrator/log.js +48 -0
  49. package/dist/ai/orchestrator/log.js.map +1 -0
  50. package/dist/ai/orchestrator/page-cache.d.ts +64 -0
  51. package/dist/ai/orchestrator/page-cache.d.ts.map +1 -0
  52. package/dist/ai/orchestrator/page-cache.js +127 -0
  53. package/dist/ai/orchestrator/page-cache.js.map +1 -0
  54. package/dist/ai/orchestrator/prompt.d.ts +16 -0
  55. package/dist/ai/orchestrator/prompt.d.ts.map +1 -0
  56. package/dist/ai/orchestrator/prompt.js +52 -0
  57. package/dist/ai/orchestrator/prompt.js.map +1 -0
  58. package/dist/ai/orchestrator/runner.d.ts +65 -0
  59. package/dist/ai/orchestrator/runner.d.ts.map +1 -0
  60. package/dist/ai/orchestrator/runner.js +223 -0
  61. package/dist/ai/orchestrator/runner.js.map +1 -0
  62. package/dist/ai/orchestrator/session.d.ts +44 -0
  63. package/dist/ai/orchestrator/session.d.ts.map +1 -0
  64. package/dist/ai/orchestrator/session.js +64 -0
  65. package/dist/ai/orchestrator/session.js.map +1 -0
  66. package/dist/ai/orchestrator/types.d.ts +99 -0
  67. package/dist/ai/orchestrator/types.d.ts.map +1 -0
  68. package/dist/ai/orchestrator/types.js +8 -0
  69. package/dist/ai/orchestrator/types.js.map +1 -0
  70. package/dist/ai/probes/cache.d.ts +12 -0
  71. package/dist/ai/probes/cache.d.ts.map +1 -0
  72. package/dist/ai/probes/cache.js +46 -0
  73. package/dist/ai/probes/cache.js.map +1 -0
  74. package/dist/ai/tools/ask-ai-engine.d.ts +77 -0
  75. package/dist/ai/tools/ask-ai-engine.d.ts.map +1 -0
  76. package/dist/ai/tools/ask-ai-engine.js +253 -0
  77. package/dist/ai/tools/ask-ai-engine.js.map +1 -0
  78. package/dist/ai/tools/check-domain-crawler-access.d.ts +71 -0
  79. package/dist/ai/tools/check-domain-crawler-access.d.ts.map +1 -0
  80. package/dist/ai/tools/check-domain-crawler-access.js +76 -0
  81. package/dist/ai/tools/check-domain-crawler-access.js.map +1 -0
  82. package/dist/ai/tools/check-domain-llms-txt.d.ts +70 -0
  83. package/dist/ai/tools/check-domain-llms-txt.d.ts.map +1 -0
  84. package/dist/ai/tools/check-domain-llms-txt.js +75 -0
  85. package/dist/ai/tools/check-domain-llms-txt.js.map +1 -0
  86. package/dist/ai/tools/check-indexability.d.ts +58 -0
  87. package/dist/ai/tools/check-indexability.d.ts.map +1 -0
  88. package/dist/ai/tools/check-indexability.js +64 -0
  89. package/dist/ai/tools/check-indexability.js.map +1 -0
  90. package/dist/ai/tools/check-robots.d.ts +68 -0
  91. package/dist/ai/tools/check-robots.d.ts.map +1 -0
  92. package/dist/ai/tools/check-robots.js +90 -0
  93. package/dist/ai/tools/check-robots.js.map +1 -0
  94. package/dist/ai/tools/check-rule-answer-first.d.ts +54 -0
  95. package/dist/ai/tools/check-rule-answer-first.d.ts.map +1 -0
  96. package/dist/ai/tools/check-rule-answer-first.js +50 -0
  97. package/dist/ai/tools/check-rule-answer-first.js.map +1 -0
  98. package/dist/ai/tools/check-rule-canonical-consistency.d.ts +66 -0
  99. package/dist/ai/tools/check-rule-canonical-consistency.d.ts.map +1 -0
  100. package/dist/ai/tools/check-rule-canonical-consistency.js +51 -0
  101. package/dist/ai/tools/check-rule-canonical-consistency.js.map +1 -0
  102. package/dist/ai/tools/check-rule-citable-facts.d.ts +58 -0
  103. package/dist/ai/tools/check-rule-citable-facts.d.ts.map +1 -0
  104. package/dist/ai/tools/check-rule-citable-facts.js +41 -0
  105. package/dist/ai/tools/check-rule-citable-facts.js.map +1 -0
  106. package/dist/ai/tools/check-rule-content-modularity.d.ts +58 -0
  107. package/dist/ai/tools/check-rule-content-modularity.d.ts.map +1 -0
  108. package/dist/ai/tools/check-rule-content-modularity.js +45 -0
  109. package/dist/ai/tools/check-rule-content-modularity.js.map +1 -0
  110. package/dist/ai/tools/check-rule-faq-coverage.d.ts +54 -0
  111. package/dist/ai/tools/check-rule-faq-coverage.d.ts.map +1 -0
  112. package/dist/ai/tools/check-rule-faq-coverage.js +39 -0
  113. package/dist/ai/tools/check-rule-faq-coverage.js.map +1 -0
  114. package/dist/ai/tools/check-rule-freshness-signals.d.ts +54 -0
  115. package/dist/ai/tools/check-rule-freshness-signals.d.ts.map +1 -0
  116. package/dist/ai/tools/check-rule-freshness-signals.js +45 -0
  117. package/dist/ai/tools/check-rule-freshness-signals.js.map +1 -0
  118. package/dist/ai/tools/check-rule-json-ld-valid.d.ts +54 -0
  119. package/dist/ai/tools/check-rule-json-ld-valid.d.ts.map +1 -0
  120. package/dist/ai/tools/check-rule-json-ld-valid.js +44 -0
  121. package/dist/ai/tools/check-rule-json-ld-valid.js.map +1 -0
  122. package/dist/ai/tools/check-rule-missing-author.d.ts +54 -0
  123. package/dist/ai/tools/check-rule-missing-author.d.ts.map +1 -0
  124. package/dist/ai/tools/check-rule-missing-author.js +45 -0
  125. package/dist/ai/tools/check-rule-missing-author.js.map +1 -0
  126. package/dist/ai/tools/check-rule-near-duplicate.d.ts +82 -0
  127. package/dist/ai/tools/check-rule-near-duplicate.d.ts.map +1 -0
  128. package/dist/ai/tools/check-rule-near-duplicate.js +63 -0
  129. package/dist/ai/tools/check-rule-near-duplicate.js.map +1 -0
  130. package/dist/ai/tools/check-rule-required-fields.d.ts +50 -0
  131. package/dist/ai/tools/check-rule-required-fields.d.ts.map +1 -0
  132. package/dist/ai/tools/check-rule-required-fields.js +38 -0
  133. package/dist/ai/tools/check-rule-required-fields.js.map +1 -0
  134. package/dist/ai/tools/check-rule-schema-consistency.d.ts +54 -0
  135. package/dist/ai/tools/check-rule-schema-consistency.d.ts.map +1 -0
  136. package/dist/ai/tools/check-rule-schema-consistency.js +44 -0
  137. package/dist/ai/tools/check-rule-schema-consistency.js.map +1 -0
  138. package/dist/ai/tools/check-rule-summary-bait.d.ts +54 -0
  139. package/dist/ai/tools/check-rule-summary-bait.d.ts.map +1 -0
  140. package/dist/ai/tools/check-rule-summary-bait.js +39 -0
  141. package/dist/ai/tools/check-rule-summary-bait.js.map +1 -0
  142. package/dist/ai/tools/check-rule-thin-content.d.ts +66 -0
  143. package/dist/ai/tools/check-rule-thin-content.d.ts.map +1 -0
  144. package/dist/ai/tools/check-rule-thin-content.js +58 -0
  145. package/dist/ai/tools/check-rule-thin-content.js.map +1 -0
  146. package/dist/ai/tools/detect-templates.d.ts +60 -0
  147. package/dist/ai/tools/detect-templates.d.ts.map +1 -0
  148. package/dist/ai/tools/detect-templates.js +43 -0
  149. package/dist/ai/tools/detect-templates.js.map +1 -0
  150. package/dist/ai/tools/fetch-page.d.ts +70 -0
  151. package/dist/ai/tools/fetch-page.d.ts.map +1 -0
  152. package/dist/ai/tools/fetch-page.js +93 -0
  153. package/dist/ai/tools/fetch-page.js.map +1 -0
  154. package/dist/ai/tools/fetch-sitemap.d.ts +60 -0
  155. package/dist/ai/tools/fetch-sitemap.d.ts.map +1 -0
  156. package/dist/ai/tools/fetch-sitemap.js +116 -0
  157. package/dist/ai/tools/fetch-sitemap.js.map +1 -0
  158. package/dist/ai/tools/index.d.ts +1555 -0
  159. package/dist/ai/tools/index.d.ts.map +1 -0
  160. package/dist/ai/tools/index.js +119 -0
  161. package/dist/ai/tools/index.js.map +1 -0
  162. package/dist/ai/tools/parse-page.d.ts +94 -0
  163. package/dist/ai/tools/parse-page.d.ts.map +1 -0
  164. package/dist/ai/tools/parse-page.js +108 -0
  165. package/dist/ai/tools/parse-page.js.map +1 -0
  166. package/dist/ai/tools/query-serp.d.ts +113 -0
  167. package/dist/ai/tools/query-serp.d.ts.map +1 -0
  168. package/dist/ai/tools/query-serp.js +131 -0
  169. package/dist/ai/tools/query-serp.js.map +1 -0
  170. package/dist/ai/tools/sample-template.d.ts +67 -0
  171. package/dist/ai/tools/sample-template.d.ts.map +1 -0
  172. package/dist/ai/tools/sample-template.js +75 -0
  173. package/dist/ai/tools/sample-template.js.map +1 -0
  174. package/dist/ai/tools/types.d.ts +73 -0
  175. package/dist/ai/tools/types.d.ts.map +1 -0
  176. package/dist/ai/tools/types.js +64 -0
  177. package/dist/ai/tools/types.js.map +1 -0
  178. package/dist/ai/tools/validate-jsonld.d.ts +62 -0
  179. package/dist/ai/tools/validate-jsonld.d.ts.map +1 -0
  180. package/dist/ai/tools/validate-jsonld.js +84 -0
  181. package/dist/ai/tools/validate-jsonld.js.map +1 -0
  182. package/dist/auditor.d.ts +16 -1
  183. package/dist/auditor.d.ts.map +1 -1
  184. package/dist/auditor.js +862 -88
  185. package/dist/auditor.js.map +1 -1
  186. package/dist/backpressure.d.ts.map +1 -1
  187. package/dist/backpressure.js +10 -3
  188. package/dist/backpressure.js.map +1 -1
  189. package/dist/enrich-findings.d.ts.map +1 -1
  190. package/dist/enrich-findings.js +15 -1
  191. package/dist/enrich-findings.js.map +1 -1
  192. package/dist/formatters/bucket-findings.d.ts +43 -0
  193. package/dist/formatters/bucket-findings.d.ts.map +1 -0
  194. package/dist/formatters/bucket-findings.js +110 -0
  195. package/dist/formatters/bucket-findings.js.map +1 -0
  196. package/dist/formatters/console.d.ts.map +1 -1
  197. package/dist/formatters/console.js +116 -34
  198. package/dist/formatters/console.js.map +1 -1
  199. package/dist/formatters/fixplan.d.ts +13 -0
  200. package/dist/formatters/fixplan.d.ts.map +1 -0
  201. package/dist/formatters/fixplan.js +328 -0
  202. package/dist/formatters/fixplan.js.map +1 -0
  203. package/dist/formatters/html.d.ts.map +1 -1
  204. package/dist/formatters/html.js +27 -0
  205. package/dist/formatters/html.js.map +1 -1
  206. package/dist/formatters/index.d.ts +2 -0
  207. package/dist/formatters/index.d.ts.map +1 -1
  208. package/dist/formatters/index.js +1 -0
  209. package/dist/formatters/index.js.map +1 -1
  210. package/dist/formatters/markdown.d.ts.map +1 -1
  211. package/dist/formatters/markdown.js +97 -9
  212. package/dist/formatters/markdown.js.map +1 -1
  213. package/dist/index.d.ts +12 -1
  214. package/dist/index.d.ts.map +1 -1
  215. package/dist/index.js +8 -0
  216. package/dist/index.js.map +1 -1
  217. package/dist/page-filter.d.ts +64 -6
  218. package/dist/page-filter.d.ts.map +1 -1
  219. package/dist/page-filter.js +124 -3
  220. package/dist/page-filter.js.map +1 -1
  221. package/dist/rule-references.d.ts.map +1 -1
  222. package/dist/rule-references.js +5 -0
  223. package/dist/rule-references.js.map +1 -1
  224. package/dist/rules/aeo/answer-first.d.ts.map +1 -1
  225. package/dist/rules/aeo/answer-first.js +17 -3
  226. package/dist/rules/aeo/answer-first.js.map +1 -1
  227. package/dist/rules/aeo/citable-facts.d.ts.map +1 -1
  228. package/dist/rules/aeo/citable-facts.js +12 -1
  229. package/dist/rules/aeo/citable-facts.js.map +1 -1
  230. package/dist/rules/aeo/content-modularity.d.ts.map +1 -1
  231. package/dist/rules/aeo/content-modularity.js +3 -0
  232. package/dist/rules/aeo/content-modularity.js.map +1 -1
  233. package/dist/rules/aeo/crawler-access.d.ts.map +1 -1
  234. package/dist/rules/aeo/crawler-access.js +6 -0
  235. package/dist/rules/aeo/crawler-access.js.map +1 -1
  236. package/dist/rules/aeo/faq-coverage.d.ts.map +1 -1
  237. package/dist/rules/aeo/faq-coverage.js +4 -0
  238. package/dist/rules/aeo/faq-coverage.js.map +1 -1
  239. package/dist/rules/aeo/freshness-signals.d.ts.map +1 -1
  240. package/dist/rules/aeo/freshness-signals.js +9 -2
  241. package/dist/rules/aeo/freshness-signals.js.map +1 -1
  242. package/dist/rules/aeo/llms-txt.d.ts.map +1 -1
  243. package/dist/rules/aeo/llms-txt.js +6 -1
  244. package/dist/rules/aeo/llms-txt.js.map +1 -1
  245. package/dist/rules/aeo/summary-bait.d.ts.map +1 -1
  246. package/dist/rules/aeo/summary-bait.js +5 -2
  247. package/dist/rules/aeo/summary-bait.js.map +1 -1
  248. package/dist/rules/content/heading-structure.d.ts +21 -0
  249. package/dist/rules/content/heading-structure.d.ts.map +1 -0
  250. package/dist/rules/content/heading-structure.js +56 -0
  251. package/dist/rules/content/heading-structure.js.map +1 -0
  252. package/dist/rules/content/image-alt-text.d.ts +18 -0
  253. package/dist/rules/content/image-alt-text.d.ts.map +1 -0
  254. package/dist/rules/content/image-alt-text.js +77 -0
  255. package/dist/rules/content/image-alt-text.js.map +1 -0
  256. package/dist/rules/content/missing-author.d.ts.map +1 -1
  257. package/dist/rules/content/missing-author.js +10 -2
  258. package/dist/rules/content/missing-author.js.map +1 -1
  259. package/dist/rules/content/title-uniqueness.d.ts +18 -0
  260. package/dist/rules/content/title-uniqueness.d.ts.map +1 -0
  261. package/dist/rules/content/title-uniqueness.js +70 -0
  262. package/dist/rules/content/title-uniqueness.js.map +1 -0
  263. package/dist/rules/links/host-section-divergence.d.ts +3 -0
  264. package/dist/rules/links/host-section-divergence.d.ts.map +1 -0
  265. package/dist/rules/links/host-section-divergence.js +158 -0
  266. package/dist/rules/links/host-section-divergence.js.map +1 -0
  267. package/dist/rules/links/link-depth.d.ts +12 -1
  268. package/dist/rules/links/link-depth.d.ts.map +1 -1
  269. package/dist/rules/links/link-depth.js +25 -12
  270. package/dist/rules/links/link-depth.js.map +1 -1
  271. package/dist/rules/scope.d.ts.map +1 -1
  272. package/dist/rules/scope.js +5 -0
  273. package/dist/rules/scope.js.map +1 -1
  274. package/dist/rules/spam/doorway-pattern.d.ts.map +1 -1
  275. package/dist/rules/spam/doorway-pattern.js +27 -4
  276. package/dist/rules/spam/doorway-pattern.js.map +1 -1
  277. package/dist/rules/spam/publication-velocity.d.ts +1 -1
  278. package/dist/rules/spam/publication-velocity.d.ts.map +1 -1
  279. package/dist/rules/spam/publication-velocity.js +9 -4
  280. package/dist/rules/spam/publication-velocity.js.map +1 -1
  281. package/dist/rules/spam/template-coverage.js +1 -1
  282. package/dist/rules/spam/template-coverage.js.map +1 -1
  283. package/dist/rules/spam/template-diversity.js +1 -1
  284. package/dist/rules/spam/template-diversity.js.map +1 -1
  285. package/dist/rules/spam/thin-content.d.ts.map +1 -1
  286. package/dist/rules/spam/thin-content.js +9 -1
  287. package/dist/rules/spam/thin-content.js.map +1 -1
  288. package/dist/rules/tech/hreflang-consistency.d.ts.map +1 -1
  289. package/dist/rules/tech/hreflang-consistency.js +33 -4
  290. package/dist/rules/tech/hreflang-consistency.js.map +1 -1
  291. package/dist/rules/tech/og-completeness.d.ts +11 -0
  292. package/dist/rules/tech/og-completeness.d.ts.map +1 -1
  293. package/dist/rules/tech/og-completeness.js +22 -23
  294. package/dist/rules/tech/og-completeness.js.map +1 -1
  295. package/dist/ruleset-version.d.ts +8 -0
  296. package/dist/ruleset-version.d.ts.map +1 -0
  297. package/dist/ruleset-version.js +8 -0
  298. package/dist/ruleset-version.js.map +1 -0
  299. package/dist/scrape-strategy.d.ts +42 -0
  300. package/dist/scrape-strategy.d.ts.map +1 -0
  301. package/dist/scrape-strategy.js +101 -0
  302. package/dist/scrape-strategy.js.map +1 -0
  303. package/dist/site-classifier.d.ts +1 -1
  304. package/dist/site-classifier.d.ts.map +1 -1
  305. package/dist/site-classifier.js +217 -0
  306. package/dist/site-classifier.js.map +1 -1
  307. package/dist/state.d.ts +36 -1
  308. package/dist/state.d.ts.map +1 -1
  309. package/dist/state.js +3 -1
  310. package/dist/state.js.map +1 -1
  311. package/dist/stratified-sample.d.ts +9 -1
  312. package/dist/stratified-sample.d.ts.map +1 -1
  313. package/dist/stratified-sample.js +23 -6
  314. package/dist/stratified-sample.js.map +1 -1
  315. package/dist/types.d.ts +179 -2
  316. package/dist/types.d.ts.map +1 -1
  317. package/dist/types.js.map +1 -1
  318. package/dist/url-normalize.d.ts.map +1 -1
  319. package/dist/url-normalize.js +13 -1
  320. package/dist/url-normalize.js.map +1 -1
  321. package/package.json +90 -90
@@ -0,0 +1,139 @@
1
+ /** HTML-escape a string for safe interpolation into attribute or text content. */
2
+ function escapeHtml(s) {
3
+ return s
4
+ .replace(/&/g, "&")
5
+ .replace(/</g, "&lt;")
6
+ .replace(/>/g, "&gt;")
7
+ .replace(/"/g, "&quot;")
8
+ .replace(/'/g, "&#39;");
9
+ }
10
+ function serializeJsonLd(block) {
11
+ return `<script type="application/ld+json">\n${JSON.stringify(block, null, 2)}\n</script>`;
12
+ }
13
+ /**
14
+ * Convert a single page-change into a `PatchDiff`. Pure transformation —
15
+ * does not validate (use `validatePageChange` for that). The two should
16
+ * be called in sequence at manifest finalization: validate first, drop
17
+ * failures, then diff the survivors.
18
+ */
19
+ export function diffPageChange(c) {
20
+ switch (c.type) {
21
+ case "replace_h1":
22
+ return {
23
+ kind: "text_replace",
24
+ field: "h1",
25
+ before: c.before,
26
+ after: c.after,
27
+ reason: c.reason,
28
+ };
29
+ case "rewrite_meta":
30
+ return {
31
+ kind: "text_replace",
32
+ field: c.field === "title" ? "title" : "meta_description",
33
+ before: c.before,
34
+ after: c.after,
35
+ reason: c.reason,
36
+ };
37
+ case "add_jsonld":
38
+ return {
39
+ kind: "html_insert",
40
+ target: "head",
41
+ description: `JSON-LD block (@type: ${(() => {
42
+ const t = c.block["@type"];
43
+ if (typeof t === "string")
44
+ return t;
45
+ if (Array.isArray(t))
46
+ return t.filter((x) => typeof x === "string").join(", ");
47
+ return "unknown";
48
+ })()})`,
49
+ html: serializeJsonLd(c.block),
50
+ reason: c.reason,
51
+ };
52
+ case "add_faq_block":
53
+ return {
54
+ kind: "html_insert",
55
+ target: "body",
56
+ description: "FAQ block",
57
+ html: c.html,
58
+ reason: c.reason,
59
+ };
60
+ case "rewrite_intro":
61
+ return {
62
+ kind: "text_replace",
63
+ field: "intro",
64
+ before: c.before,
65
+ after: c.after,
66
+ reason: c.reason,
67
+ };
68
+ case "add_internal_link":
69
+ // Escape both anchor text and href to prevent XSS in the rendered
70
+ // snippet. The validator already enforces same-host + non-empty
71
+ // anchor; this is defense in depth at the diff layer.
72
+ return {
73
+ kind: "html_insert",
74
+ target: "after_h1",
75
+ description: `Internal link → ${c.to}`,
76
+ html: `<a href="${escapeHtml(c.to)}">${escapeHtml(c.anchor)}</a>`,
77
+ reason: c.reason,
78
+ };
79
+ case "remove_thin_block":
80
+ return {
81
+ kind: "html_remove",
82
+ selector: c.selector,
83
+ reason: c.reason,
84
+ };
85
+ }
86
+ }
87
+ /** Convert a single domain patch into a `PatchDiff`. */
88
+ export function diffDomainPatch(p) {
89
+ switch (p.type) {
90
+ case "robots_txt":
91
+ return {
92
+ kind: "file_replace",
93
+ path: "/robots.txt",
94
+ before: p.before,
95
+ after: p.after,
96
+ reason: p.reason,
97
+ };
98
+ case "sitemap_xml":
99
+ return {
100
+ kind: "file_replace",
101
+ path: "/sitemap.xml",
102
+ before: p.before,
103
+ after: p.after,
104
+ reason: p.reason,
105
+ };
106
+ case "canonical_strategy":
107
+ return {
108
+ kind: "guidance",
109
+ topic: "canonical_strategy",
110
+ text: p.after,
111
+ reason: p.reason,
112
+ };
113
+ }
114
+ }
115
+ /**
116
+ * Walk every patch in a manifest and produce a structured-diff projection.
117
+ * Mirrors the manifest's tree structure so the UI can render side-by-side
118
+ * (page list / template clusters / domain-level), each populated with
119
+ * already-typed patch diffs.
120
+ */
121
+ export function diffManifest(manifest) {
122
+ return {
123
+ pages: manifest.pages.map((p) => ({
124
+ url: p.url,
125
+ diffs: p.changes.map(diffPageChange),
126
+ })),
127
+ templates: manifest.templates.map((t) => ({
128
+ templateId: t.templateId,
129
+ affectedUrlCount: t.affectedUrlCount,
130
+ recommendation: t.recommendation,
131
+ examples: t.examples.map((e) => ({
132
+ url: e.url,
133
+ diffs: e.changes.map(diffPageChange),
134
+ })),
135
+ })),
136
+ domainLevel: manifest.domainLevel.map(diffDomainPatch),
137
+ };
138
+ }
139
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/ai/manifest/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Manifest validation layer. Patches proposed by the LLM via `finish_audit`
3
+ * pass through these validators before the manifest is persisted to R2.
4
+ * Failures are not silently dropped — the caller (web app's session
5
+ * finalization) decides whether to retry the LLM, drop the failed patches,
6
+ * or surface them as a "needs human review" subset.
7
+ *
8
+ * Phase 4 batch 1 = validators only. Diff generation + ZIP bundle export
9
+ * land in batch 2.
10
+ */
11
+ export { validateAddJsonLd, validateReplaceH1, validateRewriteMeta, validateAddFaqBlock, validateRewriteIntro, validateAddInternalLink, validateRemoveThinBlock, validatePageChange, validateRobotsTxt, validateSitemapXml, validateCanonicalStrategy, validateDomainPatch, } from "./validators/index.js";
12
+ export type { ValidationOk, ValidationErr, ValidationResult } from "./validators/index.js";
13
+ export { VALID, fail } from "./validators/index.js";
14
+ export { validateManifest, } from "./validate-manifest.js";
15
+ export type { ManifestValidationReport, PatchValidationFailure, } from "./validate-manifest.js";
16
+ export { diffPageChange, diffDomainPatch, diffManifest, } from "./diff.js";
17
+ export type { PatchDiff, ManifestDiff } from "./diff.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ai/manifest/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Manifest validation layer. Patches proposed by the LLM via `finish_audit`
3
+ * pass through these validators before the manifest is persisted to R2.
4
+ * Failures are not silently dropped — the caller (web app's session
5
+ * finalization) decides whether to retry the LLM, drop the failed patches,
6
+ * or surface them as a "needs human review" subset.
7
+ *
8
+ * Phase 4 batch 1 = validators only. Diff generation + ZIP bundle export
9
+ * land in batch 2.
10
+ */
11
+ export { validateAddJsonLd, validateReplaceH1, validateRewriteMeta, validateAddFaqBlock, validateRewriteIntro, validateAddInternalLink, validateRemoveThinBlock, validatePageChange, validateRobotsTxt, validateSitemapXml, validateCanonicalStrategy, validateDomainPatch, } from "./validators/index.js";
12
+ export { VALID, fail } from "./validators/index.js";
13
+ export { validateManifest, } from "./validate-manifest.js";
14
+ export { diffPageChange, diffDomainPatch, diffManifest, } from "./diff.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ai/manifest/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EACL,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAMhC,OAAO,EACL,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,WAAW,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { FixManifest } from "../orchestrator/finish-tool.js";
2
+ export interface PatchValidationFailure {
3
+ /** Where in the manifest the failed patch lives. Used by the manifest UI to highlight + drop. */
4
+ location: {
5
+ kind: "page_patch";
6
+ pageIndex: number;
7
+ changeIndex: number;
8
+ pageUrl: string;
9
+ patchType: string;
10
+ } | {
11
+ kind: "template_patch";
12
+ templateIndex: number;
13
+ exampleIndex: number;
14
+ changeIndex: number;
15
+ templateId: string;
16
+ patchType: string;
17
+ } | {
18
+ kind: "domain_patch";
19
+ index: number;
20
+ patchType: string;
21
+ };
22
+ reason: string;
23
+ }
24
+ export interface ManifestValidationReport {
25
+ totalPatches: number;
26
+ validPatches: number;
27
+ failures: PatchValidationFailure[];
28
+ }
29
+ /**
30
+ * Walk every patch in the manifest and return a per-failure report. Does
31
+ * NOT mutate the manifest — the caller decides what to do (drop failed
32
+ * patches, surface them in a "rejected" section, retry the LLM with
33
+ * feedback). Phase 4's manifest-finalization step will use this to filter
34
+ * the manifest before persistence.
35
+ */
36
+ export declare function validateManifest(manifest: FixManifest): ManifestValidationReport;
37
+ //# sourceMappingURL=validate-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-manifest.d.ts","sourceRoot":"","sources":["../../../src/ai/manifest/validate-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAGlE,MAAM,WAAW,sBAAsB;IACrC,iGAAiG;IACjG,QAAQ,EACJ;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAClG;QAAE,IAAI,EAAE,gBAAgB,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GACnI;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,sBAAsB,EAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,GAAG,wBAAwB,CA6DhF"}
@@ -0,0 +1,67 @@
1
+ import { validatePageChange, validateDomainPatch } from "./validators/index.js";
2
+ /**
3
+ * Walk every patch in the manifest and return a per-failure report. Does
4
+ * NOT mutate the manifest — the caller decides what to do (drop failed
5
+ * patches, surface them in a "rejected" section, retry the LLM with
6
+ * feedback). Phase 4's manifest-finalization step will use this to filter
7
+ * the manifest before persistence.
8
+ */
9
+ export function validateManifest(manifest) {
10
+ const failures = [];
11
+ let total = 0;
12
+ manifest.pages.forEach((page, pageIndex) => {
13
+ page.changes.forEach((change, changeIndex) => {
14
+ total += 1;
15
+ const result = validatePageChange(change);
16
+ if (!result.valid) {
17
+ failures.push({
18
+ location: {
19
+ kind: "page_patch",
20
+ pageIndex,
21
+ changeIndex,
22
+ pageUrl: page.url,
23
+ patchType: change.type,
24
+ },
25
+ reason: result.reason,
26
+ });
27
+ }
28
+ });
29
+ });
30
+ manifest.templates.forEach((template, templateIndex) => {
31
+ template.examples.forEach((example, exampleIndex) => {
32
+ example.changes.forEach((change, changeIndex) => {
33
+ total += 1;
34
+ const result = validatePageChange(change);
35
+ if (!result.valid) {
36
+ failures.push({
37
+ location: {
38
+ kind: "template_patch",
39
+ templateIndex,
40
+ exampleIndex,
41
+ changeIndex,
42
+ templateId: template.templateId,
43
+ patchType: change.type,
44
+ },
45
+ reason: result.reason,
46
+ });
47
+ }
48
+ });
49
+ });
50
+ });
51
+ manifest.domainLevel.forEach((patch, index) => {
52
+ total += 1;
53
+ const result = validateDomainPatch(patch);
54
+ if (!result.valid) {
55
+ failures.push({
56
+ location: { kind: "domain_patch", index, patchType: patch.type },
57
+ reason: result.reason,
58
+ });
59
+ }
60
+ });
61
+ return {
62
+ totalPatches: total,
63
+ validPatches: total - failures.length,
64
+ failures,
65
+ };
66
+ }
67
+ //# sourceMappingURL=validate-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-manifest.js","sourceRoot":"","sources":["../../../src/ai/manifest/validate-manifest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAiBhF;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAqB;IACpD,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAC9C,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE;QACzC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;YAC3C,KAAK,IAAI,CAAC,CAAC;YACX,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;gBAClB,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE;wBACR,IAAI,EAAE,YAAY;wBAClB,SAAS;wBACT,WAAW;wBACX,OAAO,EAAE,IAAI,CAAC,GAAG;wBACjB,SAAS,EAAE,MAAM,CAAC,IAAI;qBACvB;oBACD,MAAM,EAAE,MAAM,CAAC,MAAM;iBACtB,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE;QACrD,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE;YAClD,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;gBAC9C,KAAK,IAAI,CAAC,CAAC;gBACX,MAAM,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;gBAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;oBAClB,QAAQ,CAAC,IAAI,CAAC;wBACZ,QAAQ,EAAE;4BACR,IAAI,EAAE,gBAAgB;4BACtB,aAAa;4BACb,YAAY;4BACZ,WAAW;4BACX,UAAU,EAAE,QAAQ,CAAC,UAAU;4BAC/B,SAAS,EAAE,MAAM,CAAC,IAAI;yBACvB;wBACD,MAAM,EAAE,MAAM,CAAC,MAAM;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC5C,KAAK,IAAI,CAAC,CAAC;QACX,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE;gBAChE,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,KAAK,GAAG,QAAQ,CAAC,MAAM;QACrC,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { FixManifest } from "../../orchestrator/finish-tool.js";
2
+ import { type ValidationResult } from "./types.js";
3
+ type DomainPatch = FixManifest["domainLevel"][number];
4
+ export declare function validateRobotsTxt(p: DomainPatch): ValidationResult;
5
+ export declare function validateSitemapXml(p: DomainPatch): ValidationResult;
6
+ /**
7
+ * canonical_strategy is freeform guidance text describing how the site
8
+ * should structure its canonicals (e.g. "always self-canonical except for
9
+ * paginated views which point to page 1"). Validation just rejects empty
10
+ * or trivially-short text — content quality is the LLM's call.
11
+ */
12
+ export declare function validateCanonicalStrategy(p: DomainPatch): ValidationResult;
13
+ export declare function validateDomainPatch(p: DomainPatch): ValidationResult;
14
+ export {};
15
+ //# sourceMappingURL=domain-patches.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-patches.d.ts","sourceRoot":"","sources":["../../../../src/ai/manifest/validators/domain-patches.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhE,KAAK,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AActD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAqBlE;AAgBD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAoCnE;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAM1E;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,CASpE"}
@@ -0,0 +1,110 @@
1
+ import { fail, VALID } from "./types.js";
2
+ /**
3
+ * robots.txt validation: parse line-by-line, require at least one
4
+ * `User-agent:` directive, reject lines that aren't either a comment, blank,
5
+ * or a recognized directive (User-agent, Disallow, Allow, Sitemap,
6
+ * Crawl-delay).
7
+ *
8
+ * Not as strict as a real robots-parser library — but catches the failure
9
+ * modes the LLM is most likely to produce (bad directive names, missing
10
+ * User-agent block, accidental markdown).
11
+ */
12
+ const RECOGNIZED_DIRECTIVE_RE = /^(user-agent|disallow|allow|sitemap|crawl-delay|host)\s*:/i;
13
+ export function validateRobotsTxt(p) {
14
+ const text = p.after.trim();
15
+ if (!text)
16
+ return fail("robots_txt: after-text is empty");
17
+ const lines = text.split(/\r?\n/);
18
+ let sawUserAgent = false;
19
+ let lineNo = 0;
20
+ for (const raw of lines) {
21
+ lineNo += 1;
22
+ const line = raw.trim();
23
+ if (!line)
24
+ continue;
25
+ if (line.startsWith("#"))
26
+ continue;
27
+ if (!RECOGNIZED_DIRECTIVE_RE.test(line)) {
28
+ return fail(`robots_txt: unrecognized directive on line ${lineNo}: ${line.slice(0, 60)}`);
29
+ }
30
+ if (/^user-agent\s*:/i.test(line))
31
+ sawUserAgent = true;
32
+ }
33
+ if (!sawUserAgent) {
34
+ return fail("robots_txt: no User-agent directive present");
35
+ }
36
+ return VALID;
37
+ }
38
+ /**
39
+ * sitemap.xml validation: require a recognizable root element (`<urlset>` or
40
+ * `<sitemapindex>`), require well-formed XML structure (matching open/close
41
+ * tags), require each `<url>` to carry a `<loc>` child.
42
+ *
43
+ * Skips full XSD validation — pulling in a libxml binding for one patch
44
+ * type isn't worth the deploy weight. The structural checks catch the
45
+ * common LLM failure modes.
46
+ */
47
+ const URLSET_RE = /<urlset[\s>]/i;
48
+ const SITEMAPINDEX_RE = /<sitemapindex[\s>]/i;
49
+ const URL_BLOCK_RE = /<url[\s>][\s\S]*?<\/url>/gi;
50
+ const LOC_RE = /<loc>[\s\S]*?<\/loc>/i;
51
+ export function validateSitemapXml(p) {
52
+ const xml = p.after.trim();
53
+ if (!xml)
54
+ return fail("sitemap_xml: after-text is empty");
55
+ const isUrlset = URLSET_RE.test(xml);
56
+ const isIndex = SITEMAPINDEX_RE.test(xml);
57
+ if (!isUrlset && !isIndex) {
58
+ return fail("sitemap_xml: missing <urlset> or <sitemapindex> root element");
59
+ }
60
+ // Cheap well-formed-ness check: count opening vs closing tags for the
61
+ // root element and `<url>` blocks. Mismatch indicates malformed XML.
62
+ if (isUrlset) {
63
+ const opens = (xml.match(/<urlset[\s>]/gi) ?? []).length;
64
+ const closes = (xml.match(/<\/urlset>/gi) ?? []).length;
65
+ if (opens !== closes) {
66
+ return fail("sitemap_xml: <urlset> open/close tag count mismatch");
67
+ }
68
+ const urlBlocks = xml.match(URL_BLOCK_RE) ?? [];
69
+ if (urlBlocks.length === 0) {
70
+ return fail("sitemap_xml: <urlset> has no <url> children");
71
+ }
72
+ for (const block of urlBlocks) {
73
+ if (!LOC_RE.test(block)) {
74
+ return fail("sitemap_xml: <url> block missing <loc>");
75
+ }
76
+ }
77
+ }
78
+ else {
79
+ const opens = (xml.match(/<sitemapindex[\s>]/gi) ?? []).length;
80
+ const closes = (xml.match(/<\/sitemapindex>/gi) ?? []).length;
81
+ if (opens !== closes) {
82
+ return fail("sitemap_xml: <sitemapindex> open/close tag count mismatch");
83
+ }
84
+ }
85
+ return VALID;
86
+ }
87
+ /**
88
+ * canonical_strategy is freeform guidance text describing how the site
89
+ * should structure its canonicals (e.g. "always self-canonical except for
90
+ * paginated views which point to page 1"). Validation just rejects empty
91
+ * or trivially-short text — content quality is the LLM's call.
92
+ */
93
+ export function validateCanonicalStrategy(p) {
94
+ const after = p.after.trim();
95
+ if (after.length < 30) {
96
+ return fail(`canonical_strategy: too short (${after.length} < 30 chars) — needs concrete guidance`);
97
+ }
98
+ return VALID;
99
+ }
100
+ export function validateDomainPatch(p) {
101
+ switch (p.type) {
102
+ case "robots_txt":
103
+ return validateRobotsTxt(p);
104
+ case "sitemap_xml":
105
+ return validateSitemapXml(p);
106
+ case "canonical_strategy":
107
+ return validateCanonicalStrategy(p);
108
+ }
109
+ }
110
+ //# sourceMappingURL=domain-patches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-patches.js","sourceRoot":"","sources":["../../../../src/ai/manifest/validators/domain-patches.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { VALID, fail } from "./types.js";
2
+ export type { ValidationOk, ValidationErr, ValidationResult } from "./types.js";
3
+ export { validateAddJsonLd, validateReplaceH1, validateRewriteMeta, validateAddFaqBlock, validateRewriteIntro, validateAddInternalLink, validateRemoveThinBlock, validatePageChange, } from "./page-changes.js";
4
+ export { validateRobotsTxt, validateSitemapXml, validateCanonicalStrategy, validateDomainPatch, } from "./domain-patches.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ai/manifest/validators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { VALID, fail } from "./types.js";
2
+ export { validateAddJsonLd, validateReplaceH1, validateRewriteMeta, validateAddFaqBlock, validateRewriteIntro, validateAddInternalLink, validateRemoveThinBlock, validatePageChange, } from "./page-changes.js";
3
+ export { validateRobotsTxt, validateSitemapXml, validateCanonicalStrategy, validateDomainPatch, } from "./domain-patches.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/ai/manifest/validators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGzC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { FixManifest } from "../../orchestrator/finish-tool.js";
2
+ import { type ValidationResult } from "./types.js";
3
+ type PageChange = FixManifest["pages"][number]["changes"][number];
4
+ /** Schema.org required-property check for proposed JSON-LD blocks. */
5
+ export declare function validateAddJsonLd(c: Extract<PageChange, {
6
+ type: "add_jsonld";
7
+ }>): ValidationResult;
8
+ export declare function validateReplaceH1(c: Extract<PageChange, {
9
+ type: "replace_h1";
10
+ }>): ValidationResult;
11
+ export declare function validateRewriteMeta(c: Extract<PageChange, {
12
+ type: "rewrite_meta";
13
+ }>): ValidationResult;
14
+ /**
15
+ * HTML-safety check using a cheerio-based allowlist. Rejects script/iframe/
16
+ * object/embed/form/style elements and any href/src that uses
17
+ * javascript:/data:/vbscript: schemes. Defense in depth — the LLM-generated
18
+ * patch is being prepared for paste into a CMS, not auto-applied, but a
19
+ * malicious patch in a public manifest is still a footgun.
20
+ */
21
+ export declare function validateAddFaqBlock(c: Extract<PageChange, {
22
+ type: "add_faq_block";
23
+ }>): ValidationResult;
24
+ export declare function validateRewriteIntro(c: Extract<PageChange, {
25
+ type: "rewrite_intro";
26
+ }>): ValidationResult;
27
+ export declare function validateAddInternalLink(c: Extract<PageChange, {
28
+ type: "add_internal_link";
29
+ }>): ValidationResult;
30
+ export declare function validateRemoveThinBlock(c: Extract<PageChange, {
31
+ type: "remove_thin_block";
32
+ }>): ValidationResult;
33
+ /** Dispatcher: routes a `PageChange` to its specific validator. */
34
+ export declare function validatePageChange(c: PageChange): ValidationResult;
35
+ export {};
36
+ //# sourceMappingURL=page-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-changes.d.ts","sourceRoot":"","sources":["../../../../src/ai/manifest/validators/page-changes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhE,KAAK,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AA6ClE,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,GAAG,gBAAgB,CAqBlG;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,GAAG,gBAAgB,CAMlG;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC,GAAG,gBAAgB,CAWtG;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,gBAAgB,CAuCvG;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,gBAAgB,CAOxG;AAED,wBAAgB,uBAAuB,CACrC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,GACpD,gBAAgB,CA0BlB;AAED,wBAAgB,uBAAuB,CACrC,CAAC,EAAE,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,CAAC,GACpD,gBAAgB,CAYlB;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,UAAU,GAAG,gBAAgB,CAiBlE"}