ax-audit 4.2.1 → 6.0.0

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 (188) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +39 -4
  3. package/dist/baseline.js +1 -1
  4. package/dist/baseline.js.map +1 -1
  5. package/dist/check-ids.js +1 -1
  6. package/dist/check-ids.js.map +1 -1
  7. package/dist/cli.js +1 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/constants.d.ts +1 -85
  10. package/dist/constants.d.ts.map +1 -1
  11. package/dist/constants.js +0 -135
  12. package/dist/constants.js.map +1 -1
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/license.d.ts +8 -0
  18. package/dist/license.d.ts.map +1 -0
  19. package/dist/license.js +18 -0
  20. package/dist/license.js.map +1 -0
  21. package/dist/metadata.d.ts +6 -0
  22. package/dist/metadata.d.ts.map +1 -0
  23. package/dist/metadata.js +205 -0
  24. package/dist/metadata.js.map +1 -0
  25. package/dist/orchestrator.d.ts +1 -0
  26. package/dist/orchestrator.d.ts.map +1 -1
  27. package/dist/orchestrator.js +134 -56
  28. package/dist/orchestrator.js.map +1 -1
  29. package/dist/scorer.js +2 -2
  30. package/dist/scorer.js.map +1 -1
  31. package/dist/types.d.ts +4 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/docs/api.md +14 -3
  34. package/docs/architecture.md +9 -98
  35. package/docs/ci.md +19 -0
  36. package/docs/cli.md +11 -0
  37. package/docs/faq.md +18 -0
  38. package/docs/getting-started.md +33 -1
  39. package/package.json +5 -5
  40. package/dist/checks/agent-access.d.ts +0 -33
  41. package/dist/checks/agent-access.d.ts.map +0 -1
  42. package/dist/checks/agent-access.js +0 -256
  43. package/dist/checks/agent-access.js.map +0 -1
  44. package/dist/checks/agent-card.d.ts +0 -37
  45. package/dist/checks/agent-card.d.ts.map +0 -1
  46. package/dist/checks/agent-card.js +0 -352
  47. package/dist/checks/agent-card.js.map +0 -1
  48. package/dist/checks/agent-operability.d.ts +0 -66
  49. package/dist/checks/agent-operability.d.ts.map +0 -1
  50. package/dist/checks/agent-operability.js +0 -383
  51. package/dist/checks/agent-operability.js.map +0 -1
  52. package/dist/checks/agent-skills.d.ts +0 -24
  53. package/dist/checks/agent-skills.d.ts.map +0 -1
  54. package/dist/checks/agent-skills.js +0 -316
  55. package/dist/checks/agent-skills.js.map +0 -1
  56. package/dist/checks/ai-catalog.d.ts +0 -28
  57. package/dist/checks/ai-catalog.d.ts.map +0 -1
  58. package/dist/checks/ai-catalog.js +0 -254
  59. package/dist/checks/ai-catalog.js.map +0 -1
  60. package/dist/checks/ai-directives.d.ts +0 -57
  61. package/dist/checks/ai-directives.d.ts.map +0 -1
  62. package/dist/checks/ai-directives.js +0 -263
  63. package/dist/checks/ai-directives.js.map +0 -1
  64. package/dist/checks/api-discovery.d.ts +0 -26
  65. package/dist/checks/api-discovery.d.ts.map +0 -1
  66. package/dist/checks/api-discovery.js +0 -432
  67. package/dist/checks/api-discovery.js.map +0 -1
  68. package/dist/checks/auth-discovery.d.ts +0 -28
  69. package/dist/checks/auth-discovery.d.ts.map +0 -1
  70. package/dist/checks/auth-discovery.js +0 -302
  71. package/dist/checks/auth-discovery.js.map +0 -1
  72. package/dist/checks/commerce-discovery.d.ts +0 -40
  73. package/dist/checks/commerce-discovery.d.ts.map +0 -1
  74. package/dist/checks/commerce-discovery.js +0 -295
  75. package/dist/checks/commerce-discovery.js.map +0 -1
  76. package/dist/checks/content-negotiation.d.ts +0 -4
  77. package/dist/checks/content-negotiation.d.ts.map +0 -1
  78. package/dist/checks/content-negotiation.js +0 -253
  79. package/dist/checks/content-negotiation.js.map +0 -1
  80. package/dist/checks/crawl-efficiency.d.ts +0 -16
  81. package/dist/checks/crawl-efficiency.d.ts.map +0 -1
  82. package/dist/checks/crawl-efficiency.js +0 -186
  83. package/dist/checks/crawl-efficiency.js.map +0 -1
  84. package/dist/checks/frontmatter.d.ts +0 -34
  85. package/dist/checks/frontmatter.d.ts.map +0 -1
  86. package/dist/checks/frontmatter.js +0 -100
  87. package/dist/checks/frontmatter.js.map +0 -1
  88. package/dist/checks/html-rendering.d.ts +0 -21
  89. package/dist/checks/html-rendering.d.ts.map +0 -1
  90. package/dist/checks/html-rendering.js +0 -221
  91. package/dist/checks/html-rendering.js.map +0 -1
  92. package/dist/checks/html-utils.d.ts +0 -66
  93. package/dist/checks/html-utils.d.ts.map +0 -1
  94. package/dist/checks/html-utils.js +0 -139
  95. package/dist/checks/html-utils.js.map +0 -1
  96. package/dist/checks/http-headers.d.ts +0 -11
  97. package/dist/checks/http-headers.d.ts.map +0 -1
  98. package/dist/checks/http-headers.js +0 -249
  99. package/dist/checks/http-headers.js.map +0 -1
  100. package/dist/checks/http-hygiene.d.ts +0 -26
  101. package/dist/checks/http-hygiene.d.ts.map +0 -1
  102. package/dist/checks/http-hygiene.js +0 -257
  103. package/dist/checks/http-hygiene.js.map +0 -1
  104. package/dist/checks/index.d.ts +0 -3
  105. package/dist/checks/index.d.ts.map +0 -1
  106. package/dist/checks/index.js +0 -55
  107. package/dist/checks/index.js.map +0 -1
  108. package/dist/checks/llms-txt.d.ts +0 -19
  109. package/dist/checks/llms-txt.d.ts.map +0 -1
  110. package/dist/checks/llms-txt.js +0 -281
  111. package/dist/checks/llms-txt.js.map +0 -1
  112. package/dist/checks/mcp-discovery.d.ts +0 -30
  113. package/dist/checks/mcp-discovery.d.ts.map +0 -1
  114. package/dist/checks/mcp-discovery.js +0 -523
  115. package/dist/checks/mcp-discovery.js.map +0 -1
  116. package/dist/checks/meta-tags.d.ts +0 -17
  117. package/dist/checks/meta-tags.d.ts.map +0 -1
  118. package/dist/checks/meta-tags.js +0 -188
  119. package/dist/checks/meta-tags.js.map +0 -1
  120. package/dist/checks/robots-parser.d.ts +0 -110
  121. package/dist/checks/robots-parser.d.ts.map +0 -1
  122. package/dist/checks/robots-parser.js +0 -277
  123. package/dist/checks/robots-parser.js.map +0 -1
  124. package/dist/checks/robots-txt.d.ts +0 -6
  125. package/dist/checks/robots-txt.d.ts.map +0 -1
  126. package/dist/checks/robots-txt.js +0 -367
  127. package/dist/checks/robots-txt.js.map +0 -1
  128. package/dist/checks/rsl.d.ts +0 -4
  129. package/dist/checks/rsl.d.ts.map +0 -1
  130. package/dist/checks/rsl.js +0 -242
  131. package/dist/checks/rsl.js.map +0 -1
  132. package/dist/checks/security-txt.d.ts +0 -4
  133. package/dist/checks/security-txt.d.ts.map +0 -1
  134. package/dist/checks/security-txt.js +0 -81
  135. package/dist/checks/security-txt.js.map +0 -1
  136. package/dist/checks/seo-basics.d.ts +0 -13
  137. package/dist/checks/seo-basics.d.ts.map +0 -1
  138. package/dist/checks/seo-basics.js +0 -221
  139. package/dist/checks/seo-basics.js.map +0 -1
  140. package/dist/checks/sitemap.d.ts +0 -12
  141. package/dist/checks/sitemap.d.ts.map +0 -1
  142. package/dist/checks/sitemap.js +0 -240
  143. package/dist/checks/sitemap.js.map +0 -1
  144. package/dist/checks/structured-data.d.ts +0 -4
  145. package/dist/checks/structured-data.d.ts.map +0 -1
  146. package/dist/checks/structured-data.js +0 -408
  147. package/dist/checks/structured-data.js.map +0 -1
  148. package/dist/checks/structured-fields.d.ts +0 -46
  149. package/dist/checks/structured-fields.d.ts.map +0 -1
  150. package/dist/checks/structured-fields.js +0 -112
  151. package/dist/checks/structured-fields.js.map +0 -1
  152. package/dist/checks/surface.d.ts +0 -59
  153. package/dist/checks/surface.d.ts.map +0 -1
  154. package/dist/checks/surface.js +0 -106
  155. package/dist/checks/surface.js.map +0 -1
  156. package/dist/checks/tls-https.d.ts +0 -13
  157. package/dist/checks/tls-https.d.ts.map +0 -1
  158. package/dist/checks/tls-https.js +0 -163
  159. package/dist/checks/tls-https.js.map +0 -1
  160. package/dist/checks/usage-policy.d.ts +0 -53
  161. package/dist/checks/usage-policy.d.ts.map +0 -1
  162. package/dist/checks/usage-policy.js +0 -339
  163. package/dist/checks/usage-policy.js.map +0 -1
  164. package/dist/checks/utils.d.ts +0 -40
  165. package/dist/checks/utils.d.ts.map +0 -1
  166. package/dist/checks/utils.js +0 -74
  167. package/dist/checks/utils.js.map +0 -1
  168. package/dist/checks/waf.d.ts +0 -75
  169. package/dist/checks/waf.d.ts.map +0 -1
  170. package/dist/checks/waf.js +0 -203
  171. package/dist/checks/waf.js.map +0 -1
  172. package/dist/checks/webmcp.d.ts +0 -55
  173. package/dist/checks/webmcp.d.ts.map +0 -1
  174. package/dist/checks/webmcp.js +0 -209
  175. package/dist/checks/webmcp.js.map +0 -1
  176. package/dist/checks/well-known.d.ts +0 -38
  177. package/dist/checks/well-known.d.ts.map +0 -1
  178. package/dist/checks/well-known.js +0 -202
  179. package/dist/checks/well-known.js.map +0 -1
  180. package/dist/fetcher.d.ts +0 -15
  181. package/dist/fetcher.d.ts.map +0 -1
  182. package/dist/fetcher.js +0 -127
  183. package/dist/fetcher.js.map +0 -1
  184. package/dist/guide-urls.d.ts +0 -2
  185. package/dist/guide-urls.d.ts.map +0 -1
  186. package/dist/guide-urls.js +0 -5
  187. package/dist/guide-urls.js.map +0 -1
  188. package/docs/roadmap.md +0 -367
