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,203 +0,0 @@
1
- /** Body markers for challenge interstitials that do not set a header. */
2
- const CHALLENGE_BODY_MARKERS = [
3
- { marker: /\/cdn-cgi\/challenge-platform\//i, vendor: 'Cloudflare' },
4
- { marker: /<title>\s*Just a moment/i, vendor: 'Cloudflare' },
5
- { marker: /Vercel Security Checkpoint/i, vendor: 'Vercel' },
6
- { marker: /challenges\.cloudflare\.com\/turnstile/i, vendor: 'Cloudflare Turnstile' },
7
- { marker: /www\.google\.com\/recaptcha\//i, vendor: 'reCAPTCHA' },
8
- { marker: /\bhcaptcha\.com\/(1\/api\.js|captcha)/i, vendor: 'hCaptcha' },
9
- { marker: /_Incapsula_Resource|Incapsula incident ID/i, vendor: 'Imperva' },
10
- { marker: /Checking your browser before accessing/i, vendor: 'Cloudflare' },
11
- { marker: /Please enable (JS|JavaScript) and disable any ad ?blocker/i, vendor: 'Cloudflare' },
12
- { marker: /Request unsuccessful\. Incapsula/i, vendor: 'Imperva' },
13
- { marker: /Pardon Our Interruption/i, vendor: 'Imperva' },
14
- { marker: /PerimeterX|px-captcha/i, vendor: 'HUMAN (PerimeterX)' },
15
- { marker: /Access Denied.*Reference #[0-9a-f.]+/is, vendor: 'Akamai' },
16
- ];
17
- /** Identify the CDN or edge from response headers, for context in findings. */
18
- export function detectEdgeVendor(headers) {
19
- if (headers['cf-ray'] !== undefined || /cloudflare/i.test(headers['server'] ?? ''))
20
- return 'Cloudflare';
21
- if (headers['x-vercel-id'] !== undefined || /vercel/i.test(headers['server'] ?? ''))
22
- return 'Vercel';
23
- if (headers['x-amzn-waf-action'] !== undefined || headers['x-amz-cf-id'] !== undefined)
24
- return 'AWS';
25
- if (headers['x-served-by']?.includes('cache-') || /varnish/i.test(headers['via'] ?? ''))
26
- return 'Fastly';
27
- if (headers['x-akamai-transformed'] !== undefined || /akamai/i.test(headers['server'] ?? ''))
28
- return 'Akamai';
29
- if (/netlify/i.test(headers['server'] ?? ''))
30
- return 'Netlify';
31
- return undefined;
32
- }
33
- function withVendor(base, vendor) {
34
- return vendor === undefined ? base : `${base} (${vendor})`;
35
- }
36
- /**
37
- * Classify a fetch result. Pure and total: any response produces a
38
- * classification, and unknown shapes fall back to status-based buckets.
39
- */
40
- export function classifyResponse(res) {
41
- const h = res.headers ?? {};
42
- const edge = detectEdgeVendor(h);
43
- const body = res.body ?? '';
44
- if (res.status === 0) {
45
- return {
46
- kind: 'network-error',
47
- label: res.error ? `Network error: ${res.error}` : 'Network error',
48
- evidence: res.error ? [res.error] : [],
49
- inconclusive: true,
50
- };
51
- }
52
- /* ── Challenges: an interstitial, not a policy decision ───────────────── */
53
- if ((h['cf-mitigated'] ?? '').toLowerCase() === 'challenge') {
54
- return {
55
- kind: 'challenge',
56
- vendor: 'Cloudflare',
57
- label: 'Cloudflare served a challenge page',
58
- evidence: ['cf-mitigated: challenge'],
59
- inconclusive: true,
60
- };
61
- }
62
- if ((h['x-vercel-mitigated'] ?? '').toLowerCase() === 'challenge' || h['x-vercel-challenge-token'] !== undefined) {
63
- return {
64
- kind: 'challenge',
65
- vendor: 'Vercel',
66
- label: 'Vercel served a security checkpoint',
67
- evidence: [
68
- h['x-vercel-mitigated'] !== undefined ? `x-vercel-mitigated: ${h['x-vercel-mitigated']}` : '',
69
- h['x-vercel-challenge-token'] !== undefined ? 'x-vercel-challenge-token present' : '',
70
- ].filter(Boolean),
71
- inconclusive: true,
72
- };
73
- }
74
- if ((h['x-amzn-waf-action'] ?? '').toLowerCase() === 'challenge') {
75
- return {
76
- kind: 'challenge',
77
- vendor: 'AWS WAF',
78
- label: `AWS WAF served a challenge (HTTP ${res.status})`,
79
- evidence: [`x-amzn-waf-action: challenge`, `status ${res.status}`],
80
- inconclusive: true,
81
- };
82
- }
83
- /* ── Payment and licensing: an offer, not a refusal ───────────────────── */
84
- if (res.status === 402) {
85
- const price = h['crawler-price'];
86
- if (price !== undefined) {
87
- return {
88
- kind: 'paywall',
89
- vendor: 'Cloudflare pay-per-crawl',
90
- label: `Content is priced for crawlers at ${price}`,
91
- evidence: [`crawler-price: ${price}`],
92
- inconclusive: false,
93
- price,
94
- };
95
- }
96
- if (h['payment-signature'] !== undefined || /"(payTo|maxTimeoutSeconds|x402Version)"/.test(body)) {
97
- return {
98
- kind: 'paywall',
99
- vendor: withVendor('x402', edge),
100
- label: 'Content is monetised through an x402 payment challenge',
101
- evidence: [h['payment-signature'] !== undefined ? 'payment-signature header' : 'x402 fields in body'],
102
- inconclusive: false,
103
- };
104
- }
105
- if (/^License\b/i.test(h['www-authenticate'] ?? '')) {
106
- return {
107
- kind: 'license-required',
108
- vendor: 'RSL Open Licensing Protocol',
109
- label: 'A licence is required before this content may be used',
110
- evidence: [`www-authenticate: ${h['www-authenticate']}`],
111
- inconclusive: false,
112
- };
113
- }
114
- return {
115
- kind: 'blocked',
116
- vendor: edge,
117
- label: withVendor('Refused with 402 but no payment mechanism advertised', edge),
118
- evidence: ['status 402 with no crawler-price, x402 fields, or licence challenge'],
119
- inconclusive: false,
120
- };
121
- }
122
- if (res.status === 401 && /^License\b/i.test(h['www-authenticate'] ?? '')) {
123
- return {
124
- kind: 'license-required',
125
- vendor: 'RSL Open Licensing Protocol',
126
- label: 'A licence is required before this content may be used',
127
- evidence: [`www-authenticate: ${h['www-authenticate']}`],
128
- inconclusive: false,
129
- };
130
- }
131
- /* ── Signature demands: the site wants a verifiable agent ─────────────── */
132
- if ((res.status === 401 || res.status === 403) && h['accept-signature'] !== undefined) {
133
- return {
134
- kind: 'needs-signature',
135
- vendor: withVendor('Web Bot Auth', edge),
136
- label: 'The origin requires a signed request (Web Bot Auth)',
137
- evidence: [`accept-signature: ${h['accept-signature']}`],
138
- inconclusive: true,
139
- };
140
- }
141
- if (res.status === 429) {
142
- return {
143
- kind: 'rate-limited',
144
- vendor: edge,
145
- label: h['retry-after'] !== undefined ? `Rate limited, retry after ${h['retry-after']}` : 'Rate limited',
146
- evidence: h['retry-after'] !== undefined ? [`retry-after: ${h['retry-after']}`] : ['status 429'],
147
- inconclusive: true,
148
- };
149
- }
150
- /* ── Body-marker challenges, on any status ────────────────────────────── */
151
- const bodyChallenge = CHALLENGE_BODY_MARKERS.find((m) => m.marker.test(body));
152
- if (bodyChallenge !== undefined) {
153
- return {
154
- kind: 'challenge',
155
- vendor: bodyChallenge.vendor,
156
- label: `${bodyChallenge.vendor} interstitial served instead of the page`,
157
- evidence: [`body matched ${bodyChallenge.vendor} challenge markup`, `status ${res.status}`],
158
- inconclusive: true,
159
- };
160
- }
161
- if (res.status === 401 || res.status === 403) {
162
- return {
163
- kind: 'blocked',
164
- vendor: edge,
165
- label: withVendor(`Refused with HTTP ${res.status}`, edge),
166
- evidence: [`status ${res.status}`],
167
- // An edge that verifies bots by IP range or signature rejects an unsigned
168
- // probe on principle, so a bare 403 from a known bot-managing CDN cannot
169
- // prove a policy block.
170
- inconclusive: edge !== undefined,
171
- };
172
- }
173
- if (res.status === 404 || res.status === 410) {
174
- return { kind: 'not-found', vendor: edge, label: `HTTP ${res.status}`, evidence: [], inconclusive: false };
175
- }
176
- if (res.status >= 500) {
177
- return {
178
- kind: 'server-error',
179
- vendor: edge,
180
- label: `Server error (HTTP ${res.status})`,
181
- evidence: [`status ${res.status}`],
182
- inconclusive: true,
183
- };
184
- }
185
- if (res.ok) {
186
- return { kind: 'ok', vendor: edge, label: `HTTP ${res.status}`, evidence: [], inconclusive: false };
187
- }
188
- return {
189
- kind: 'blocked',
190
- vendor: edge,
191
- label: `Unexpected HTTP ${res.status}`,
192
- evidence: [`status ${res.status}`],
193
- inconclusive: true,
194
- };
195
- }
196
- /**
197
- * Standard caveat for classifications an unauthenticated probe cannot settle.
198
- * Appended to hints so a report never overstates what it observed.
199
- */
200
- export const INCONCLUSIVE_CAVEAT = 'ax-audit sends this user agent from its own network without a Web Bot Auth signature, so an edge that verifies ' +
201
- 'crawlers by IP range or signature will reject the probe while admitting the real crawler. Confirm against your ' +
202
- 'WAF logs before changing any rule.';
203
- //# sourceMappingURL=waf.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"waf.js","sourceRoot":"","sources":["../../src/checks/waf.ts"],"names":[],"mappings":"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"}
@@ -1,55 +0,0 @@
1
- import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
- /**
3
- * "webmcp" — can a browser agent invoke this page's forms as tools?
4
- *
5
- * Today an agent that wants to use a form has to look at pixels, guess which
6
- * field is which, type into them, and hope. WebMCP lets a page declare a form as
7
- * a callable tool with named parameters, so the agent calls it instead of
8
- * driving it. The declarative form is two attributes:
9
- *
10
- * ```html
11
- * <form toolname="searchDocs" tooldescription="Search the documentation">
12
- * <input name="q" toolparamdescription="The search query">
13
- * </form>
14
- * ```
15
- *
16
- * Status, verified 2026-09-04: a W3C Web Machine Learning Community Group draft
17
- * with a Chrome origin trial running from Chrome 149. Not a standard, not
18
- * shipped by default, not implemented in Firefox or Safari. Adoption is
19
- * effectively zero.
20
- *
21
- * So this check never asks for WebMCP and never scores a site down for lacking
22
- * it. It reports N/A on a page with no forms and no WebMCP code at all. What it
23
- * does do, on pages that have adopted it, is catch the mistakes a static
24
- * analysis can catch with certainty: a `toolname` with no `tooldescription`,
25
- * which is the exact condition Lighthouse's `webmcp-schema-validity` audit
26
- * fails, parameters with no description, and use of the `navigator.modelContext`
27
- * namespace that Chrome deprecated in favour of `document.modelContext`.
28
- */
29
- export declare const meta: CheckMeta;
30
- export interface FormAnalysis {
31
- total: number;
32
- annotated: number;
33
- /** Forms declaring a name but no description — invalid, and Lighthouse fails them. */
34
- missingDescription: string[];
35
- /** Forms declaring a description but no name: nothing for an agent to call. */
36
- missingName: number;
37
- /** Tool names that are not usable identifiers. */
38
- invalidNames: string[];
39
- /** Annotated forms whose named controls lack `toolparamdescription`. */
40
- undescribedParams: {
41
- tool: string;
42
- missing: number;
43
- total: number;
44
- }[];
45
- autoSubmit: string[];
46
- }
47
- /** Analyse declarative WebMCP annotations across every form on the page. */
48
- export declare function analyseForms(html: string): FormAnalysis;
49
- /** Detect imperative WebMCP registration in inline scripts. */
50
- export declare function detectImperative(html: string): {
51
- registers: boolean;
52
- deprecatedNamespace: boolean;
53
- };
54
- export default function check(ctx: CheckContext): Promise<CheckResult>;
55
- //# sourceMappingURL=webmcp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webmcp.d.ts","sourceRoot":"","sources":["../../src/checks/webmcp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAIjF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAWF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wEAAwE;IACxE,iBAAiB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAWD,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiDvD;AAED,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAMnG;AAED,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAmH3E"}
@@ -1,209 +0,0 @@
1
- import { guideUrl } from '../guide-urls.js';
2
- import { buildResult, notApplicable } from './utils.js';
3
- import { getAttribute } from './html-utils.js';
4
- /**
5
- * "webmcp" — can a browser agent invoke this page's forms as tools?
6
- *
7
- * Today an agent that wants to use a form has to look at pixels, guess which
8
- * field is which, type into them, and hope. WebMCP lets a page declare a form as
9
- * a callable tool with named parameters, so the agent calls it instead of
10
- * driving it. The declarative form is two attributes:
11
- *
12
- * ```html
13
- * <form toolname="searchDocs" tooldescription="Search the documentation">
14
- * <input name="q" toolparamdescription="The search query">
15
- * </form>
16
- * ```
17
- *
18
- * Status, verified 2026-09-04: a W3C Web Machine Learning Community Group draft
19
- * with a Chrome origin trial running from Chrome 149. Not a standard, not
20
- * shipped by default, not implemented in Firefox or Safari. Adoption is
21
- * effectively zero.
22
- *
23
- * So this check never asks for WebMCP and never scores a site down for lacking
24
- * it. It reports N/A on a page with no forms and no WebMCP code at all. What it
25
- * does do, on pages that have adopted it, is catch the mistakes a static
26
- * analysis can catch with certainty: a `toolname` with no `tooldescription`,
27
- * which is the exact condition Lighthouse's `webmcp-schema-validity` audit
28
- * fails, parameters with no description, and use of the `navigator.modelContext`
29
- * namespace that Chrome deprecated in favour of `document.modelContext`.
30
- */
31
- export const meta = {
32
- id: 'webmcp',
33
- name: 'WebMCP',
34
- description: 'Checks declarative WebMCP tool annotations on forms',
35
- category: 'protocols',
36
- };
37
- /** Tool names are identifiers an agent calls, so they follow identifier rules. */
38
- const TOOL_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
39
- /** Form controls that carry a value an agent would need described. */
40
- const CONTROL_RE = /<(input|select|textarea)\b([^>]*)>/gi;
41
- /** Input types that carry no user-supplied value worth describing. */
42
- const VALUELESS_TYPES = new Set(['hidden', 'submit', 'button', 'reset', 'image']);
43
- /** Split the document into `<form>` blocks, keeping each element's attributes and inner HTML. */
44
- function forms(html) {
45
- const out = [];
46
- for (const m of html.matchAll(/<form\b([^>]*)>([\s\S]*?)<\/form>/gi)) {
47
- out.push({ attrs: m[1], inner: m[2] });
48
- }
49
- return out;
50
- }
51
- /** Analyse declarative WebMCP annotations across every form on the page. */
52
- export function analyseForms(html) {
53
- const analysis = {
54
- total: 0,
55
- annotated: 0,
56
- missingDescription: [],
57
- missingName: 0,
58
- invalidNames: [],
59
- undescribedParams: [],
60
- autoSubmit: [],
61
- };
62
- for (const form of forms(html)) {
63
- analysis.total++;
64
- const toolName = getAttribute(form.attrs, 'toolname');
65
- const toolDescription = getAttribute(form.attrs, 'tooldescription');
66
- if (toolName === null && toolDescription === null)
67
- continue;
68
- const label = toolName ?? '(unnamed)';
69
- analysis.annotated++;
70
- if (toolName === null || toolName.trim() === '') {
71
- analysis.missingName++;
72
- }
73
- if (toolDescription === null || toolDescription.trim() === '') {
74
- analysis.missingDescription.push(label);
75
- }
76
- if (toolName !== null && !TOOL_NAME_RE.test(toolName)) {
77
- analysis.invalidNames.push(toolName);
78
- }
79
- if (/\btoolautosubmit\b/i.test(form.attrs)) {
80
- analysis.autoSubmit.push(label);
81
- }
82
- let total = 0;
83
- let missing = 0;
84
- for (const control of form.inner.matchAll(CONTROL_RE)) {
85
- const attrs = control[2];
86
- const type = (getAttribute(attrs, 'type') ?? '').toLowerCase();
87
- if (VALUELESS_TYPES.has(type))
88
- continue;
89
- if (getAttribute(attrs, 'name') === null)
90
- continue;
91
- total++;
92
- if (getAttribute(attrs, 'toolparamdescription') === null)
93
- missing++;
94
- }
95
- if (total > 0 && missing > 0) {
96
- analysis.undescribedParams.push({ tool: label, missing, total });
97
- }
98
- }
99
- return analysis;
100
- }
101
- /** Detect imperative WebMCP registration in inline scripts. */
102
- export function detectImperative(html) {
103
- const scripts = [...html.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script>/gi)].map((m) => m[1]).join('\n');
104
- return {
105
- registers: /\bmodelContext\s*\.\s*(registerTool|provideContext)\s*\(/.test(scripts),
106
- deprecatedNamespace: /\bnavigator\s*\.\s*modelContext\b/.test(scripts),
107
- };
108
- }
109
- export default async function check(ctx) {
110
- const start = performance.now();
111
- const findings = [];
112
- let score = 100;
113
- const html = ctx.html ?? '';
114
- const analysis = analyseForms(html);
115
- const imperative = detectImperative(html);
116
- if (analysis.total === 0 && !imperative.registers && !imperative.deprecatedNamespace) {
117
- findings.push({
118
- status: 'pass',
119
- message: 'No forms and no WebMCP code — nothing here for an agent to invoke as a tool',
120
- });
121
- return notApplicable(meta, findings, start);
122
- }
123
- if (imperative.registers) {
124
- findings.push({
125
- status: 'pass',
126
- message: 'Imperative WebMCP registration detected in page scripts',
127
- detail: 'A static audit cannot enumerate the registered tools or validate their schemas; that needs a browser.',
128
- });
129
- }
130
- if (imperative.deprecatedNamespace) {
131
- findings.push({
132
- status: 'warn',
133
- message: 'Page uses the deprecated navigator.modelContext namespace',
134
- hint: 'Chrome moved the API to document.modelContext. Feature-detect both while the origin trial runs: const ctx = document.modelContext ?? navigator.modelContext.',
135
- learnMoreUrl: guideUrl(meta.id, 'deprecated-namespace'),
136
- });
137
- score -= 10;
138
- }
139
- if (analysis.annotated === 0) {
140
- findings.push({
141
- status: 'warn',
142
- message: `${analysis.total} form(s) on the page, none declared as agent tools`,
143
- detail: 'WebMCP is a W3C Community Group draft in a Chrome origin trial. It is not a standard and adoption is minimal, ' +
144
- 'so this is a forward-looking note, not a defect.',
145
- hint: 'A declared form is called by an agent rather than driven pixel by pixel. Add toolname and tooldescription to ' +
146
- 'the forms worth automating — search, filter, subscribe — and toolparamdescription to each field.',
147
- learnMoreUrl: guideUrl(meta.id, 'no-annotations'),
148
- });
149
- return buildResult(meta, score, findings, start);
150
- }
151
- findings.push({
152
- status: 'pass',
153
- message: `${analysis.annotated}/${analysis.total} form(s) declared as agent tools`,
154
- });
155
- if (analysis.missingDescription.length > 0) {
156
- findings.push({
157
- status: 'fail',
158
- message: `${analysis.missingDescription.length} tool form(s) declare a name but no description`,
159
- detail: analysis.missingDescription.join(', '),
160
- hint: 'The description is what an agent reads to decide whether to call the tool; a named tool without one is ' +
161
- 'unusable. Both attributes are required together.',
162
- learnMoreUrl: guideUrl(meta.id, 'missing-description'),
163
- });
164
- score -= 30;
165
- }
166
- if (analysis.missingName > 0) {
167
- findings.push({
168
- status: 'fail',
169
- message: `${analysis.missingName} form(s) declare a tool description but no tool name`,
170
- hint: 'Without a toolname there is nothing for an agent to call. Both attributes are required together.',
171
- learnMoreUrl: guideUrl(meta.id, 'missing-name'),
172
- });
173
- score -= 30;
174
- }
175
- if (analysis.invalidNames.length > 0) {
176
- findings.push({
177
- status: 'warn',
178
- message: 'Tool name is not a usable identifier',
179
- detail: analysis.invalidNames.join(', '),
180
- hint: 'A tool name is called like a function. Use letters, digits and underscores, starting with a letter: searchDocs, subscribe_newsletter.',
181
- learnMoreUrl: guideUrl(meta.id, 'invalid-name'),
182
- });
183
- score -= 10;
184
- }
185
- if (analysis.undescribedParams.length > 0) {
186
- const totalMissing = analysis.undescribedParams.reduce((acc, p) => acc + p.missing, 0);
187
- findings.push({
188
- status: 'warn',
189
- message: `${totalMissing} tool parameter(s) have no description`,
190
- detail: analysis.undescribedParams.map((p) => `${p.tool}: ${p.missing}/${p.total} fields undescribed`).join('\n'),
191
- hint: 'Add toolparamdescription to each named field. Without it an agent has to infer a field’s meaning from its ' +
192
- 'name, which is how a search box gets an email address in it.',
193
- learnMoreUrl: guideUrl(meta.id, 'undescribed-params'),
194
- });
195
- score -= 15;
196
- }
197
- else {
198
- findings.push({ status: 'pass', message: 'Every tool parameter carries a description' });
199
- }
200
- if (analysis.autoSubmit.length > 0) {
201
- findings.push({
202
- status: 'pass',
203
- message: `${analysis.autoSubmit.length} tool form(s) declare toolautosubmit`,
204
- detail: 'The agent submits without a further confirmation step. Appropriate for read-only actions such as search, not for anything that charges, sends or deletes.',
205
- });
206
- }
207
- return buildResult(meta, score, findings, start);
208
- }
209
- //# sourceMappingURL=webmcp.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webmcp.js","sourceRoot":"","sources":["../../src/checks/webmcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,IAAI,GAAc;IAC7B,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,qDAAqD;IAClE,QAAQ,EAAE,WAAW;CACtB,CAAC;AAEF,kFAAkF;AAClF,MAAM,YAAY,GAAG,gCAAgC,CAAC;AAEtD,sEAAsE;AACtE,MAAM,UAAU,GAAG,sCAAsC,CAAC;AAE1D,sEAAsE;AACtE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAgBlF,iGAAiG;AACjG,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,GAAG,GAAuC,EAAE,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,qCAAqC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,QAAQ,GAAiB;QAC7B,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,CAAC;QACZ,kBAAkB,EAAE,EAAE;QACtB,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE,EAAE;QACrB,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,QAAQ,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACtD,MAAM,eAAe,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;QACpE,IAAI,QAAQ,KAAK,IAAI,IAAI,eAAe,KAAK,IAAI;YAAE,SAAS;QAE5D,MAAM,KAAK,GAAG,QAAQ,IAAI,WAAW,CAAC;QACtC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAErB,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAChD,QAAQ,CAAC,WAAW,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC9D,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtD,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;QACD,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3C,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAED,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACtD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACzB,MAAM,IAAI,GAAG,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YAC/D,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YACxC,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI;gBAAE,SAAS;YACnD,KAAK,EAAE,CAAC;YACR,IAAI,YAAY,CAAC,KAAK,EAAE,sBAAsB,CAAC,KAAK,IAAI;gBAAE,OAAO,EAAE,CAAC;QACtE,CAAC;QACD,IAAI,KAAK,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAC7B,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,uCAAuC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxG,OAAO;QACL,SAAS,EAAE,0DAA0D,CAAC,IAAI,CAAC,OAAO,CAAC;QACnF,mBAAmB,EAAE,mCAAmC,CAAC,IAAI,CAAC,OAAO,CAAC;KACvE,CAAC;AACJ,CAAC;AAED,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,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAE1C,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC;QACrF,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,6EAA6E;SACvF,CAAC,CAAC;QACH,OAAO,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,yDAAyD;YAClE,MAAM,EAAE,uGAAuG;SAChH,CAAC,CAAC;IACL,CAAC;IAED,IAAI,UAAU,CAAC,mBAAmB,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,2DAA2D;YACpE,IAAI,EAAE,8JAA8J;YACpK,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,sBAAsB,CAAC;SACxD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,oDAAoD;YAC9E,MAAM,EACJ,gHAAgH;gBAChH,kDAAkD;YACpD,IAAI,EACF,+GAA+G;gBAC/G,kGAAkG;YACpG,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC;SAClD,CAAC,CAAC;QACH,OAAO,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,QAAQ,CAAC,IAAI,CAAC;QACZ,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,KAAK,kCAAkC;KACnF,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,QAAQ,CAAC,kBAAkB,CAAC,MAAM,iDAAiD;YAC/F,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9C,IAAI,EACF,yGAAyG;gBACzG,kDAAkD;YACpD,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC;SACvD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,QAAQ,CAAC,WAAW,sDAAsD;YACtF,IAAI,EAAE,kGAAkG;YACxG,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC;SAChD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,sCAAsC;YAC/C,MAAM,EAAE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,uIAAuI;YAC7I,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,CAAC;SAChD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,IAAI,QAAQ,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,YAAY,GAAG,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvF,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,YAAY,wCAAwC;YAChE,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,qBAAqB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACjH,IAAI,EACF,4GAA4G;gBAC5G,8DAA8D;YAChE,YAAY,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,oBAAoB,CAAC;SACtD,CAAC,CAAC;QACH,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,4CAA4C,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,sCAAsC;YAC5E,MAAM,EACJ,2JAA2J;SAC9J,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC"}
@@ -1,38 +0,0 @@
1
- /**
2
- * Standing of every well-known URI and discovery convention ax-audit probes.
3
- *
4
- * The agent web is a mix of IETF-registered URIs, vendor conventions that are
5
- * widely deployed but unregistered, and drafts that may be renamed next month.
6
- * Reporting them all as equally authoritative would be misleading, so every
7
- * probe carries its standing and audiences can weigh a miss accordingly:
8
- *
9
- * - `registered` — in the IANA Well-Known URI registry (permanent or provisional).
10
- * - `convention` — no registration, but shipped by multiple independent vendors.
11
- * - `draft` — an open spec PR, individual I-D, or origin-trial-era proposal.
12
- * - `legacy` — superseded or abandoned; recognised so we can advise removal.
13
- *
14
- * Registry snapshot: https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml
15
- * (last verified 2026-09-04, registry last updated 2026-08-19).
16
- */
17
- export type Standing = 'registered' | 'convention' | 'draft' | 'legacy';
18
- export interface WellKnownEntry {
19
- /** Path as probed, root-relative. */
20
- path: string;
21
- standing: Standing;
22
- /** Short human label used in findings. */
23
- label: string;
24
- /** Authoritative reference for the path. */
25
- specUrl: string;
26
- /** Free-text note surfaced in `detail` when the standing is not `registered`. */
27
- note?: string;
28
- }
29
- /**
30
- * Every path ax-audit knows about, keyed by path. Checks look up their probe
31
- * targets here so a rename in a draft spec is a one-line change in one file.
32
- */
33
- export declare const WELL_KNOWN: Record<string, WellKnownEntry>;
34
- /** Look up a path's standing, defaulting to `convention` for unknown paths. */
35
- export declare function standingOf(path: string): Standing;
36
- /** Human sentence describing a path's standing, for finding details. */
37
- export declare function standingNote(path: string): string | undefined;
38
- //# sourceMappingURL=well-known.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"well-known.d.ts","sourceRoot":"","sources":["../../src/checks/well-known.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC;AAExE,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAqLrD,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAEjD;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAY7D"}