@farming-labs/docs 0.2.62 → 0.2.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-CQTH7NFu.mjs +624 -0
- package/dist/agent-DKKptIgy.mjs +4365 -0
- package/dist/agent-evals-B7MIxuEX.mjs +2144 -0
- package/dist/agent-export-CBgWgPvH.mjs +910 -0
- package/dist/agent-scope-C_U--OZ7.mjs +283 -0
- package/dist/agent-skills-bundle.d.mts +13 -0
- package/dist/agent-skills-bundle.mjs +12 -0
- package/dist/agent-skills-server-CPja6Syt.d.mts +14 -0
- package/dist/agent-skills-server-DraIb6FV.mjs +415 -0
- package/dist/agent-skills-vite.d.mts +31 -0
- package/dist/agent-skills-vite.mjs +70 -0
- package/dist/agents-XWZBub6f.mjs +221 -0
- package/dist/analytics-Bx44lg6d.mjs +177 -0
- package/dist/cli/index.d.mts +15 -0
- package/dist/cli/index.mjs +452 -0
- package/dist/client/react.d.mts +45 -0
- package/dist/client/react.mjs +223 -0
- package/dist/cloud-analytics-CSyFE6SS.mjs +132 -0
- package/dist/cloud-ask-ai-sbpjOR2K.mjs +382 -0
- package/dist/cloud-ask-ai-zpwkdwnF.d.mts +23 -0
- package/dist/cloud-pdNC-tyj.mjs +1615 -0
- package/dist/code-blocks-DnNVNK2M.mjs +871 -0
- package/dist/codeblocks-CFuurVIH.mjs +250 -0
- package/dist/config-Wcdj-D0a.mjs +369 -0
- package/dist/dev-Cmy6DtdF.mjs +1333 -0
- package/dist/docs-cloud-server.d.mts +70 -0
- package/dist/docs-cloud-server.mjs +310 -0
- package/dist/doctor-DtGYZ41i.mjs +2036 -0
- package/dist/downgrade-w7e6Se0L.mjs +184 -0
- package/dist/errors-DbOhkE1h.mjs +20 -0
- package/dist/golden-evaluations-Dj-9Eo3v.mjs +1785 -0
- package/dist/i18n-CCaFUnAN.mjs +40 -0
- package/dist/index.d.mts +1150 -0
- package/dist/index.mjs +10 -0
- package/dist/init-CQY0Woe3.mjs +1264 -0
- package/dist/mcp-B9dcsivk.mjs +156 -0
- package/dist/mcp.d.mts +298 -0
- package/dist/mcp.mjs +4430 -0
- package/dist/metadata-DWExHQnx.mjs +237 -0
- package/dist/package-version-n5AFur8a.mjs +128 -0
- package/dist/reading-time-CYZ5VvKU.mjs +742 -0
- package/dist/review-CLoHTywU.mjs +673 -0
- package/dist/robots-BIpC4j4P.mjs +201 -0
- package/dist/robots-CUTahhoY.mjs +179 -0
- package/dist/search-B6V6qtiI.mjs +1826 -0
- package/dist/search-CaSyi6H6.d.mts +279 -0
- package/dist/search-DSjCeOk7.mjs +104 -0
- package/dist/server.d.mts +343 -0
- package/dist/server.mjs +14 -0
- package/dist/sitemap-Cykpe3Tz.mjs +249 -0
- package/dist/sitemap-server-C_6Wes83.mjs +1137 -0
- package/dist/standards-discovery-C4HUqMd2.d.mts +227 -0
- package/dist/standards-discovery-jkykaXq1.mjs +519 -0
- package/dist/templates-Bq_P7ctv.mjs +2465 -0
- package/dist/types-lMBIdZg0.d.mts +3315 -0
- package/dist/upgrade-oz-GChgt.mjs +56 -0
- package/dist/utils-DpiIioYb.mjs +225 -0
- package/package.json +1 -1
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import matter from "gray-matter";
|
|
2
|
+
|
|
3
|
+
//#region src/standards-discovery.ts
|
|
4
|
+
const DEFAULT_API_CATALOG_ROUTE = "/.well-known/api-catalog";
|
|
5
|
+
const DEFAULT_API_CATALOG_FORMAT = "api-catalog";
|
|
6
|
+
const API_CATALOG_PROFILE_URI = "https://www.rfc-editor.org/info/rfc9727";
|
|
7
|
+
const API_CATALOG_MEDIA_TYPE = "application/linkset+json";
|
|
8
|
+
const DEFAULT_AGENT_SKILLS_INDEX_ROUTE = "/.well-known/agent-skills/index.json";
|
|
9
|
+
const DEFAULT_AGENT_SKILLS_ROUTE_PREFIX = "/.well-known/agent-skills";
|
|
10
|
+
const DEFAULT_AGENT_SKILLS_ROUTE_PATTERN = `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/{name}/SKILL.md`;
|
|
11
|
+
const DEFAULT_AGENT_SKILLS_ARCHIVE_ROUTE_PATTERN = `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/{name}.tar.gz`;
|
|
12
|
+
const DEFAULT_AGENT_SKILLS_INDEX_FORMAT = "agent-skills";
|
|
13
|
+
const DEFAULT_AGENT_SKILL_FORMAT = "agent-skill";
|
|
14
|
+
const DEFAULT_AGENT_SKILL_ARCHIVE_FORMAT = "agent-skill-archive";
|
|
15
|
+
const DEFAULT_AGENT_SKILL_FILE_FORMAT = "agent-skill-file";
|
|
16
|
+
const DEFAULT_AGENT_SKILL_RESOURCE_FORMAT = "agent-skill-resource";
|
|
17
|
+
const DEFAULT_LEGACY_SKILLS_INDEX_ROUTE = "/.well-known/skills/index.json";
|
|
18
|
+
const DEFAULT_LEGACY_SKILLS_INDEX_FORMAT = "legacy-skills";
|
|
19
|
+
const DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX = "/.well-known/skills";
|
|
20
|
+
const DEFAULT_A2A_AGENT_CARD_ROUTE = "/.well-known/agent-card.json";
|
|
21
|
+
const DEFAULT_A2A_AGENT_CARD_FORMAT = "agent-card";
|
|
22
|
+
const AGENT_SKILLS_DISCOVERY_SCHEMA_URI = "https://schemas.agentskills.io/discovery/0.2.0/schema.json";
|
|
23
|
+
const DEFAULT_DOCS_API_ROUTE = "/api/docs";
|
|
24
|
+
const DEFAULT_AGENT_MANIFEST_ROUTE = "/.well-known/agent.json";
|
|
25
|
+
const AGENT_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
26
|
+
const AGENT_SKILL_NAME_MAX_LENGTH = 64;
|
|
27
|
+
const AGENT_SKILL_DESCRIPTION_MAX_LENGTH = 1024;
|
|
28
|
+
const DISCOVERY_CACHE_CONTROL = "public, max-age=0, s-maxage=3600";
|
|
29
|
+
function normalizeDocsRoute(value) {
|
|
30
|
+
const normalized = `/${value.trim()}`.replace(/\/{2,}/g, "/");
|
|
31
|
+
return normalized === "/" ? normalized : normalized.replace(/\/+$/, "");
|
|
32
|
+
}
|
|
33
|
+
/** Resolve the same-origin Docs API pathname used by query-form discovery routes. */
|
|
34
|
+
function resolveDocsDiscoveryApiRoute(apiRoute) {
|
|
35
|
+
const candidate = apiRoute?.trim().split(/[?#]/, 1)[0];
|
|
36
|
+
return normalizeDocsRoute(candidate || DEFAULT_DOCS_API_ROUTE);
|
|
37
|
+
}
|
|
38
|
+
function resolveHttpUrl(value, origin) {
|
|
39
|
+
if (!value) return null;
|
|
40
|
+
try {
|
|
41
|
+
const base = new URL(origin);
|
|
42
|
+
const resolved = new URL(value, `${base.origin}/`);
|
|
43
|
+
if (resolved.protocol !== "http:" && resolved.protocol !== "https:") return null;
|
|
44
|
+
return resolved.toString();
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function compactUniqueTargets(targets) {
|
|
50
|
+
const seen = /* @__PURE__ */ new Set();
|
|
51
|
+
return targets.filter((target) => {
|
|
52
|
+
if (!target) return false;
|
|
53
|
+
const key = `${target.href}\u0000${target.type ?? ""}\u0000${target.title ?? ""}`;
|
|
54
|
+
if (seen.has(key)) return false;
|
|
55
|
+
seen.add(key);
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function toTarget(route, origin, type, title) {
|
|
60
|
+
const href = resolveHttpUrl(route, origin);
|
|
61
|
+
return href ? {
|
|
62
|
+
href,
|
|
63
|
+
...type ? { type } : {},
|
|
64
|
+
...title ? { title } : {}
|
|
65
|
+
} : null;
|
|
66
|
+
}
|
|
67
|
+
/** Build an RFC 9727 API Catalog using the RFC 9264 JSON Linkset representation. */
|
|
68
|
+
function buildDocsApiCatalog(options) {
|
|
69
|
+
const catalogUrl = resolveHttpUrl(DEFAULT_API_CATALOG_ROUTE, options.origin);
|
|
70
|
+
if (!catalogUrl) throw new Error(`Invalid HTTP(S) docs origin for API catalog: ${options.origin}`);
|
|
71
|
+
const apiRoute = options.apiRoute === null ? null : resolveDocsDiscoveryApiRoute(options.apiRoute);
|
|
72
|
+
const agentManifestRoute = options.agentManifestRoute === void 0 ? DEFAULT_AGENT_MANIFEST_ROUTE : options.agentManifestRoute;
|
|
73
|
+
const agentSkillsIndexRoute = options.agentSkillsIndexRoute === void 0 ? DEFAULT_AGENT_SKILLS_INDEX_ROUTE : options.agentSkillsIndexRoute;
|
|
74
|
+
const apiTargets = compactUniqueTargets([
|
|
75
|
+
toTarget(apiRoute, options.origin, "application/json", "Documentation API"),
|
|
76
|
+
...(options.apiRoutes ?? []).map((target) => toTarget(target.route, options.origin, target.type, target.title)),
|
|
77
|
+
toTarget(options.mcpRoute, options.origin, "application/json", "Documentation MCP endpoint"),
|
|
78
|
+
...(options.feedbackRoutes ?? []).map((route, index) => toTarget(route, options.origin, index === 0 ? "application/json" : "application/schema+json", index === 0 ? "Agent feedback endpoint" : "Agent feedback schema"))
|
|
79
|
+
]);
|
|
80
|
+
const serviceDocs = compactUniqueTargets([
|
|
81
|
+
toTarget(options.docsRoute ?? "/docs", options.origin, "text/html", "Documentation"),
|
|
82
|
+
toTarget(options.markdownRootRoute, options.origin, "text/markdown", "Documentation Markdown"),
|
|
83
|
+
toTarget(options.agentsRoute, options.origin, "text/markdown", "Agent instructions"),
|
|
84
|
+
toTarget(options.skillRoute, options.origin, "text/markdown", "Site skill"),
|
|
85
|
+
...(options.llmsRoutes ?? []).map((route) => toTarget(route, options.origin, "text/plain", "LLM documentation index")),
|
|
86
|
+
...(options.sitemapRoutes ?? []).map((route) => toTarget(route, options.origin, route.endsWith(".xml") ? "application/xml" : "text/markdown", "Documentation sitemap")),
|
|
87
|
+
toTarget(options.apiReferenceRoute, options.origin, "text/html", "API reference")
|
|
88
|
+
]);
|
|
89
|
+
const serviceMetadata = compactUniqueTargets([
|
|
90
|
+
toTarget(agentManifestRoute, options.origin, "application/json", "Agent discovery manifest"),
|
|
91
|
+
toTarget(agentSkillsIndexRoute, options.origin, "application/json", "Agent Skills discovery index"),
|
|
92
|
+
toTarget(options.legacySkillsIndexRoute === void 0 ? DEFAULT_LEGACY_SKILLS_INDEX_ROUTE : options.legacySkillsIndexRoute, options.origin, "application/json", "Legacy Agent Skills discovery index"),
|
|
93
|
+
toTarget(options.agentCardRoute, options.origin, "application/json", "A2A Agent Card"),
|
|
94
|
+
toTarget(options.configRoute, options.origin, "application/json", "Docs configuration map"),
|
|
95
|
+
toTarget(options.diagnosticsRoute, options.origin, "application/json", "Docs diagnostics"),
|
|
96
|
+
toTarget(options.robotsRoute, options.origin, "text/plain", "Robots policy"),
|
|
97
|
+
...(options.protectedResourceMetadataRoutes ?? []).map((route) => toTarget(route, options.origin, "application/json", "OAuth protected-resource metadata"))
|
|
98
|
+
]);
|
|
99
|
+
const serviceDescriptions = compactUniqueTargets([toTarget(options.openapiRoute, options.origin, "application/vnd.oai.openapi+json;version=3.1", "OpenAPI schema")]);
|
|
100
|
+
const catalogContext = {
|
|
101
|
+
anchor: catalogUrl,
|
|
102
|
+
"api-catalog": [{
|
|
103
|
+
href: catalogUrl,
|
|
104
|
+
type: API_CATALOG_MEDIA_TYPE,
|
|
105
|
+
title: "API catalog"
|
|
106
|
+
}]
|
|
107
|
+
};
|
|
108
|
+
if (apiTargets.length > 0) catalogContext.item = apiTargets;
|
|
109
|
+
if (serviceDocs.length > 0) catalogContext["service-doc"] = serviceDocs;
|
|
110
|
+
if (serviceMetadata.length > 0) catalogContext["service-meta"] = serviceMetadata;
|
|
111
|
+
if (serviceDescriptions.length > 0) catalogContext["service-desc"] = serviceDescriptions;
|
|
112
|
+
const linkset = [catalogContext];
|
|
113
|
+
for (const target of apiTargets) {
|
|
114
|
+
const context = { anchor: target.href };
|
|
115
|
+
if (serviceDocs.length > 0) context["service-doc"] = serviceDocs;
|
|
116
|
+
if (serviceMetadata.length > 0) context["service-meta"] = serviceMetadata;
|
|
117
|
+
if (serviceDescriptions.length > 0 && target.href === resolveHttpUrl(apiRoute, options.origin)) context["service-desc"] = serviceDescriptions;
|
|
118
|
+
linkset.push(context);
|
|
119
|
+
}
|
|
120
|
+
return { linkset };
|
|
121
|
+
}
|
|
122
|
+
function readAgentSkillFrontmatter(document) {
|
|
123
|
+
const normalized = document.startsWith("") ? document.slice(1) : document;
|
|
124
|
+
let data;
|
|
125
|
+
try {
|
|
126
|
+
data = matter(normalized).data;
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const name = typeof data.name === "string" ? data.name.trim() : "";
|
|
131
|
+
const description = typeof data.description === "string" ? data.description.trim() : "";
|
|
132
|
+
if (!name || name.length > AGENT_SKILL_NAME_MAX_LENGTH || !AGENT_SKILL_NAME_PATTERN.test(name) || !description || description.length > AGENT_SKILL_DESCRIPTION_MAX_LENGTH) return null;
|
|
133
|
+
return {
|
|
134
|
+
name,
|
|
135
|
+
description
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function toDiscoveryBytes(content) {
|
|
139
|
+
if (typeof content === "string") return new TextEncoder().encode(content);
|
|
140
|
+
const bytes = new Uint8Array(new ArrayBuffer(content.byteLength));
|
|
141
|
+
bytes.set(content);
|
|
142
|
+
return bytes;
|
|
143
|
+
}
|
|
144
|
+
function toPublishedSkillArray(skills) {
|
|
145
|
+
return Array.isArray(skills) ? skills : [skills];
|
|
146
|
+
}
|
|
147
|
+
async function sha256DocsDiscoveryContent(content) {
|
|
148
|
+
const subtle = globalThis.crypto?.subtle;
|
|
149
|
+
if (!subtle) throw new Error("Web Crypto SHA-256 support is required for Agent Skills discovery.");
|
|
150
|
+
const digest = await subtle.digest("SHA-256", toDiscoveryBytes(content));
|
|
151
|
+
return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
152
|
+
}
|
|
153
|
+
function createDocsPublishedAgentSkill(content, metadata, sha256) {
|
|
154
|
+
return {
|
|
155
|
+
name: metadata.name,
|
|
156
|
+
type: "skill-md",
|
|
157
|
+
description: metadata.description,
|
|
158
|
+
url: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${metadata.name}/SKILL.md`,
|
|
159
|
+
digest: `sha256:${sha256}`,
|
|
160
|
+
content,
|
|
161
|
+
sha256,
|
|
162
|
+
skillDocument: content,
|
|
163
|
+
files: [{
|
|
164
|
+
path: "SKILL.md",
|
|
165
|
+
url: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${metadata.name}/SKILL.md`,
|
|
166
|
+
mediaType: "text/markdown",
|
|
167
|
+
content,
|
|
168
|
+
sha256,
|
|
169
|
+
digest: `sha256:${sha256}`
|
|
170
|
+
}]
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/** Build a published skill from an exact SKILL.md document and its precomputed SHA-256. */
|
|
174
|
+
function buildDocsPublishedAgentSkill(document, sha256) {
|
|
175
|
+
const metadata = readAgentSkillFrontmatter(document);
|
|
176
|
+
if (!metadata) throw new Error("The generated Agent Skills fallback must contain valid name and description frontmatter.");
|
|
177
|
+
if (!/^[a-f0-9]{64}$/.test(sha256)) throw new Error("Agent Skill SHA-256 must be a lowercase 64-character hexadecimal digest.");
|
|
178
|
+
return createDocsPublishedAgentSkill(document, metadata, sha256);
|
|
179
|
+
}
|
|
180
|
+
/** Select a valid public skill and hash the exact bytes returned by its standards route. */
|
|
181
|
+
async function resolveDocsPublishedAgentSkill({ preferredDocument, fallbackDocument }) {
|
|
182
|
+
const preferredMetadata = preferredDocument ? readAgentSkillFrontmatter(preferredDocument) : null;
|
|
183
|
+
const fallbackMetadata = readAgentSkillFrontmatter(fallbackDocument);
|
|
184
|
+
const content = preferredMetadata ? preferredDocument : fallbackDocument;
|
|
185
|
+
const metadata = preferredMetadata ?? fallbackMetadata;
|
|
186
|
+
if (!metadata) throw new Error("The generated Agent Skills fallback must contain valid name and description frontmatter.");
|
|
187
|
+
return createDocsPublishedAgentSkill(content, metadata, await sha256DocsDiscoveryContent(content));
|
|
188
|
+
}
|
|
189
|
+
function buildDocsAgentSkillsIndex(skills) {
|
|
190
|
+
return {
|
|
191
|
+
$schema: AGENT_SKILLS_DISCOVERY_SCHEMA_URI,
|
|
192
|
+
skills: toPublishedSkillArray(skills).map(({ name, type, description, url, digest }) => ({
|
|
193
|
+
name,
|
|
194
|
+
type,
|
|
195
|
+
description,
|
|
196
|
+
url,
|
|
197
|
+
digest
|
|
198
|
+
})).sort((left, right) => left.name.localeCompare(right.name))
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/** Build the compatibility index used by older Agent Skills clients. */
|
|
202
|
+
function buildDocsLegacySkillsIndex(skills) {
|
|
203
|
+
return { skills: toPublishedSkillArray(skills).map((skill) => ({
|
|
204
|
+
name: skill.name,
|
|
205
|
+
description: skill.description,
|
|
206
|
+
files: [...skill.files].sort((left, right) => {
|
|
207
|
+
if (left.path === "SKILL.md") return -1;
|
|
208
|
+
if (right.path === "SKILL.md") return 1;
|
|
209
|
+
return left.path.localeCompare(right.path);
|
|
210
|
+
}).map((file) => file.path)
|
|
211
|
+
})).sort((left, right) => left.name.localeCompare(right.name)) };
|
|
212
|
+
}
|
|
213
|
+
/** Build an A2A Agent Card only when a real A2A interface is explicitly configured. */
|
|
214
|
+
function buildDocsA2AAgentCard(options, skills) {
|
|
215
|
+
const interfaceUrl = resolveHttpUrl(options.interfaceUrl, options.interfaceUrl);
|
|
216
|
+
const documentationUrl = resolveHttpUrl(options.documentationUrl, options.interfaceUrl);
|
|
217
|
+
const providerUrl = resolveHttpUrl(options.provider.url, options.interfaceUrl);
|
|
218
|
+
if (!interfaceUrl || !documentationUrl || !providerUrl) throw new Error("A2A Agent Card URLs must use HTTP(S).");
|
|
219
|
+
const protocolVersion = options.protocolVersion ?? "0.3";
|
|
220
|
+
const protocolBinding = options.protocolBinding ?? "HTTP+JSON";
|
|
221
|
+
return {
|
|
222
|
+
protocolVersion,
|
|
223
|
+
preferredTransport: protocolBinding,
|
|
224
|
+
supportedInterfaces: [{
|
|
225
|
+
url: interfaceUrl,
|
|
226
|
+
protocolBinding,
|
|
227
|
+
protocolVersion
|
|
228
|
+
}],
|
|
229
|
+
name: options.name,
|
|
230
|
+
description: options.description,
|
|
231
|
+
url: interfaceUrl,
|
|
232
|
+
provider: {
|
|
233
|
+
organization: options.provider.organization,
|
|
234
|
+
url: providerUrl
|
|
235
|
+
},
|
|
236
|
+
version: options.version ?? "1.0.0",
|
|
237
|
+
documentationUrl,
|
|
238
|
+
capabilities: {
|
|
239
|
+
streaming: false,
|
|
240
|
+
pushNotifications: false
|
|
241
|
+
},
|
|
242
|
+
defaultInputModes: ["text/plain"],
|
|
243
|
+
defaultOutputModes: ["text/plain"],
|
|
244
|
+
skills: toPublishedSkillArray(skills).map((skill) => ({
|
|
245
|
+
id: skill.name,
|
|
246
|
+
name: skill.name,
|
|
247
|
+
description: skill.description,
|
|
248
|
+
tags: ["documentation"],
|
|
249
|
+
examples: [],
|
|
250
|
+
url: skill.url
|
|
251
|
+
})).sort((left, right) => left.name.localeCompare(right.name))
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function resolveDocsStandardsDiscoveryRequest(url, options = {}) {
|
|
255
|
+
const pathname = normalizeDocsRoute(url.pathname);
|
|
256
|
+
if (pathname === DEFAULT_API_CATALOG_ROUTE) return { kind: "api-catalog" };
|
|
257
|
+
if (pathname === DEFAULT_AGENT_SKILLS_INDEX_ROUTE) return { kind: "agent-skills-index" };
|
|
258
|
+
if (pathname === DEFAULT_LEGACY_SKILLS_INDEX_ROUTE) return { kind: "legacy-skills-index" };
|
|
259
|
+
if (pathname === DEFAULT_A2A_AGENT_CARD_ROUTE) return { kind: "agent-card" };
|
|
260
|
+
const archiveMatch = pathname.match(/^\/\.well-known\/agent-skills\/([^/]+)\.tar\.gz$/);
|
|
261
|
+
if (archiveMatch) try {
|
|
262
|
+
return {
|
|
263
|
+
kind: "agent-skill-archive",
|
|
264
|
+
name: decodeURIComponent(archiveMatch[1])
|
|
265
|
+
};
|
|
266
|
+
} catch {
|
|
267
|
+
return {
|
|
268
|
+
kind: "agent-skill-archive",
|
|
269
|
+
name: ""
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
const artifactMatch = pathname.match(/^\/\.well-known\/agent-skills\/([^/]+)\/skill\.md$/i);
|
|
273
|
+
if (artifactMatch) try {
|
|
274
|
+
return {
|
|
275
|
+
kind: "agent-skill",
|
|
276
|
+
name: decodeURIComponent(artifactMatch[1])
|
|
277
|
+
};
|
|
278
|
+
} catch {
|
|
279
|
+
return {
|
|
280
|
+
kind: "agent-skill",
|
|
281
|
+
name: ""
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const fileMatch = pathname.match(/^\/\.well-known\/agent-skills\/([^/]+)\/(references|scripts|assets)\/(.+)$/);
|
|
285
|
+
if (fileMatch) try {
|
|
286
|
+
return {
|
|
287
|
+
kind: "agent-skill-file",
|
|
288
|
+
name: decodeURIComponent(fileMatch[1]),
|
|
289
|
+
path: `${fileMatch[2]}/${decodeURIComponent(fileMatch[3])}`
|
|
290
|
+
};
|
|
291
|
+
} catch {
|
|
292
|
+
return {
|
|
293
|
+
kind: "agent-skill-file",
|
|
294
|
+
name: "",
|
|
295
|
+
path: ""
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const legacySkillMatch = pathname.match(/^\/\.well-known\/skills\/([^/]+)\/skill\.md$/i);
|
|
299
|
+
if (legacySkillMatch) try {
|
|
300
|
+
return {
|
|
301
|
+
kind: "agent-skill-file",
|
|
302
|
+
name: decodeURIComponent(legacySkillMatch[1]),
|
|
303
|
+
path: "SKILL.md"
|
|
304
|
+
};
|
|
305
|
+
} catch {
|
|
306
|
+
return {
|
|
307
|
+
kind: "agent-skill-file",
|
|
308
|
+
name: "",
|
|
309
|
+
path: ""
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
const legacyFileMatch = pathname.match(/^\/\.well-known\/skills\/([^/]+)\/(references|scripts|assets)\/(.+)$/);
|
|
313
|
+
if (legacyFileMatch) try {
|
|
314
|
+
return {
|
|
315
|
+
kind: "agent-skill-file",
|
|
316
|
+
name: decodeURIComponent(legacyFileMatch[1]),
|
|
317
|
+
path: `${legacyFileMatch[2]}/${decodeURIComponent(legacyFileMatch[3])}`
|
|
318
|
+
};
|
|
319
|
+
} catch {
|
|
320
|
+
return {
|
|
321
|
+
kind: "agent-skill-file",
|
|
322
|
+
name: "",
|
|
323
|
+
path: ""
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
if (pathname !== resolveDocsDiscoveryApiRoute(options.apiRoute)) return null;
|
|
327
|
+
const format = url.searchParams.get("format")?.trim();
|
|
328
|
+
if (format === DEFAULT_API_CATALOG_FORMAT) return { kind: "api-catalog" };
|
|
329
|
+
if (format === DEFAULT_AGENT_SKILLS_INDEX_FORMAT) return { kind: "agent-skills-index" };
|
|
330
|
+
if (format === DEFAULT_LEGACY_SKILLS_INDEX_FORMAT) return { kind: "legacy-skills-index" };
|
|
331
|
+
if (format === DEFAULT_A2A_AGENT_CARD_FORMAT) return { kind: "agent-card" };
|
|
332
|
+
if (format === DEFAULT_AGENT_SKILL_FORMAT) return {
|
|
333
|
+
kind: "agent-skill",
|
|
334
|
+
name: url.searchParams.get("name")?.trim() ?? ""
|
|
335
|
+
};
|
|
336
|
+
if (format === DEFAULT_AGENT_SKILL_ARCHIVE_FORMAT) return {
|
|
337
|
+
kind: "agent-skill-archive",
|
|
338
|
+
name: url.searchParams.get("name")?.trim() ?? ""
|
|
339
|
+
};
|
|
340
|
+
if (format === DEFAULT_AGENT_SKILL_FILE_FORMAT || format === DEFAULT_AGENT_SKILL_RESOURCE_FORMAT) return {
|
|
341
|
+
kind: "agent-skill-file",
|
|
342
|
+
name: url.searchParams.get("name")?.trim() ?? "",
|
|
343
|
+
path: url.searchParams.get("path")?.trim() ?? "SKILL.md"
|
|
344
|
+
};
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
function isDocsStandardsDiscoveryRequest(url, options = {}) {
|
|
348
|
+
return resolveDocsStandardsDiscoveryRequest(url, options) !== null;
|
|
349
|
+
}
|
|
350
|
+
function formatLinkTarget(href, relation, options = {}) {
|
|
351
|
+
return [
|
|
352
|
+
`<${href}>`,
|
|
353
|
+
`rel="${relation}"`,
|
|
354
|
+
...options.type ? [`type="${options.type}"`] : [],
|
|
355
|
+
...options.profile ? [`profile="${options.profile}"`] : []
|
|
356
|
+
].join("; ");
|
|
357
|
+
}
|
|
358
|
+
/** Cross-link the standards endpoints without replacing an existing canonical Link value. */
|
|
359
|
+
function getDocsDiscoveryLinkHeader(options = {}) {
|
|
360
|
+
return [
|
|
361
|
+
...options.includeApiCatalog === false ? [] : [formatLinkTarget(DEFAULT_API_CATALOG_ROUTE, "api-catalog", {
|
|
362
|
+
type: API_CATALOG_MEDIA_TYPE,
|
|
363
|
+
profile: API_CATALOG_PROFILE_URI
|
|
364
|
+
})],
|
|
365
|
+
...options.includeManifest === false ? [] : [formatLinkTarget(DEFAULT_AGENT_MANIFEST_ROUTE, "service-meta", { type: "application/json" })],
|
|
366
|
+
...options.includeSkills === false ? [] : [formatLinkTarget(DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "service-meta", { type: "application/json" }), formatLinkTarget(DEFAULT_LEGACY_SKILLS_INDEX_ROUTE, "service-meta", { type: "application/json" })],
|
|
367
|
+
...options.includeAgentCard ? [formatLinkTarget(DEFAULT_A2A_AGENT_CARD_ROUTE, "service-meta", { type: "application/json" })] : []
|
|
368
|
+
].join(", ");
|
|
369
|
+
}
|
|
370
|
+
function appendDocsDiscoveryLinkHeader(headers, value) {
|
|
371
|
+
const next = new Headers(headers);
|
|
372
|
+
const discoveryLinks = value ?? getDocsDiscoveryLinkHeader();
|
|
373
|
+
const existing = next.get("Link");
|
|
374
|
+
next.set("Link", existing ? `${existing}, ${discoveryLinks}` : discoveryLinks);
|
|
375
|
+
return next;
|
|
376
|
+
}
|
|
377
|
+
function requestMatchesEtag(request, etag) {
|
|
378
|
+
const value = request.headers.get("if-none-match");
|
|
379
|
+
if (!value) return false;
|
|
380
|
+
if (value.trim() === "*") return true;
|
|
381
|
+
return value.split(",").some((candidate) => candidate.trim().replace(/^W\//i, "") === etag);
|
|
382
|
+
}
|
|
383
|
+
async function createHashedDiscoveryResponse(options) {
|
|
384
|
+
const etag = `"${options.sha256 ?? await sha256DocsDiscoveryContent(options.content)}"`;
|
|
385
|
+
const headers = {
|
|
386
|
+
"Access-Control-Allow-Origin": "*",
|
|
387
|
+
"Access-Control-Expose-Headers": "ETag, Link",
|
|
388
|
+
Allow: "GET, HEAD",
|
|
389
|
+
"Cache-Control": DISCOVERY_CACHE_CONTROL,
|
|
390
|
+
"Content-Type": options.contentType,
|
|
391
|
+
ETag: etag,
|
|
392
|
+
Link: options.linkHeader,
|
|
393
|
+
"X-Robots-Tag": "noindex"
|
|
394
|
+
};
|
|
395
|
+
if (requestMatchesEtag(options.request, etag)) {
|
|
396
|
+
const { "Content-Type": _contentType, ...notModifiedHeaders } = headers;
|
|
397
|
+
return new Response(null, {
|
|
398
|
+
status: 304,
|
|
399
|
+
headers: notModifiedHeaders
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
const body = options.request.method.toUpperCase() === "HEAD" ? null : typeof options.content === "string" ? options.content : toDiscoveryBytes(options.content).buffer;
|
|
403
|
+
return new Response(body, { headers });
|
|
404
|
+
}
|
|
405
|
+
function standardsNotFoundResponse(request, linkHeader) {
|
|
406
|
+
return new Response(request.method.toUpperCase() === "HEAD" ? null : "Not Found", {
|
|
407
|
+
status: 404,
|
|
408
|
+
headers: {
|
|
409
|
+
"Access-Control-Allow-Origin": "*",
|
|
410
|
+
"Access-Control-Expose-Headers": "Link",
|
|
411
|
+
"Cache-Control": "no-store",
|
|
412
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
413
|
+
Link: linkHeader,
|
|
414
|
+
"X-Robots-Tag": "noindex"
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
function standardsMethodNotAllowedResponse(linkHeader) {
|
|
419
|
+
return new Response("Method Not Allowed", {
|
|
420
|
+
status: 405,
|
|
421
|
+
headers: {
|
|
422
|
+
"Access-Control-Allow-Origin": "*",
|
|
423
|
+
"Access-Control-Expose-Headers": "Link",
|
|
424
|
+
Allow: "GET, HEAD",
|
|
425
|
+
"Cache-Control": "no-store",
|
|
426
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
427
|
+
Link: linkHeader,
|
|
428
|
+
"X-Robots-Tag": "noindex"
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
/** Return one RFC 9727 or Agent Skills discovery response, or null for unrelated requests. */
|
|
433
|
+
async function createDocsStandardsResponse({ request, apiCatalog, apiCatalogEnabled = true, apiRoute, preferredSkillDocument, fallbackSkillDocument, publishedSkills = [], agentCard }) {
|
|
434
|
+
const resolved = resolveDocsStandardsDiscoveryRequest(new URL(request.url), { apiRoute });
|
|
435
|
+
if (!resolved) return null;
|
|
436
|
+
const linkHeader = getDocsDiscoveryLinkHeader({
|
|
437
|
+
includeApiCatalog: apiCatalogEnabled,
|
|
438
|
+
includeAgentCard: Boolean(agentCard)
|
|
439
|
+
});
|
|
440
|
+
if (resolved.kind === "api-catalog" && (!apiCatalogEnabled || !apiCatalog)) return standardsNotFoundResponse(request, linkHeader);
|
|
441
|
+
const method = request.method.toUpperCase();
|
|
442
|
+
if (method !== "GET" && method !== "HEAD") return standardsMethodNotAllowedResponse(linkHeader);
|
|
443
|
+
if (resolved.kind === "api-catalog") return createHashedDiscoveryResponse({
|
|
444
|
+
request,
|
|
445
|
+
content: `${JSON.stringify(apiCatalog, null, 2)}\n`,
|
|
446
|
+
contentType: `${API_CATALOG_MEDIA_TYPE}; profile="${API_CATALOG_PROFILE_URI}"; charset=utf-8`,
|
|
447
|
+
linkHeader
|
|
448
|
+
});
|
|
449
|
+
const skills = [await resolveDocsPublishedAgentSkill({
|
|
450
|
+
preferredDocument: preferredSkillDocument,
|
|
451
|
+
fallbackDocument: fallbackSkillDocument
|
|
452
|
+
}), ...publishedSkills];
|
|
453
|
+
const skillsByName = /* @__PURE__ */ new Map();
|
|
454
|
+
for (const skill of skills) {
|
|
455
|
+
if (skillsByName.has(skill.name)) throw new Error(`Duplicate published Agent Skill name: ${skill.name}`);
|
|
456
|
+
skillsByName.set(skill.name, skill);
|
|
457
|
+
}
|
|
458
|
+
if (resolved.kind === "agent-skill") {
|
|
459
|
+
const skill = skillsByName.get(resolved.name);
|
|
460
|
+
if (!skill) return standardsNotFoundResponse(request, linkHeader);
|
|
461
|
+
const file = new URL(request.url).pathname.toLowerCase().endsWith(`${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${encodeURIComponent(skill.name)}/skill.md`.toLowerCase()) ? skill.files.find((candidate) => candidate.path === "SKILL.md") : void 0;
|
|
462
|
+
return createHashedDiscoveryResponse({
|
|
463
|
+
request,
|
|
464
|
+
content: file?.content ?? skill.content,
|
|
465
|
+
contentType: file ? "text/markdown; charset=utf-8" : skill.type === "archive" ? "application/gzip" : "text/markdown; charset=utf-8",
|
|
466
|
+
sha256: file?.sha256 ?? skill.sha256,
|
|
467
|
+
linkHeader: [linkHeader, formatLinkTarget(DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "collection", { type: "application/json" })].join(", ")
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (resolved.kind === "agent-skill-archive") {
|
|
471
|
+
const skill = skillsByName.get(resolved.name);
|
|
472
|
+
if (!skill || skill.type !== "archive") return standardsNotFoundResponse(request, linkHeader);
|
|
473
|
+
return createHashedDiscoveryResponse({
|
|
474
|
+
request,
|
|
475
|
+
content: skill.content,
|
|
476
|
+
contentType: "application/gzip",
|
|
477
|
+
sha256: skill.sha256,
|
|
478
|
+
linkHeader: [linkHeader, formatLinkTarget(DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "collection", { type: "application/json" })].join(", ")
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (resolved.kind === "agent-skill-file") {
|
|
482
|
+
const skill = skillsByName.get(resolved.name);
|
|
483
|
+
const normalizedPath = resolved.path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
484
|
+
if (!skill || normalizedPath.split("/").some((segment) => !segment || segment === "." || segment === "..")) return standardsNotFoundResponse(request, linkHeader);
|
|
485
|
+
const file = skill.files.find((candidate) => candidate.path === normalizedPath);
|
|
486
|
+
if (!file) return standardsNotFoundResponse(request, linkHeader);
|
|
487
|
+
return createHashedDiscoveryResponse({
|
|
488
|
+
request,
|
|
489
|
+
content: file.content,
|
|
490
|
+
contentType: `${file.mediaType}${file.mediaType.startsWith("text/") ? "; charset=utf-8" : ""}`,
|
|
491
|
+
sha256: file.sha256,
|
|
492
|
+
linkHeader: [linkHeader, formatLinkTarget(DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "collection", { type: "application/json" })].join(", ")
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (resolved.kind === "agent-card") {
|
|
496
|
+
if (!agentCard) return standardsNotFoundResponse(request, linkHeader);
|
|
497
|
+
return createHashedDiscoveryResponse({
|
|
498
|
+
request,
|
|
499
|
+
content: `${JSON.stringify(buildDocsA2AAgentCard(agentCard, skills), null, 2)}\n`,
|
|
500
|
+
contentType: "application/json; charset=utf-8",
|
|
501
|
+
linkHeader
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
if (resolved.kind === "legacy-skills-index") return createHashedDiscoveryResponse({
|
|
505
|
+
request,
|
|
506
|
+
content: `${JSON.stringify(buildDocsLegacySkillsIndex(skills), null, 2)}\n`,
|
|
507
|
+
contentType: "application/json; charset=utf-8",
|
|
508
|
+
linkHeader
|
|
509
|
+
});
|
|
510
|
+
return createHashedDiscoveryResponse({
|
|
511
|
+
request,
|
|
512
|
+
content: `${JSON.stringify(buildDocsAgentSkillsIndex(skills), null, 2)}\n`,
|
|
513
|
+
contentType: "application/json; charset=utf-8",
|
|
514
|
+
linkHeader: [linkHeader, ...skills.map((skill) => formatLinkTarget(skill.url, "item", { type: skill.type === "archive" ? "application/gzip" : "text/markdown" }))].join(", ")
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
//#endregion
|
|
519
|
+
export { resolveDocsPublishedAgentSkill as A, buildDocsApiCatalog as C, getDocsDiscoveryLinkHeader as D, createDocsStandardsResponse as E, sha256DocsDiscoveryContent as M, isDocsStandardsDiscoveryRequest as O, buildDocsAgentSkillsIndex as S, buildDocsPublishedAgentSkill as T, DEFAULT_LEGACY_SKILLS_INDEX_FORMAT as _, DEFAULT_A2A_AGENT_CARD_ROUTE as a, appendDocsDiscoveryLinkHeader as b, DEFAULT_AGENT_SKILLS_INDEX_ROUTE as c, DEFAULT_AGENT_SKILL_ARCHIVE_FORMAT as d, DEFAULT_AGENT_SKILL_FILE_FORMAT as f, DEFAULT_API_CATALOG_ROUTE as g, DEFAULT_API_CATALOG_FORMAT as h, DEFAULT_A2A_AGENT_CARD_FORMAT as i, resolveDocsStandardsDiscoveryRequest as j, resolveDocsDiscoveryApiRoute as k, DEFAULT_AGENT_SKILLS_ROUTE_PATTERN as l, DEFAULT_AGENT_SKILL_RESOURCE_FORMAT as m, API_CATALOG_MEDIA_TYPE as n, DEFAULT_AGENT_SKILLS_ARCHIVE_ROUTE_PATTERN as o, DEFAULT_AGENT_SKILL_FORMAT as p, API_CATALOG_PROFILE_URI as r, DEFAULT_AGENT_SKILLS_INDEX_FORMAT as s, AGENT_SKILLS_DISCOVERY_SCHEMA_URI as t, DEFAULT_AGENT_SKILLS_ROUTE_PREFIX as u, DEFAULT_LEGACY_SKILLS_INDEX_ROUTE as v, buildDocsLegacySkillsIndex as w, buildDocsA2AAgentCard as x, DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX as y };
|