From d45f676f3732292bf117cde84d23cfca7638b29b Mon Sep 17 00:00:00 2001 From: Florian Berger Date: Tue, 22 Sep 2026 09:51:20 +0200 Subject: [PATCH 1/3] well-known: add /.well-known/ai-catalog.json (Agentic Resource Discovery) --- dist/well-known.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/dist/well-known.js b/dist/well-known.js index 86de465..a8fd826 100644 --- a/dist/well-known.js +++ b/dist/well-known.js @@ -276,6 +276,32 @@ return Promise.all([ return data; }); }), + // Agentic Resource Discovery (ARD) - checked by Lighthouse's agentic-browsing category + // (core/gather/gatherers/agentic/ard.js falls back to this path) + parseResponse('/.well-known/ai-catalog.json', r => { + return r.text().then(text => { + let result = { + spec_version: null, + has_host: false, + entries_count: 0, + entry_types: [] + }; + try { + const data = JSON.parse(text); + result.spec_version = typeof data.specVersion === 'string' ? data.specVersion : null; + result.has_host = !!(data.host && typeof data.host === 'object'); + if (Array.isArray(data.entries)) { + result.entries_count = data.entries.length; + result.entry_types = [...new Set(data.entries + .map(e => e && typeof e.type === 'string' ? e.type : null) + .filter(Boolean))].slice(0, 20); + } + } catch (e) { + // Failed to parse JSON, result will contain default values. + } + return result; + }); + }), parseResponseWithRedirects('/.well-known/security.txt', r => { let data = { status: r.status, From 28fba51a6d31aaa5c7109b672281bf91fec00b20 Mon Sep 17 00:00:00 2001 From: Florian Berger Date: Tue, 22 Sep 2026 11:48:49 +0200 Subject: [PATCH 2/3] well-known: resolve ai-catalog via when present, fall back to /.well-known path --- dist/well-known.js | 71 +++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/dist/well-known.js b/dist/well-known.js index a8fd826..25f3172 100644 --- a/dist/well-known.js +++ b/dist/well-known.js @@ -276,32 +276,57 @@ return Promise.all([ return data; }); }), - // Agentic Resource Discovery (ARD) - checked by Lighthouse's agentic-browsing category - // (core/gather/gatherers/agentic/ard.js falls back to this path) - parseResponse('/.well-known/ai-catalog.json', r => { - return r.text().then(text => { - let result = { - spec_version: null, - has_host: false, - entries_count: 0, - entry_types: [] - }; - try { - const data = JSON.parse(text); - result.spec_version = typeof data.specVersion === 'string' ? data.specVersion : null; - result.has_host = !!(data.host && typeof data.host === 'object'); - if (Array.isArray(data.entries)) { - result.entries_count = data.entries.length; - result.entry_types = [...new Set(data.entries - .map(e => e && typeof e.type === 'string' ? e.type : null) - .filter(Boolean))].slice(0, 20); + // Agentic Resource Discovery (ARD) - checked by Lighthouse's agentic-browsing category. + // Resolution follows Lighthouse's ARD gatherer (core/gather/gatherers/agentic/ard.js): + // in the document wins, otherwise /.well-known/ai-catalog.json. + // Output is keyed by the well-known path either way so the BigQuery key stays stable; + // `catalog_url` and `source` say what was actually fetched. + (() => { + const wellKnownUrl = '/.well-known/ai-catalog.json'; + let catalogUrl = wellKnownUrl; + let source = 'well-known'; + try { + const link = document.querySelector('link[rel~="ai-catalog" i]'); + if (link && link.href) { + catalogUrl = link.href; + source = 'link'; + } + } catch (e) { + // No document access, fall back to the well-known path. + } + return parseResponse(catalogUrl, r => { + return r.text().then(text => { + let result = { + catalog_url: catalogUrl, + source: source, + spec_version: null, + has_host: false, + entries_count: 0, + entry_types: [] + }; + try { + const data = JSON.parse(text); + result.spec_version = typeof data.specVersion === 'string' ? data.specVersion : null; + result.has_host = !!(data.host && typeof data.host === 'object'); + if (Array.isArray(data.entries)) { + result.entries_count = data.entries.length; + result.entry_types = [...new Set(data.entries + .map(e => e && typeof e.type === 'string' ? e.type : null) + .filter(Boolean))].slice(0, 20); + } + } catch (e) { + // Failed to parse JSON, result will contain default values. } - } catch (e) { - // Failed to parse JSON, result will contain default values. + return result; + }); + }).then(([, resultObj]) => { + if (!resultObj.data) { + resultObj.catalog_url = catalogUrl; + resultObj.source = source; } - return result; + return [wellKnownUrl, resultObj]; }); - }), + })(), parseResponseWithRedirects('/.well-known/security.txt', r => { let data = { status: r.status, From 8f72116f0bd884c9f4e8cf2fa97bb0775b3c0b52 Mon Sep 17 00:00:00 2001 From: Florian Berger Date: Thu, 24 Sep 2026 05:43:01 +0200 Subject: [PATCH 3/3] well-known: slimmer ai-catalog output (found:false only, catalog_url only for non-default link targets, drop source) --- dist/well-known.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/dist/well-known.js b/dist/well-known.js index 25f3172..224e38e 100644 --- a/dist/well-known.js +++ b/dist/well-known.js @@ -279,26 +279,25 @@ return Promise.all([ // Agentic Resource Discovery (ARD) - checked by Lighthouse's agentic-browsing category. // Resolution follows Lighthouse's ARD gatherer (core/gather/gatherers/agentic/ard.js): // in the document wins, otherwise /.well-known/ai-catalog.json. - // Output is keyed by the well-known path either way so the BigQuery key stays stable; - // `catalog_url` and `source` say what was actually fetched. + // Keyed by the well-known path either way; `catalog_url` is added only when the + // link points somewhere other than the default location. (() => { const wellKnownUrl = '/.well-known/ai-catalog.json'; - let catalogUrl = wellKnownUrl; - let source = 'well-known'; + let catalogUrl = null; try { const link = document.querySelector('link[rel~="ai-catalog" i]'); if (link && link.href) { - catalogUrl = link.href; - source = 'link'; + const target = new URL(link.href, location.href); + if (target.origin !== location.origin || target.pathname !== wellKnownUrl) { + catalogUrl = target.href; + } } } catch (e) { - // No document access, fall back to the well-known path. + // No usable link, fall back to the well-known path. } - return parseResponse(catalogUrl, r => { + return parseResponse(catalogUrl || wellKnownUrl, r => { return r.text().then(text => { let result = { - catalog_url: catalogUrl, - source: source, spec_version: null, has_host: false, entries_count: 0, @@ -320,9 +319,8 @@ return Promise.all([ return result; }); }).then(([, resultObj]) => { - if (!resultObj.data) { + if (catalogUrl) { resultObj.catalog_url = catalogUrl; - resultObj.source = source; } return [wellKnownUrl, resultObj]; });