@@ -1 +0,0 @@
1
- {"version":3,"file":"commerce-discovery.js","sourceRoot":"","sources":["../../src/checks/commerce-discovery.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
- export declare const meta: CheckMeta;
3
- export default function check(ctx: CheckContext): Promise<CheckResult>;
4
- //# sourceMappingURL=content-negotiation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-negotiation.d.ts","sourceRoot":"","sources":["../../src/checks/content-negotiation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAKjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAyCF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA6G3E"}
@@ -1,253 +0,0 @@
1
- import { guideUrl } from '../guide-urls.js';
2
- import { buildResult } from './utils.js';
3
- import { findLinkTags, getAttribute } from './html-utils.js';
4
- import { parseFrontmatter } from './frontmatter.js';
5
- export const meta = {
6
- id: 'content-negotiation',
7
- name: 'Content Negotiation',
8
- description: 'Checks whether the homepage serves Markdown to AI agents via Accept: text/markdown',
9
- category: 'content',
10
- };
11
- /** Markdown sent by agents that support content negotiation (Claude Code, Cursor, OpenCode). */
12
- const MARKDOWN_ACCEPT = 'text/markdown';
13
- /**
14
- * The Accept header a real agent sends. Probing with a bare `text/markdown`
15
- * tests a code path no client actually exercises: Claude Code, Cursor and
16
- * OpenCode all send a q-weighted list with HTML as the fallback, and a
17
- * negotiation implementation that only matches the bare string will pass this
18
- * check and fail every real request.
19
- */
20
- const REALISTIC_ACCEPT = 'text/markdown, text/html;q=0.9, */*;q=0.1';
21
- /**
22
- * Vercel and others negotiate on the user agent for known agents that send no
23
- * Accept preference, so the same URL may serve Markdown to Claude Code and HTML
24
- * to this audit unless the audit asks the same way.
25
- */
26
- const AGENT_USER_AGENT = 'Claude-Code/1.0';
27
- /** Score when Markdown is not negotiated but a `<link rel="alternate" type="text/markdown">` exists. */
28
- const ALTERNATE_ONLY_SCORE = 40;
29
- /**
30
- * Detect an HTML document masquerading as Markdown. Markdown may legally
31
- * contain inline HTML, so this only flags full documents (doctype / <html> /
32
- * <head> at the start), not embedded tags.
33
- */
34
- function looksLikeHtmlDocument(body) {
35
- return /^\s*(?:<!doctype\s+html|<html[\s>]|<head[\s>])/i.test(body);
36
- }
37
- /** Find `<link rel="alternate" type="text/markdown">` tags in the homepage HTML. */
38
- function findMarkdownAlternates(html) {
39
- return findLinkTags(html, 'alternate').filter((tag) => {
40
- const type = getAttribute(tag, 'type');
41
- return type !== null && type.toLowerCase().includes('text/markdown');
42
- });
43
- }
44
- export default async function check(ctx) {
45
- const start = performance.now();
46
- const findings = [];
47
- const res = await ctx.fetch(ctx.url, { headers: { Accept: REALISTIC_ACCEPT } });
48
- if (res.status === 0) {
49
- findings.push({
50
- status: 'fail',
51
- message: 'Could not fetch homepage with "Accept: text/markdown"',
52
- detail: res.error ?? 'Network error',
53
- learnMoreUrl: guideUrl(meta.id, 'fetch-error'),
54
- });
55
- return buildResult(meta, 0, findings, start);
56
- }
57
- const contentType = (res.headers['content-type'] ?? '').toLowerCase();
58
- const servesMarkdown = res.ok && contentType.includes(MARKDOWN_ACCEPT);
59
- if (!servesMarkdown) {
60
- findings.push({
61
- status: 'fail',
62
- message: 'Homepage does not serve Markdown via content negotiation',
63
- detail: res.status === 406
64
- ? 'Server responded 406 Not Acceptable to "Accept: text/markdown"'
65
- : `Got ${contentType.split(';')[0] || 'no Content-Type'} (HTTP ${res.status}) for "Accept: text/markdown"`,
66
- hint: 'Serve a Markdown representation of your pages when agents request "Accept: text/markdown". ' +
67
- 'Agents like Claude Code and Cursor ask for it, and Markdown cuts token usage by roughly 80% against HTML. ' +
68
- 'Cloudflare ("Markdown for Agents") and Vercel can enable this without code changes.',
69
- learnMoreUrl: guideUrl(meta.id, res.status === 406 ? 'http-406' : 'not-supported'),
70
- });
71
- await reportUserAgentNegotiation(ctx, findings);
72
- await reportMarkdownSuffix(ctx, findings);
73
- const alternates = findMarkdownAlternates(ctx.html);
74
- if (alternates.length > 0) {
75
- findings.push({
76
- status: 'pass',
77
- message: `Markdown alternate advertised via <link rel="alternate" type="text/markdown"> (${alternates.length} link tag(s))`,
78
- detail: 'Discoverable, but agents must perform an extra fetch instead of negotiating the same URL.',
79
- });
80
- return buildResult(meta, ALTERNATE_ONLY_SCORE, findings, start);
81
- }
82
- findings.push({
83
- status: 'warn',
84
- message: 'No <link rel="alternate" type="text/markdown"> fallback found on the homepage',
85
- hint: 'If you cannot enable content negotiation, advertise a Markdown version with ' +
86
- '<link rel="alternate" type="text/markdown" href="/index.md"> so agents can discover it.',
87
- learnMoreUrl: guideUrl(meta.id, 'no-alternate'),
88
- });
89
- return buildResult(meta, 0, findings, start);
90
- }
91
- let score = 100;
92
- findings.push({
93
- status: 'pass',
94
- message: 'Homepage serves Markdown via content negotiation (Accept: text/markdown)',
95
- });
96
- if (res.body.trim().length === 0) {
97
- findings.push({
98
- status: 'warn',
99
- message: 'Markdown response body is empty',
100
- hint: 'Return the page content as Markdown — an empty body gives agents nothing to work with.',
101
- learnMoreUrl: guideUrl(meta.id, 'empty-body'),
102
- });
103
- score -= 30;
104
- }
105
- else if (looksLikeHtmlDocument(res.body)) {
106
- findings.push({
107
- status: 'warn',
108
- message: 'Response is labeled text/markdown but the body is an HTML document',
109
- hint: 'Convert the page to actual Markdown instead of relabeling the HTML response.',
110
- learnMoreUrl: guideUrl(meta.id, 'mislabeled-content-type'),
111
- });
112
- score -= 25;
113
- }
114
- else {
115
- findings.push({ status: 'pass', message: 'Response body is Markdown, not an HTML document' });
116
- }
117
- const vary = (res.headers['vary'] ?? '').toLowerCase();
118
- const variesOnAccept = vary
119
- .split(',')
120
- .map((v) => v.trim())
121
- .some((v) => v === 'accept' || v === '*');
122
- if (variesOnAccept) {
123
- findings.push({ status: 'pass', message: 'Vary: Accept present (caches keep HTML and Markdown apart)' });
124
- }
125
- else {
126
- findings.push({
127
- status: 'warn',
128
- message: 'Vary header does not include "Accept"',
129
- detail: vary ? `Vary: ${res.headers['vary']}` : 'No Vary header',
130
- hint: 'Send "Vary: Accept" when the same URL serves both HTML and Markdown, ' +
131
- 'otherwise shared caches and CDNs may serve Markdown to browsers (or HTML to agents).',
132
- learnMoreUrl: guideUrl(meta.id, 'missing-vary'),
133
- });
134
- score -= 15;
135
- }
136
- reportTokenSavings(ctx, res.headers, res.body, findings);
137
- reportFrontmatter(res.body, findings);
138
- reportCanonicalLink(res.headers, findings);
139
- return buildResult(meta, score, findings, start);
140
- }
141
- /* ── Extended reporting (informational) ─────────────────────────────────── */
142
- /**
143
- * Report how much the Markdown representation actually saves.
144
- *
145
- * Cloudflare's implementation states the numbers directly, in
146
- * `x-markdown-tokens` and `x-original-tokens`, which is better evidence than a
147
- * byte ratio: bytes and tokens diverge sharply on markup-heavy pages. When the
148
- * headers are absent, fall back to comparing sizes.
149
- */
150
- function reportTokenSavings(ctx, headers, body, findings) {
151
- const markdownTokens = Number(headers['x-markdown-tokens']);
152
- const originalTokens = Number(headers['x-original-tokens']);
153
- if (Number.isFinite(markdownTokens) && Number.isFinite(originalTokens) && originalTokens > 0) {
154
- const saved = Math.round((1 - markdownTokens / originalTokens) * 100);
155
- findings.push({
156
- status: saved > 0 ? 'pass' : 'warn',
157
- message: `Markdown costs ${markdownTokens} tokens against ${originalTokens} for the HTML (${saved}% saved)`,
158
- detail: 'Counts reported by the origin via x-markdown-tokens and x-original-tokens.',
159
- });
160
- return;
161
- }
162
- if (ctx.html.length === 0 || body.length === 0)
163
- return;
164
- const reduction = Math.round((1 - body.length / ctx.html.length) * 100);
165
- if (reduction > 0) {
166
- findings.push({
167
- status: 'pass',
168
- message: `Markdown is ~${reduction}% lighter than the HTML representation (${body.length} vs ${ctx.html.length} bytes)`,
169
- });
170
- }
171
- else {
172
- findings.push({
173
- status: 'warn',
174
- message: `Markdown response is not smaller than the HTML representation (${body.length} vs ${ctx.html.length} bytes)`,
175
- hint: 'Strip navigation, boilerplate, and markup remnants from the Markdown output — its purpose is token efficiency.',
176
- learnMoreUrl: guideUrl(meta.id, 'not-smaller'),
177
- });
178
- }
179
- }
180
- /**
181
- * Frontmatter carries what the HTML expressed through tags an agent no longer
182
- * sees: the canonical URL, the title, when the page last changed. Without it a
183
- * Markdown response is content with no provenance, and an agent quoting it
184
- * cannot say where it came from.
185
- */
186
- function reportFrontmatter(body, findings) {
187
- const { frontmatter, present } = parseFrontmatter(body);
188
- if (!present) {
189
- findings.push({
190
- status: 'warn',
191
- message: 'Markdown response has no frontmatter',
192
- hint: 'Add a YAML block with at least title and canonical_url, plus last_updated where you have it. Stripping the ' +
193
- 'HTML also strips the canonical link and the metadata tags, so without frontmatter an agent cannot attribute ' +
194
- 'what it quotes.',
195
- learnMoreUrl: guideUrl(meta.id, 'no-frontmatter'),
196
- });
197
- return;
198
- }
199
- const useful = ['title', 'canonical_url', 'url', 'last_updated', 'description'].filter((k) => frontmatter[k] !== undefined && frontmatter[k] !== '');
200
- findings.push({
201
- status: useful.length > 0 ? 'pass' : 'warn',
202
- message: useful.length > 0
203
- ? `Markdown frontmatter carries ${useful.join(', ')}`
204
- : 'Markdown frontmatter is present but carries no title, canonical URL or date',
205
- ...(useful.length === 0
206
- ? {
207
- hint: 'Include title and canonical_url so a quotation can be attributed back to the page.',
208
- learnMoreUrl: guideUrl(meta.id, 'empty-frontmatter'),
209
- }
210
- : {}),
211
- });
212
- }
213
- /** A `Link: rel="canonical"` header attributes the Markdown even without frontmatter. */
214
- function reportCanonicalLink(headers, findings) {
215
- const link = headers['link'] ?? '';
216
- if (/rel\s*=\s*"?canonical"?/i.test(link)) {
217
- findings.push({ status: 'pass', message: 'Markdown response carries a canonical Link header' });
218
- }
219
- }
220
- /**
221
- * Some origins negotiate on the user agent rather than on Accept, serving
222
- * Markdown to a recognised agent that expressed no preference. Worth probing
223
- * before concluding the site has no Markdown at all.
224
- */
225
- async function reportUserAgentNegotiation(ctx, findings) {
226
- const res = await ctx.fetch(ctx.url, { headers: { 'User-Agent': AGENT_USER_AGENT } });
227
- if (!res.ok)
228
- return;
229
- if (!(res.headers['content-type'] ?? '').toLowerCase().includes(MARKDOWN_ACCEPT))
230
- return;
231
- findings.push({
232
- status: 'pass',
233
- message: 'Markdown is served to a recognised agent user agent, without an Accept preference',
234
- detail: `Probed with User-Agent: ${AGENT_USER_AGENT}.`,
235
- hint: 'This works for agents you recognise today. Negotiating on Accept as well covers every client that asks ' +
236
- 'properly, including ones whose user agent you have never seen.',
237
- });
238
- }
239
- /** The `.md` suffix convention: a durable URL for the Markdown version. */
240
- async function reportMarkdownSuffix(ctx, findings) {
241
- for (const path of ['/index.md', '/index.html.md']) {
242
- const res = await ctx.fetch(`${ctx.url}${path}`);
243
- if (!res.ok || res.body.trim().length === 0 || looksLikeHtmlDocument(res.body))
244
- continue;
245
- findings.push({
246
- status: 'pass',
247
- message: `Markdown available at the suffix URL ${path}`,
248
- detail: 'A durable URL an agent can construct, though it still costs a second request against negotiating in place.',
249
- });
250
- return;
251
- }
252
- }
253
- //# sourceMappingURL=content-negotiation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-negotiation.js","sourceRoot":"","sources":["../../src/checks/content-negotiation.ts"],"names":[],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- import type { CheckContext, CheckResult, CheckMeta, Finding } from '../types.js';
2
- export declare const meta: CheckMeta;
3
- export default function check(ctx: CheckContext): Promise<CheckResult>;
4
- /**
5
- * Estimate the token cost of the readable content.
6
- *
7
- * Bytes are the wrong unit for an agent: a page can be small and still expensive
8
- * once markup is stripped, or large and cheap. The estimate is a chars-per-token
9
- * approximation, stated as such, and it is compared against the whole response
10
- * so an operator can see how much of what they send is markup the agent pays to
11
- * receive and then discards.
12
- */
13
- export declare function reportTokenBudget(html: string, findings: Finding[]): void;
14
- /** Report how long the origin took, since agents give up sooner than people do. */
15
- export declare function reportResponseTime(elapsedMs: number | undefined, findings: Finding[]): void;
16
- //# sourceMappingURL=crawl-efficiency.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"crawl-efficiency.d.ts","sourceRoot":"","sources":["../../src/checks/crawl-efficiency.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjF,eAAO,MAAM,IAAI,EAAE,SAIlB,CAAC;AAMF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAiH3E;AAWD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAgCzE;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAgB3F"}
@@ -1,186 +0,0 @@
1
- import { guideUrl } from '../guide-urls.js';
2
- import { buildResult } from './utils.js';
3
- import { extractVisibleText } from './html-utils.js';
4
- export const meta = {
5
- id: 'crawl-efficiency',
6
- name: 'Crawl Efficiency',
7
- description: 'Checks compression, conditional GET (ETag / Last-Modified), and response size',
8
- };
9
- /** Page sizes (decompressed HTML bytes) above this earn a warning. */
10
- const LARGE_PAGE_BYTES = 2_000_000;
11
- const ACCEPTABLE_PAGE_BYTES = 500_000;
12
- export default async function check(ctx) {
13
- const start = performance.now();
14
- const findings = [];
15
- let score = 100;
16
- // Request explicitly advertising modern compression. The runtime's fetch
17
- // transparently decompresses the body, but the Content-Encoding header still
18
- // reflects what the server sent on the wire.
19
- const res = await ctx.fetch(ctx.url, { headers: { 'Accept-Encoding': 'br, gzip, deflate' } });
20
- if (!res.ok) {
21
- findings.push({
22
- status: 'fail',
23
- message: 'Homepage request failed — cannot assess crawl efficiency',
24
- detail: `HTTP ${res.status || 'network error'}`,
25
- learnMoreUrl: guideUrl(meta.id, 'fetch-failed'),
26
- });
27
- return buildResult(meta, 0, findings, start);
28
- }
29
- /* ── Compression ──────────────────────────────────────────────────── */
30
- const encoding = (res.headers['content-encoding'] ?? '').toLowerCase().trim();
31
- if (encoding === 'br') {
32
- findings.push({ status: 'pass', message: 'Response compressed with Brotli (br)' });
33
- }
34
- else if (encoding === 'gzip' || encoding === 'deflate' || encoding === 'zstd') {
35
- findings.push({
36
- status: 'pass',
37
- message: `Response compressed with ${encoding}`,
38
- detail: 'Brotli (br) typically compresses text 10–20% smaller — consider enabling it.',
39
- });
40
- }
41
- else {
42
- findings.push({
43
- status: 'warn',
44
- message: 'Response is not compressed',
45
- detail: encoding ? `Content-Encoding: ${encoding}` : 'No Content-Encoding header',
46
- hint: 'Enable Brotli or gzip for text responses. Compression cuts bytes transferred by ~70–80% and ' +
47
- 'reduces crawl cost for every agent and bot that fetches your pages.',
48
- learnMoreUrl: guideUrl(meta.id, 'no-compression'),
49
- });
50
- score -= 30;
51
- }
52
- /* ── Conditional GET (ETag / Last-Modified → 304) ─────────────────── */
53
- const etag = res.headers['etag'];
54
- const lastModified = res.headers['last-modified'];
55
- if (!etag && !lastModified) {
56
- findings.push({
57
- status: 'warn',
58
- message: 'No ETag or Last-Modified header — conditional requests unsupported',
59
- hint: 'Send an ETag or Last-Modified header so crawlers can revalidate with If-None-Match / ' +
60
- 'If-Modified-Since and receive a cheap 304 Not Modified instead of the full body.',
61
- learnMoreUrl: guideUrl(meta.id, 'no-validators'),
62
- });
63
- score -= 30;
64
- }
65
- else {
66
- const validator = etag ? 'ETag' : 'Last-Modified';
67
- findings.push({ status: 'pass', message: `Cache validator present (${validator})` });
68
- const conditionalHeaders = {};
69
- if (etag)
70
- conditionalHeaders['If-None-Match'] = etag;
71
- if (lastModified)
72
- conditionalHeaders['If-Modified-Since'] = lastModified;
73
- const conditional = await ctx.fetch(ctx.url, { headers: conditionalHeaders });
74
- if (conditional.status === 304) {
75
- findings.push({ status: 'pass', message: 'Conditional request returns 304 Not Modified' });
76
- }
77
- else {
78
- findings.push({
79
- status: 'warn',
80
- message: `Conditional request returned ${conditional.status} instead of 304 Not Modified`,
81
- detail: `Re-requested with ${Object.keys(conditionalHeaders).join(' + ')}`,
82
- hint: 'The server advertises a cache validator but does not honor If-None-Match / If-Modified-Since. ' +
83
- 'Configure it to return 304 when the validator matches, so crawlers avoid re-downloading unchanged pages.',
84
- learnMoreUrl: guideUrl(meta.id, 'no-304'),
85
- });
86
- score -= 15;
87
- }
88
- }
89
- /* ── Response size ────────────────────────────────────────────────── */
90
- const bytes = Buffer.byteLength(res.body, 'utf8');
91
- if (bytes > LARGE_PAGE_BYTES) {
92
- findings.push({
93
- status: 'warn',
94
- message: `Homepage is very large (${formatBytes(bytes)} decompressed)`,
95
- hint: 'Large documents inflate crawl cost and token usage. Trim inlined data, split content, ' +
96
- 'or serve a Markdown representation to agents (see the content-negotiation check).',
97
- learnMoreUrl: guideUrl(meta.id, 'large-page'),
98
- });
99
- score -= 10;
100
- }
101
- else if (bytes > ACCEPTABLE_PAGE_BYTES) {
102
- findings.push({
103
- status: 'warn',
104
- message: `Homepage is on the large side (${formatBytes(bytes)} decompressed)`,
105
- hint: 'Consider trimming inlined payloads to reduce crawl cost.',
106
- learnMoreUrl: guideUrl(meta.id, 'large-page'),
107
- });
108
- score -= 5;
109
- }
110
- else {
111
- findings.push({ status: 'pass', message: `Homepage size is reasonable (${formatBytes(bytes)} decompressed)` });
112
- }
113
- reportTokenBudget(ctx.html ?? '', findings);
114
- reportResponseTime(res.elapsedMs, findings);
115
- return buildResult(meta, score, findings, start);
116
- }
117
- /* ── Cost in tokens and in time (informational in 3.x) ──────────────────── */
118
- /** Rough characters-per-token ratio for English prose in a byte-pair encoding. */
119
- const CHARS_PER_TOKEN = 4;
120
- /** Above this, a page crowds out everything else in an agent's context window. */
121
- const LARGE_TOKEN_BUDGET = 25_000;
122
- /** Time to a complete response beyond which agents start timing out or giving up. */
123
- const SLOW_RESPONSE_MS = 2_000;
124
- /**
125
- * Estimate the token cost of the readable content.
126
- *
127
- * Bytes are the wrong unit for an agent: a page can be small and still expensive
128
- * once markup is stripped, or large and cheap. The estimate is a chars-per-token
129
- * approximation, stated as such, and it is compared against the whole response
130
- * so an operator can see how much of what they send is markup the agent pays to
131
- * receive and then discards.
132
- */
133
- export function reportTokenBudget(html, findings) {
134
- if (html.length === 0)
135
- return;
136
- const text = extractVisibleText(html);
137
- const contentTokens = Math.round(text.length / CHARS_PER_TOKEN);
138
- const wireTokens = Math.round(html.length / CHARS_PER_TOKEN);
139
- const markupShare = wireTokens > 0 ? Math.round((1 - contentTokens / wireTokens) * 100) : 0;
140
- if (contentTokens > LARGE_TOKEN_BUDGET) {
141
- findings.push({
142
- status: 'warn',
143
- message: `Homepage carries roughly ${contentTokens.toLocaleString('en-US')} tokens of readable content`,
144
- detail: 'Estimated at four characters per token.',
145
- hint: 'A page this large crowds out everything else in an agent\u2019s context window, so it reads the beginning and ' +
146
- 'gives up. Split it, or serve a Markdown representation.',
147
- learnMoreUrl: guideUrl(meta.id, 'large-token-budget'),
148
- });
149
- return;
150
- }
151
- findings.push({
152
- status: markupShare > 90 ? 'warn' : 'pass',
153
- message: `Roughly ${contentTokens.toLocaleString('en-US')} tokens of content in ${wireTokens.toLocaleString('en-US')} tokens of response (${markupShare}% markup)`,
154
- detail: 'Estimated at four characters per token.',
155
- ...(markupShare > 90
156
- ? {
157
- hint: 'An agent pays to receive the markup and then discards it. Serving Markdown on Accept negotiation is the direct fix.',
158
- learnMoreUrl: guideUrl(meta.id, 'markup-overhead'),
159
- }
160
- : {}),
161
- });
162
- }
163
- /** Report how long the origin took, since agents give up sooner than people do. */
164
- export function reportResponseTime(elapsedMs, findings) {
165
- if (elapsedMs === undefined)
166
- return;
167
- if (elapsedMs > SLOW_RESPONSE_MS) {
168
- findings.push({
169
- status: 'warn',
170
- message: `Homepage took ${elapsedMs}ms to respond`,
171
- hint: 'Agents crawl on tighter timeouts than browsers and rarely retry. A slow page is not a slow page to them, it ' +
172
- 'is a missing one.',
173
- learnMoreUrl: guideUrl(meta.id, 'slow-response'),
174
- });
175
- return;
176
- }
177
- findings.push({ status: 'pass', message: `Homepage responded in ${elapsedMs}ms` });
178
- }
179
- function formatBytes(bytes) {
180
- if (bytes < 1024)
181
- return `${bytes} B`;
182
- if (bytes < 1024 * 1024)
183
- return `${(bytes / 1024).toFixed(1)} KB`;
184
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
185
- }
186
- //# sourceMappingURL=crawl-efficiency.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"crawl-efficiency.js","sourceRoot":"","sources":["../../src/checks/crawl-efficiency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,CAAC,MAAM,IAAI,GAAc;IAC7B,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,+EAA+E;CAC7F,CAAC;AAEF,sEAAsE;AACtE,MAAM,gBAAgB,GAAG,SAAS,CAAC;AACnC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAEtC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,KAAK,CAAC,GAAiB;IACnD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,KAAK,GAAG,GAAG,CAAC;IAEhB,yEAAyE;IACzE,6EAA6E;IAC7E,6CAA6C;IAC7C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAC;IAE9F,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,0DAA0D;YACnE,MAAM,EAAE,QAAQ,GAAG,CAAC,MAAM,IAAI,eAAe,EAAE;YAC/C,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC;SAChD,CAAC,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,yEAAyE;IAEzE,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAC9E,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,sCAAsC,EAAE,CAAC,CAAC;IACrF,CAAC;SAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QAChF,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,4BAA4B,QAAQ,EAAE;YAC/C,MAAM,EAAE,8EAA8E;SACvF,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,4BAA4B;YACrC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC,CAAC,4BAA4B;YACjF,IAAI,EACF,8FAA8F;gBAC9F,qEAAqE;YACvE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC;SAClD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,yEAAyE;IAEzE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAElD,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,oEAAoE;YAC7E,IAAI,EACF,uFAAuF;gBACvF,kFAAkF;YACpF,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,eAAe,CAAC;SACjD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC;QAClD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,4BAA4B,SAAS,GAAG,EAAE,CAAC,CAAC;QAErF,MAAM,kBAAkB,GAA2B,EAAE,CAAC;QACtD,IAAI,IAAI;YAAE,kBAAkB,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;QACrD,IAAI,YAAY;YAAE,kBAAkB,CAAC,mBAAmB,CAAC,GAAG,YAAY,CAAC;QAEzE,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC9E,IAAI,WAAW,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC,CAAC;QAC7F,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC;gBACZ,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,gCAAgC,WAAW,CAAC,MAAM,8BAA8B;gBACzF,MAAM,EAAE,qBAAqB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;gBAC1E,IAAI,EACF,gGAAgG;oBAChG,0GAA0G;gBAC5G,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC;aAC1C,CAAC,CAAC;YACH,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,yEAAyE;IAEzE,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAClD,IAAI,KAAK,GAAG,gBAAgB,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,2BAA2B,WAAW,CAAC,KAAK,CAAC,gBAAgB;YACtE,IAAI,EACF,wFAAwF;gBACxF,mFAAmF;YACrF,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC;SAC9C,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;SAAM,IAAI,KAAK,GAAG,qBAAqB,EAAE,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,kCAAkC,WAAW,CAAC,KAAK,CAAC,gBAAgB;YAC7E,IAAI,EAAE,0DAA0D;YAChE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC;SAC9C,CAAC,CAAC;QACH,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,gCAAgC,WAAW,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACjH,CAAC;IAED,iBAAiB,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC5C,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAE5C,OAAO,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,+EAA+E;AAE/E,kFAAkF;AAClF,MAAM,eAAe,GAAG,CAAC,CAAC;AAC1B,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,qFAAqF;AACrF,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,QAAmB;IACjE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE9B,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,aAAa,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5F,IAAI,aAAa,GAAG,kBAAkB,EAAE,CAAC;QACvC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,4BAA4B,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,6BAA6B;YACvG,MAAM,EAAE,yCAAyC;YACjD,IAAI,EACF,gHAAgH;gBAChH,yDAAyD;YAC3D,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,oBAAoB,CAAC;SACtD,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC;QACZ,MAAM,EAAE,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAC1C,OAAO,EAAE,WAAW,aAAa,CAAC,cAAc,CAAC,OAAO,CAAC,yBAAyB,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,wBAAwB,WAAW,WAAW;QAClK,MAAM,EAAE,yCAAyC;QACjD,GAAG,CAAC,WAAW,GAAG,EAAE;YAClB,CAAC,CAAC;gBACE,IAAI,EAAE,qHAAqH;gBAC3H,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC;aACnD;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,SAA6B,EAAE,QAAmB;IACnF,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO;IAEpC,IAAI,SAAS,GAAG,gBAAgB,EAAE,CAAC;QACjC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,iBAAiB,SAAS,eAAe;YAClD,IAAI,EACF,8GAA8G;gBAC9G,mBAAmB;YACrB,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,eAAe,CAAC;SACjD,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,SAAS,IAAI,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AACpD,CAAC"}
@@ -1,34 +0,0 @@
1
- /**
2
- * Minimal YAML frontmatter reader.
3
- *
4
- * ax-audit has two runtime dependencies and will not grow a YAML parser for
5
- * this. The documents it reads frontmatter from — SKILL.md, the Markdown
6
- * mirrors Vercel and Mintlify serve — use a flat `key: value` block by
7
- * convention, so a focused reader handles them exactly and reports anything
8
- * more elaborate as unparsed rather than guessing at it.
9
- *
10
- * Supported: `key: value`, single- and double-quoted values, `#` comments on
11
- * their own line or after a value, and inline flow sequences (`tags: [a, b]`).
12
- * Nested mappings and block sequences are recognised and skipped, with their
13
- * keys recorded in `skipped` so a caller can say what it could not read.
14
- */
15
- export interface Frontmatter {
16
- /** Flat scalar keys, lowercased, in source order. */
17
- frontmatter: Record<string, string>;
18
- /** Inline sequences, e.g. `tags: [a, b]` or `tags: a, b`. */
19
- lists: Record<string, string[]>;
20
- /** Keys whose values were nested structures this reader does not parse. */
21
- skipped: string[];
22
- /** The document with its frontmatter block removed. */
23
- body: string;
24
- /** Whether a frontmatter block was present at all. */
25
- present: boolean;
26
- }
27
- /**
28
- * Parse a leading `---` delimited frontmatter block.
29
- *
30
- * A document with no block returns `present: false` and its whole text as the
31
- * body, so callers can distinguish "no frontmatter" from "empty frontmatter".
32
- */
33
- export declare function parseFrontmatter(document: string): Frontmatter;
34
- //# sourceMappingURL=frontmatter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/checks/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAChC,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;CAClB;AAsBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CA+D9D"}