@andesine/pages 0.0.0-stage → 0.6.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.
- package/CHANGELOG.md +103 -0
- package/LICENSE +21 -0
- package/README.md +92 -2
- package/dist/answers.d.ts +6 -0
- package/dist/astro/content.astro +118 -0
- package/dist/astro/middleware.js +39 -0
- package/dist/astro/middleware.js.map +1 -0
- package/dist/astro/routes/answers.js +129 -0
- package/dist/astro/routes/answers.js.map +1 -0
- package/dist/astro/routes/entry-pages.js +22 -0
- package/dist/astro/routes/entry-pages.js.map +1 -0
- package/dist/astro/routes/llms-full.js +12 -0
- package/dist/astro/routes/llms-full.js.map +1 -0
- package/dist/astro/routes/llms.js +12 -0
- package/dist/astro/routes/llms.js.map +1 -0
- package/dist/astro/routes/markdown-alias.js +14 -0
- package/dist/astro/routes/markdown-alias.js.map +1 -0
- package/dist/astro/routes/markdown.js +12 -0
- package/dist/astro/routes/markdown.js.map +1 -0
- package/dist/astro/routes/not-found.astro +12 -0
- package/dist/astro/routes/robots.js +9 -0
- package/dist/astro/routes/robots.js.map +1 -0
- package/dist/astro/routes/search.js +42 -0
- package/dist/astro/routes/search.js.map +1 -0
- package/dist/astro/routes/sitemap.js +12 -0
- package/dist/astro/routes/sitemap.js.map +1 -0
- package/dist/astro/routes/skill.js +13 -0
- package/dist/astro/routes/skill.js.map +1 -0
- package/dist/astro/routes/skills.js +24 -0
- package/dist/astro/routes/skills.js.map +1 -0
- package/dist/astro/routes/social.js +91 -0
- package/dist/astro/routes/social.js.map +1 -0
- package/dist/astro/routes/static.astro +53 -0
- package/dist/astro/routes/well-known-llms.js +2 -0
- package/dist/astro.d.ts +34 -0
- package/dist/astro.js +60 -0
- package/dist/astro.js.map +1 -0
- package/dist/chunks/assets-D6WJmZ05.js +21 -0
- package/dist/chunks/assets-D6WJmZ05.js.map +1 -0
- package/dist/chunks/catalog-DU4BUrpw.js +28 -0
- package/dist/chunks/catalog-DU4BUrpw.js.map +1 -0
- package/dist/chunks/config-CuH5JSI4.js +184 -0
- package/dist/chunks/config-CuH5JSI4.js.map +1 -0
- package/dist/chunks/files-BxqiQzFj.js +62 -0
- package/dist/chunks/files-BxqiQzFj.js.map +1 -0
- package/dist/chunks/hash-D4piIIQ6.js +11 -0
- package/dist/chunks/hash-D4piIIQ6.js.map +1 -0
- package/dist/chunks/index-D8wL2B5s.d.ts +571 -0
- package/dist/chunks/index-vsu3hISM.d.ts +62 -0
- package/dist/chunks/limits-Ppc7BQPG.js +45 -0
- package/dist/chunks/limits-Ppc7BQPG.js.map +1 -0
- package/dist/chunks/markdown-DKJSQxR2.js +42 -0
- package/dist/chunks/markdown-DKJSQxR2.js.map +1 -0
- package/dist/chunks/mdx-components-CUUDTapN.d.ts +9 -0
- package/dist/chunks/normalize-DG5nxOLm.js +361 -0
- package/dist/chunks/normalize-DG5nxOLm.js.map +1 -0
- package/dist/chunks/paths-75QgA3Qs.js +16 -0
- package/dist/chunks/paths-75QgA3Qs.js.map +1 -0
- package/dist/chunks/prepare-lnuw_ycM.js +219 -0
- package/dist/chunks/prepare-lnuw_ycM.js.map +1 -0
- package/dist/chunks/read-DCv1lmcM.js +57 -0
- package/dist/chunks/read-DCv1lmcM.js.map +1 -0
- package/dist/chunks/request-DOuBHGQs.js +92 -0
- package/dist/chunks/request-DOuBHGQs.js.map +1 -0
- package/dist/chunks/response-CtzaKMWH.js +15 -0
- package/dist/chunks/response-CtzaKMWH.js.map +1 -0
- package/dist/chunks/site-DY-uZ0PP.js +419 -0
- package/dist/chunks/site-DY-uZ0PP.js.map +1 -0
- package/dist/chunks/skill-CBTGUHQH.js +85 -0
- package/dist/chunks/skill-CBTGUHQH.js.map +1 -0
- package/dist/chunks/sources-Cm6NdIen.js +236 -0
- package/dist/chunks/sources-Cm6NdIen.js.map +1 -0
- package/dist/chunks/stored-CabomV-C.js +354 -0
- package/dist/chunks/stored-CabomV-C.js.map +1 -0
- package/dist/chunks/stored-CcEfvCQH.js +475 -0
- package/dist/chunks/stored-CcEfvCQH.js.map +1 -0
- package/dist/chunks/types-DBzuXfSe.d.ts +53 -0
- package/dist/chunks/view-C-9ZM1zK.js +745 -0
- package/dist/chunks/view-C-9ZM1zK.js.map +1 -0
- package/dist/chunks/view-Dlf_VRI7.d.ts +151 -0
- package/dist/client.d.ts +73 -0
- package/dist/client.js +295 -0
- package/dist/client.js.map +1 -0
- package/dist/collections.d.ts +7 -0
- package/dist/collections.js +215 -0
- package/dist/collections.js.map +1 -0
- package/dist/entry-pages.d.ts +10 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.d.ts +16 -0
- package/dist/integration.js +435 -0
- package/dist/integration.js.map +1 -0
- package/dist/llms-full.d.ts +5 -0
- package/dist/llms.d.ts +5 -0
- package/dist/markdown-alias.d.ts +7 -0
- package/dist/markdown.d.ts +7 -0
- package/dist/middleware.d.ts +8 -0
- package/dist/robots.d.ts +5 -0
- package/dist/runtime.d.ts +81 -0
- package/dist/runtime.js +56 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scripts/restore-navigation.js +1 -0
- package/dist/search.d.ts +6 -0
- package/dist/sitemap.d.ts +5 -0
- package/dist/skill.d.ts +5 -0
- package/dist/skills.d.ts +10 -0
- package/dist/social.d.ts +7 -0
- package/dist/well-known-llms.d.ts +2 -0
- package/package.json +103 -3
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import { n as toSegments, t as toHref } from "./paths-75QgA3Qs.js";
|
|
2
|
+
import { a as findTrail, i as createNavigationItems, o as flattenTree, r as createSections, t as loadStaticSources } from "./sources-Cm6NdIen.js";
|
|
3
|
+
import { r as prepareMarkdown } from "./prepare-lnuw_ycM.js";
|
|
4
|
+
import { a as toOpenAPIMarkdown } from "./stored-CcEfvCQH.js";
|
|
5
|
+
import { t as createMarkdownPage } from "./markdown-DKJSQxR2.js";
|
|
6
|
+
import { t as createOperationView } from "./view-C-9ZM1zK.js";
|
|
7
|
+
import { render } from "astro:content";
|
|
8
|
+
//#region src/routing/routes.ts
|
|
9
|
+
/**
|
|
10
|
+
* Creates one route for each page, and a redirect to the first page for each source mount
|
|
11
|
+
* and the site root without a page. Fails when two pages use the same URL.
|
|
12
|
+
*/
|
|
13
|
+
const createRoutes = (base, sections) => {
|
|
14
|
+
const routes = /* @__PURE__ */ new Map();
|
|
15
|
+
const addRedirect = (href, target) => {
|
|
16
|
+
if (target && target !== href && !routes.has(href)) routes.set(href, {
|
|
17
|
+
type: "redirect",
|
|
18
|
+
href,
|
|
19
|
+
target
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
for (const section of sections) for (const page of section.sources.flatMap((source) => source.pages)) {
|
|
23
|
+
const existing = routes.get(page.href);
|
|
24
|
+
if (existing?.type === "page") throw new Error(`Pages "${existing.page.sourceID}/${existing.page.id}" and "${page.sourceID}/${page.id}" both use the URL ${page.href}. Change the file location or slug of one page.`);
|
|
25
|
+
routes.set(page.href, {
|
|
26
|
+
type: "page",
|
|
27
|
+
href: page.href,
|
|
28
|
+
page,
|
|
29
|
+
section
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
for (const source of sections.flatMap((section) => section.sources)) addRedirect(source.href, flattenTree(source.navigation)[0]?.page?.href);
|
|
33
|
+
addRedirect(toHref(toSegments(base, "Site base")), sections[0]?.href);
|
|
34
|
+
return [...routes.values()];
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/context/site.ts
|
|
38
|
+
const defaultAPIURL = "https://api.andesine.app";
|
|
39
|
+
/** Direct API access for a source with a publishable key. */
|
|
40
|
+
const toAPIContext = (config, source) => {
|
|
41
|
+
if (source.type !== "andesine" || !source.publicKey) return void 0;
|
|
42
|
+
return {
|
|
43
|
+
url: (source.apiURL ?? defaultAPIURL).replace(/\/$/, ""),
|
|
44
|
+
key: source.publicKey,
|
|
45
|
+
collection: source.collection,
|
|
46
|
+
pages: `${config.base}_andesine/pages/${source.id}.json`
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
const createSearchSources = (config) => {
|
|
50
|
+
return config.sources.map((source) => {
|
|
51
|
+
return {
|
|
52
|
+
id: source.id,
|
|
53
|
+
label: config.sections.find((section) => section.sources.includes(source.id))?.label ?? config.name,
|
|
54
|
+
type: source.type === "andesine" ? "andesine" : "pagefind",
|
|
55
|
+
api: toAPIContext(config, source)
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const createSiteContext = (config) => {
|
|
60
|
+
const sources = createSearchSources(config);
|
|
61
|
+
const answers = config.sources.find((source) => source.type === "andesine" && source.answers);
|
|
62
|
+
return {
|
|
63
|
+
name: config.name,
|
|
64
|
+
description: config.description,
|
|
65
|
+
language: config.language,
|
|
66
|
+
href: config.base,
|
|
67
|
+
url: new URL(config.base, config.site).href,
|
|
68
|
+
storageKey: `andesine:${config.base}`,
|
|
69
|
+
logo: config.logo,
|
|
70
|
+
favicon: config.favicon,
|
|
71
|
+
sectionsDisplay: config.sectionsDisplay,
|
|
72
|
+
links: config.links,
|
|
73
|
+
cta: config.cta,
|
|
74
|
+
socialLinks: config.socialLinks,
|
|
75
|
+
search: sources.length ? {
|
|
76
|
+
sources,
|
|
77
|
+
endpoint: `${config.base}_andesine/search/`,
|
|
78
|
+
pagefind: `${config.base}pagefind/`,
|
|
79
|
+
answers: answers && {
|
|
80
|
+
endpoint: `${config.base}_andesine/answers/`,
|
|
81
|
+
source: answers.id,
|
|
82
|
+
api: toAPIContext(config, answers)
|
|
83
|
+
}
|
|
84
|
+
} : void 0
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/context/actions.ts
|
|
89
|
+
const services = {
|
|
90
|
+
chatgpt: {
|
|
91
|
+
label: "ChatGPT",
|
|
92
|
+
url: "https://chatgpt.com/?q="
|
|
93
|
+
},
|
|
94
|
+
claude: {
|
|
95
|
+
label: "Claude",
|
|
96
|
+
url: "https://claude.ai/new?q="
|
|
97
|
+
},
|
|
98
|
+
perplexity: {
|
|
99
|
+
label: "Perplexity",
|
|
100
|
+
url: "https://www.perplexity.ai/search?q="
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const createPageActions = (config, markdownURL) => {
|
|
104
|
+
if (!config) return;
|
|
105
|
+
const prompt = encodeURIComponent(`Read ${markdownURL} so I can ask questions about it.`);
|
|
106
|
+
return { openIn: config.openIn.map((id) => {
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
label: services[id].label,
|
|
110
|
+
href: `${services[id].url}${prompt}`
|
|
111
|
+
};
|
|
112
|
+
}) };
|
|
113
|
+
};
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/context/meta.ts
|
|
116
|
+
/** The document title, description, and type of a page. */
|
|
117
|
+
const createPageMeta = (site, page) => {
|
|
118
|
+
return {
|
|
119
|
+
title: page.title === site.name ? site.name : `${page.title} | ${site.name}`,
|
|
120
|
+
description: page.description ?? site.description,
|
|
121
|
+
type: page.href === site.href ? "website" : "article"
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/context/structured-data.ts
|
|
126
|
+
/** Makes JSON safe inside a `<script>` element, where `<\/script>` would end it. */
|
|
127
|
+
const serialize = (value) => JSON.stringify(value).replace(/</g, "\\u003c");
|
|
128
|
+
/**
|
|
129
|
+
* Creates schema.org JSON-LD for a page: the site with its search action, the page as a
|
|
130
|
+
* technical article, and its breadcrumbs.
|
|
131
|
+
*/
|
|
132
|
+
const createStructuredData = (options) => {
|
|
133
|
+
const { site } = options;
|
|
134
|
+
const websiteID = `${site.url}#website`;
|
|
135
|
+
const breadcrumbs = options.trail.filter((item) => item.href);
|
|
136
|
+
return serialize({
|
|
137
|
+
"@context": "https://schema.org",
|
|
138
|
+
"@graph": [
|
|
139
|
+
{
|
|
140
|
+
"@type": "WebSite",
|
|
141
|
+
"@id": websiteID,
|
|
142
|
+
"name": site.name,
|
|
143
|
+
"description": site.description,
|
|
144
|
+
"url": site.url,
|
|
145
|
+
"inLanguage": site.language,
|
|
146
|
+
"potentialAction": site.search && {
|
|
147
|
+
"@type": "SearchAction",
|
|
148
|
+
"target": {
|
|
149
|
+
"@type": "EntryPoint",
|
|
150
|
+
"urlTemplate": `${site.url}?q={search_term_string}`
|
|
151
|
+
},
|
|
152
|
+
"query-input": "required name=search_term_string"
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"@type": "TechArticle",
|
|
157
|
+
"headline": options.title,
|
|
158
|
+
"description": options.description,
|
|
159
|
+
"url": options.url,
|
|
160
|
+
"dateModified": options.updatedAt,
|
|
161
|
+
"image": options.image,
|
|
162
|
+
"inLanguage": site.language,
|
|
163
|
+
"isPartOf": { "@id": websiteID }
|
|
164
|
+
},
|
|
165
|
+
...breadcrumbs.length > 1 ? [{
|
|
166
|
+
"@type": "BreadcrumbList",
|
|
167
|
+
"itemListElement": breadcrumbs.map((item, index) => {
|
|
168
|
+
return {
|
|
169
|
+
"@type": "ListItem",
|
|
170
|
+
"position": index + 1,
|
|
171
|
+
"name": item.label,
|
|
172
|
+
"item": new URL(item.href, site.url).href
|
|
173
|
+
};
|
|
174
|
+
})
|
|
175
|
+
}] : []
|
|
176
|
+
]
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/context/page.ts
|
|
181
|
+
const toPageLink = (node) => {
|
|
182
|
+
return node?.page && {
|
|
183
|
+
label: node.label,
|
|
184
|
+
href: node.page.href
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
const toSectionContexts = (sections, current) => {
|
|
188
|
+
return sections.map((item) => {
|
|
189
|
+
return {
|
|
190
|
+
id: item.id,
|
|
191
|
+
label: item.label,
|
|
192
|
+
icon: item.icon,
|
|
193
|
+
href: item.href,
|
|
194
|
+
current: item === current
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
/** Creates the page context without headings, which exist only after rendering. */
|
|
199
|
+
const createPageContext = (options) => {
|
|
200
|
+
const { page, section } = options.route;
|
|
201
|
+
const trail = findTrail(section.navigation, page);
|
|
202
|
+
const order = flattenTree(section.navigation);
|
|
203
|
+
const position = order.findIndex((node) => node.page === page);
|
|
204
|
+
const markdown = `${page.href}index.md`;
|
|
205
|
+
const canonical = new URL(page.href, options.site.url).href;
|
|
206
|
+
const breadcrumbs = trail.slice(0, -1).map((node) => {
|
|
207
|
+
return {
|
|
208
|
+
label: node.label,
|
|
209
|
+
href: node.page?.href
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
const sectionItem = options.sections.length ? [{
|
|
213
|
+
label: section.label,
|
|
214
|
+
href: section.href
|
|
215
|
+
}] : [];
|
|
216
|
+
return {
|
|
217
|
+
site: options.site,
|
|
218
|
+
title: page.title,
|
|
219
|
+
description: page.description,
|
|
220
|
+
meta: createPageMeta(options.site, page),
|
|
221
|
+
fragments: {
|
|
222
|
+
summary: page.content.type === "andesine" && Boolean(page.content.summary),
|
|
223
|
+
aside: page.content.type === "andesine" && Boolean(page.content.aside)
|
|
224
|
+
},
|
|
225
|
+
layout: page.layout,
|
|
226
|
+
sections: toSectionContexts(options.sections, section),
|
|
227
|
+
links: [...options.site.links, ...section.links],
|
|
228
|
+
navigation: createNavigationItems(section.navigation, trail),
|
|
229
|
+
breadcrumbs,
|
|
230
|
+
previous: position > 0 ? toPageLink(order[position - 1]) : void 0,
|
|
231
|
+
next: position >= 0 ? toPageLink(order[position + 1]) : void 0,
|
|
232
|
+
canonical,
|
|
233
|
+
markdown,
|
|
234
|
+
updatedAt: page.updatedAt,
|
|
235
|
+
noindex: page.searchHidden,
|
|
236
|
+
image: options.image,
|
|
237
|
+
structuredData: createStructuredData({
|
|
238
|
+
site: options.site,
|
|
239
|
+
title: page.title,
|
|
240
|
+
description: page.description,
|
|
241
|
+
url: canonical,
|
|
242
|
+
updatedAt: page.updatedAt,
|
|
243
|
+
image: options.image?.url,
|
|
244
|
+
trail: [
|
|
245
|
+
...sectionItem,
|
|
246
|
+
...breadcrumbs,
|
|
247
|
+
{
|
|
248
|
+
label: page.title,
|
|
249
|
+
href: page.href
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}),
|
|
253
|
+
actions: createPageActions(options.pageActions, new URL(markdown, options.site.url).href)
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/social/size.ts
|
|
258
|
+
/** The size of generated social images, as Open Graph recommends. */
|
|
259
|
+
const socialImageSize = {
|
|
260
|
+
width: 1200,
|
|
261
|
+
height: 630
|
|
262
|
+
};
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/context/image.ts
|
|
265
|
+
/** The link preview image of a page: its generated card, or the configured default image. */
|
|
266
|
+
const getSocialImage = (config, href) => {
|
|
267
|
+
const site = new URL(config.base, config.site);
|
|
268
|
+
if (href && config.social.generate) return {
|
|
269
|
+
url: new URL(`${href}social.png`, site).href,
|
|
270
|
+
...socialImageSize
|
|
271
|
+
};
|
|
272
|
+
return config.social.image ? { url: new URL(config.social.image, site).href } : void 0;
|
|
273
|
+
};
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/site/index.ts
|
|
276
|
+
/** Decodes a base-prefixed URL path into the `[...path]` parameter. */
|
|
277
|
+
const toParam = (href, base) => {
|
|
278
|
+
return decodeURIComponent(href.slice(base.length)).replace(/\/$/, "") || void 0;
|
|
279
|
+
};
|
|
280
|
+
/** Creates the routes of loaded sources, with the page context of each page. */
|
|
281
|
+
const createSiteRoutes = (config, sources) => {
|
|
282
|
+
const sections = createSections(config, sources);
|
|
283
|
+
const site = createSiteContext(config);
|
|
284
|
+
const shownSections = config.sections.length ? sections : [];
|
|
285
|
+
return createRoutes(config.base, sections).map((route) => {
|
|
286
|
+
return {
|
|
287
|
+
href: route.href,
|
|
288
|
+
route: route.type === "redirect" ? route : {
|
|
289
|
+
type: "page",
|
|
290
|
+
content: route.page.content,
|
|
291
|
+
toc: route.page.toc,
|
|
292
|
+
sourceID: route.page.sourceID,
|
|
293
|
+
indexed: route.page.content.type !== "andesine" && !route.page.searchHidden,
|
|
294
|
+
markdown: createMarkdownPage(config, route.page),
|
|
295
|
+
context: createPageContext({
|
|
296
|
+
site,
|
|
297
|
+
sections: shownSections,
|
|
298
|
+
route,
|
|
299
|
+
pageActions: config.pageActions,
|
|
300
|
+
image: getSocialImage(config, route.href)
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
const getStaticPaths = async (config) => {
|
|
307
|
+
return createSiteRoutes(config, await loadStaticSources(config)).map(({ href, route }) => {
|
|
308
|
+
return {
|
|
309
|
+
params: { path: toParam(href, config.base) },
|
|
310
|
+
props: { route }
|
|
311
|
+
};
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
const getMarkdownPaths = async (config) => {
|
|
315
|
+
return createSiteRoutes(config, await loadStaticSources(config)).flatMap(({ href, route }) => {
|
|
316
|
+
return route.type === "page" ? [{
|
|
317
|
+
params: { path: toParam(href, config.base) },
|
|
318
|
+
props: { markdown: route.markdown }
|
|
319
|
+
}] : [];
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
const toSocialData = (context) => {
|
|
323
|
+
return {
|
|
324
|
+
siteName: context.site.name,
|
|
325
|
+
title: context.title,
|
|
326
|
+
description: context.description,
|
|
327
|
+
group: context.breadcrumbs.at(-1)?.label
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
const getSocialPaths = async (config) => {
|
|
331
|
+
return createSiteRoutes(config, await loadStaticSources(config)).flatMap(({ href, route }) => {
|
|
332
|
+
return route.type === "page" ? [{
|
|
333
|
+
params: { path: toParam(href, config.base) },
|
|
334
|
+
props: { data: toSocialData(route.context) }
|
|
335
|
+
}] : [];
|
|
336
|
+
});
|
|
337
|
+
};
|
|
338
|
+
/** The context of the not-found page, with the navigation of the first section. */
|
|
339
|
+
const getNotFoundContext = async (config) => {
|
|
340
|
+
const sections = createSections(config, await loadStaticSources(config));
|
|
341
|
+
const site = createSiteContext(config);
|
|
342
|
+
const title = "Page not found";
|
|
343
|
+
return {
|
|
344
|
+
site,
|
|
345
|
+
title,
|
|
346
|
+
meta: createPageMeta(site, { title }),
|
|
347
|
+
fragments: {
|
|
348
|
+
summary: false,
|
|
349
|
+
aside: false
|
|
350
|
+
},
|
|
351
|
+
layout: "docs",
|
|
352
|
+
sections: config.sections.length ? toSectionContexts(sections) : [],
|
|
353
|
+
links: [...site.links, ...sections[0]?.links ?? []],
|
|
354
|
+
navigation: createNavigationItems(sections[0]?.navigation ?? [], []),
|
|
355
|
+
breadcrumbs: [],
|
|
356
|
+
headings: [],
|
|
357
|
+
noindex: true,
|
|
358
|
+
image: getSocialImage(config)
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
const toOutline = (headings, toc) => {
|
|
362
|
+
return toc ? headings.filter((heading) => heading.depth >= 2 && heading.depth <= 3) : [];
|
|
363
|
+
};
|
|
364
|
+
const renderRoute = async (route, highlight) => {
|
|
365
|
+
if (route.content.type === "openapi" && route.content.operation) {
|
|
366
|
+
const { operation, model, links } = route.content;
|
|
367
|
+
return {
|
|
368
|
+
operation: await createOperationView(operation, model, {
|
|
369
|
+
highlight,
|
|
370
|
+
title: route.context.title,
|
|
371
|
+
href: links.operations[operation.id]
|
|
372
|
+
}),
|
|
373
|
+
page: {
|
|
374
|
+
...route.context,
|
|
375
|
+
headings: []
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
if (route.content.type === "openapi") {
|
|
380
|
+
const prepared = await prepareMarkdown(toOpenAPIMarkdown(route.content, (href) => href), highlight);
|
|
381
|
+
return {
|
|
382
|
+
nodes: prepared.nodes,
|
|
383
|
+
iconCSS: prepared.iconCSS,
|
|
384
|
+
page: {
|
|
385
|
+
...route.context,
|
|
386
|
+
headings: toOutline(prepared.headings, route.toc)
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
if (route.content.type === "andesine") return {
|
|
391
|
+
nodes: route.content.nodes,
|
|
392
|
+
summary: route.content.summary,
|
|
393
|
+
aside: route.content.aside,
|
|
394
|
+
iconCSS: route.content.iconCSS,
|
|
395
|
+
page: {
|
|
396
|
+
...route.context,
|
|
397
|
+
headings: toOutline(route.content.headings, route.toc)
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
const { Content, headings } = await render(route.content.entry);
|
|
401
|
+
const outline = headings.map((heading) => {
|
|
402
|
+
return {
|
|
403
|
+
id: heading.slug,
|
|
404
|
+
text: heading.text,
|
|
405
|
+
depth: heading.depth
|
|
406
|
+
};
|
|
407
|
+
});
|
|
408
|
+
return {
|
|
409
|
+
Content,
|
|
410
|
+
page: {
|
|
411
|
+
...route.context,
|
|
412
|
+
headings: toOutline(outline, route.toc)
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
//#endregion
|
|
417
|
+
export { renderRoute as a, getStaticPaths as i, getNotFoundContext as n, socialImageSize as o, getSocialPaths as r, getMarkdownPaths as t };
|
|
418
|
+
|
|
419
|
+
//# sourceMappingURL=site-DY-uZ0PP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-DY-uZ0PP.js","names":[],"sources":["../../src/routing/routes.ts","../../src/context/site.ts","../../src/context/actions.ts","../../src/context/meta.ts","../../src/context/structured-data.ts","../../src/context/page.ts","../../src/social/size.ts","../../src/context/image.ts","../../src/site/index.ts"],"sourcesContent":["import type { Section } from \"../navigation\";\nimport { flattenTree } from \"../navigation\";\nimport type { SourcePage } from \"../sources\";\nimport { toHref, toSegments } from \"./paths\";\n\ninterface PageRoute {\n type: \"page\";\n href: string;\n page: SourcePage;\n section: Section;\n}\n\ninterface RedirectRoute {\n type: \"redirect\";\n href: string;\n target: string;\n}\n\ntype Route = PageRoute | RedirectRoute;\n\n/**\n * Creates one route for each page, and a redirect to the first page for each source mount\n * and the site root without a page. Fails when two pages use the same URL.\n */\nconst createRoutes = (base: string, sections: Section[]): Route[] => {\n const routes = new Map<string, Route>();\n const addRedirect = (href: string, target?: string): void => {\n const isFree = target && target !== href && !routes.has(href);\n\n if (isFree) routes.set(href, { type: \"redirect\", href, target });\n };\n\n for (const section of sections) {\n for (const page of section.sources.flatMap((source) => source.pages)) {\n const existing = routes.get(page.href);\n\n if (existing?.type === \"page\") {\n throw new Error(\n `Pages \"${existing.page.sourceID}/${existing.page.id}\" and \"${page.sourceID}/${page.id}\" both use the URL ${page.href}. Change the file location or slug of one page.`\n );\n }\n\n routes.set(page.href, { type: \"page\", href: page.href, page, section });\n }\n }\n\n for (const source of sections.flatMap((section) => section.sources)) {\n addRedirect(source.href, flattenTree(source.navigation)[0]?.page?.href);\n }\n\n addRedirect(toHref(toSegments(base, \"Site base\")), sections[0]?.href);\n\n return [...routes.values()];\n};\n\nexport { createRoutes };\nexport type { PageRoute, RedirectRoute, Route };\n","import type { PagesConfig, SourceConfig } from \"../config\";\nimport type { AndesineAPIContext, SearchSourceContext, SiteContext } from \"./types\";\n\nconst defaultAPIURL = \"https://api.andesine.app\";\n\n/** Direct API access for a source with a publishable key. */\nconst toAPIContext = (\n config: PagesConfig,\n source: SourceConfig\n): AndesineAPIContext | undefined => {\n if (source.type !== \"andesine\" || !source.publicKey) return undefined;\n\n return {\n url: (source.apiURL ?? defaultAPIURL).replace(/\\/$/, \"\"),\n key: source.publicKey,\n collection: source.collection,\n pages: `${config.base}_andesine/pages/${source.id}.json`\n };\n};\nconst createSearchSources = (config: PagesConfig): SearchSourceContext[] => {\n return config.sources.map((source) => {\n return {\n id: source.id,\n label:\n config.sections.find((section) => section.sources.includes(source.id))?.label ??\n config.name,\n type: source.type === \"andesine\" ? \"andesine\" : \"pagefind\",\n api: toAPIContext(config, source)\n };\n });\n};\nconst createSiteContext = (config: PagesConfig): SiteContext => {\n const sources = createSearchSources(config);\n // The API answers about one collection, so the first source with answers is used.\n const answers = config.sources.find((source) => source.type === \"andesine\" && source.answers);\n\n return {\n name: config.name,\n description: config.description,\n language: config.language,\n href: config.base,\n url: new URL(config.base, config.site).href,\n storageKey: `andesine:${config.base}`,\n logo: config.logo,\n favicon: config.favicon,\n sectionsDisplay: config.sectionsDisplay,\n links: config.links,\n cta: config.cta,\n socialLinks: config.socialLinks,\n search: sources.length\n ? {\n sources,\n endpoint: `${config.base}_andesine/search/`,\n pagefind: `${config.base}pagefind/`,\n answers: answers && {\n endpoint: `${config.base}_andesine/answers/`,\n source: answers.id,\n api: toAPIContext(config, answers)\n }\n }\n : undefined\n };\n};\n\nexport { createSiteContext };\n","import type { AIService, PagesConfig } from \"../config\";\nimport type { PageActionsContext } from \"./types\";\n\nconst services: Record<AIService, { label: string; url: string }> = {\n chatgpt: { label: \"ChatGPT\", url: \"https://chatgpt.com/?q=\" },\n claude: { label: \"Claude\", url: \"https://claude.ai/new?q=\" },\n perplexity: { label: \"Perplexity\", url: \"https://www.perplexity.ai/search?q=\" }\n};\n\nconst createPageActions = (\n config: PagesConfig[\"pageActions\"],\n markdownURL: string\n): PageActionsContext | undefined => {\n if (!config) return;\n\n const prompt = encodeURIComponent(`Read ${markdownURL} so I can ask questions about it.`);\n\n return {\n openIn: config.openIn.map((id) => {\n return {\n id,\n label: services[id].label,\n href: `${services[id].url}${prompt}`\n };\n })\n };\n};\n\nexport { createPageActions };\n","import type { PageMeta, SiteContext } from \"./types\";\n\n/** The document title, description, and type of a page. */\nconst createPageMeta = (\n site: SiteContext,\n page: { title: string; description?: string; href?: string }\n): PageMeta => {\n return {\n title: page.title === site.name ? site.name : `${page.title} | ${site.name}`,\n description: page.description ?? site.description,\n type: page.href === site.href ? \"website\" : \"article\"\n };\n};\n\nexport { createPageMeta };\n","import type { BreadcrumbItem, SiteContext } from \"./types\";\n\ninterface StructuredDataOptions {\n site: SiteContext;\n title: string;\n description?: string;\n /** Absolute URL of the page. */\n url: string;\n updatedAt?: string;\n image?: string;\n /** The section, groups, and page, from the top. Items without a URL are left out. */\n trail: BreadcrumbItem[];\n}\n\n/** Makes JSON safe inside a `<script>` element, where `</script>` would end it. */\nconst serialize = (value: unknown): string => JSON.stringify(value).replace(/</g, \"\\\\u003c\");\n/**\n * Creates schema.org JSON-LD for a page: the site with its search action, the page as a\n * technical article, and its breadcrumbs.\n */\nconst createStructuredData = (options: StructuredDataOptions): string => {\n const { site } = options;\n const websiteID = `${site.url}#website`;\n const breadcrumbs = options.trail.filter((item) => item.href);\n\n return serialize({\n \"@context\": \"https://schema.org\",\n \"@graph\": [\n {\n \"@type\": \"WebSite\",\n \"@id\": websiteID,\n \"name\": site.name,\n \"description\": site.description,\n \"url\": site.url,\n \"inLanguage\": site.language,\n \"potentialAction\": site.search && {\n \"@type\": \"SearchAction\",\n \"target\": { \"@type\": \"EntryPoint\", \"urlTemplate\": `${site.url}?q={search_term_string}` },\n \"query-input\": \"required name=search_term_string\"\n }\n },\n {\n \"@type\": \"TechArticle\",\n \"headline\": options.title,\n \"description\": options.description,\n \"url\": options.url,\n \"dateModified\": options.updatedAt,\n \"image\": options.image,\n \"inLanguage\": site.language,\n \"isPartOf\": { \"@id\": websiteID }\n },\n ...(breadcrumbs.length > 1\n ? [\n {\n \"@type\": \"BreadcrumbList\",\n \"itemListElement\": breadcrumbs.map((item, index) => {\n return {\n \"@type\": \"ListItem\",\n \"position\": index + 1,\n \"name\": item.label,\n \"item\": new URL(item.href!, site.url).href\n };\n })\n }\n ]\n : [])\n ]\n });\n};\n\nexport { createStructuredData };\n","import type { PagesConfig } from \"../config\";\nimport { createNavigationItems, findTrail, flattenTree, type Section } from \"../navigation\";\nimport type { PageRoute } from \"../routing\";\nimport type { SourceNode } from \"../sources\";\nimport { createPageActions } from \"./actions\";\nimport { createPageMeta } from \"./meta\";\nimport { createStructuredData } from \"./structured-data\";\nimport type { PageContext, PageLink, SectionContext, SiteContext, SocialImage } from \"./types\";\n\ninterface PageContextOptions {\n site: SiteContext;\n /** Configured sections; empty when the site uses the implicit section. */\n sections: Section[];\n route: PageRoute;\n pageActions: PagesConfig[\"pageActions\"];\n image?: SocialImage;\n}\n\nconst toPageLink = (node?: SourceNode): PageLink | undefined => {\n return node?.page && { label: node.label, href: node.page.href };\n};\nconst toSectionContexts = (sections: Section[], current?: Section): SectionContext[] => {\n return sections.map((item) => {\n return {\n id: item.id,\n label: item.label,\n icon: item.icon,\n href: item.href,\n current: item === current\n };\n });\n};\n\n/** Creates the page context without headings, which exist only after rendering. */\nconst createPageContext = (options: PageContextOptions): Omit<PageContext, \"headings\"> => {\n const { page, section } = options.route;\n const trail = findTrail(section.navigation, page);\n const order = flattenTree(section.navigation);\n const position = order.findIndex((node) => node.page === page);\n const markdown = `${page.href}index.md`;\n const canonical = new URL(page.href, options.site.url).href;\n const breadcrumbs = trail.slice(0, -1).map((node) => {\n return {\n label: node.label,\n href: node.page?.href\n };\n });\n const sectionItem = options.sections.length ? [{ label: section.label, href: section.href }] : [];\n\n return {\n site: options.site,\n title: page.title,\n description: page.description,\n meta: createPageMeta(options.site, page),\n fragments: {\n summary: page.content.type === \"andesine\" && Boolean(page.content.summary),\n aside: page.content.type === \"andesine\" && Boolean(page.content.aside)\n },\n layout: page.layout,\n sections: toSectionContexts(options.sections, section),\n links: [...options.site.links, ...section.links],\n navigation: createNavigationItems(section.navigation, trail),\n breadcrumbs,\n previous: position > 0 ? toPageLink(order[position - 1]) : undefined,\n next: position >= 0 ? toPageLink(order[position + 1]) : undefined,\n canonical,\n markdown,\n updatedAt: page.updatedAt,\n noindex: page.searchHidden,\n image: options.image,\n structuredData: createStructuredData({\n site: options.site,\n title: page.title,\n description: page.description,\n url: canonical,\n updatedAt: page.updatedAt,\n image: options.image?.url,\n trail: [...sectionItem, ...breadcrumbs, { label: page.title, href: page.href }]\n }),\n actions: createPageActions(options.pageActions, new URL(markdown, options.site.url).href)\n };\n};\n\nexport { createPageContext, toSectionContexts };\n","/** The size of generated social images, as Open Graph recommends. */\nconst socialImageSize = { width: 1200, height: 630 };\n\nexport { socialImageSize };\n","import type { PagesConfig } from \"../config\";\nimport { socialImageSize } from \"../social/size\";\nimport type { SocialImage } from \"./types\";\n\n/** The link preview image of a page: its generated card, or the configured default image. */\nconst getSocialImage = (config: PagesConfig, href?: string): SocialImage | undefined => {\n const site = new URL(config.base, config.site);\n\n if (href && config.social.generate) {\n return { url: new URL(`${href}social.png`, site).href, ...socialImageSize };\n }\n\n return config.social.image ? { url: new URL(config.social.image, site).href } : undefined;\n};\n\nexport { getSocialImage };\n","import type { MarkdownHeading } from \"astro\";\nimport { render } from \"astro:content\";\nimport type { Root } from \"hast\";\nimport type { PagesConfig } from \"../config\";\nimport {\n createPageContext,\n createPageMeta,\n createSiteContext,\n toSectionContexts,\n type HeadingContext,\n type PageContext\n} from \"../context\";\nimport { createNavigationItems, createSections } from \"../navigation\";\nimport { getSocialImage } from \"../context/image\";\nimport type { SocialCardData } from \"../social/types\";\nimport { createMarkdownPage } from \"../output/markdown\";\nimport { createRoutes, type RedirectRoute, type Route } from \"../routing\";\nimport { prepareMarkdown, type HighlightOptions } from \"../content/prepare\";\nimport { loadStaticSources, type SourceData, type SourcePage } from \"../sources\";\nimport { toOpenAPIMarkdown } from \"../sources/openapi/markdown\";\nimport { createOperationView, type OperationView } from \"../sources/openapi/view\";\n\ninterface PageRouteData {\n type: \"page\";\n content: SourcePage[\"content\"];\n toc: boolean;\n sourceID: string;\n /** The page is in the Pagefind index. */\n indexed: boolean;\n /** The Markdown alternative, with the title and description. */\n markdown: string;\n context: Omit<PageContext, \"headings\">;\n}\n\ninterface SiteRoute {\n href: string;\n route: PageRouteData | RedirectRoute;\n}\n\ninterface StaticPath {\n params: { path?: string };\n props: { route: PageRouteData | RedirectRoute };\n}\n\ninterface MarkdownPath {\n params: { path?: string };\n props: { markdown: string };\n}\n\ninterface SocialPath {\n params: { path?: string };\n props: { data: SocialData };\n}\n\ninterface RenderedRoute {\n /** Astro content of a file page. */\n Content?: unknown;\n /** The operation of an OpenAPI operation page. */\n operation?: OperationView;\n /** HTML syntax tree of an Andesine page, or of an OpenAPI overview or tag page. */\n nodes?: Root;\n summary?: Root;\n aside?: Root;\n /** CSS for icons in the Andesine content. */\n iconCSS?: string;\n page: PageContext;\n}\n\n/** Card data without the configured images and brand, which the route adds. */\ntype SocialData = Omit<\n SocialCardData,\n \"logo\" | \"showSiteName\" | \"logoFormat\" | \"background\" | \"brand\"\n>;\n\n/** Decodes a base-prefixed URL path into the `[...path]` parameter. */\nconst toParam = (href: string, base: string): string | undefined => {\n return decodeURIComponent(href.slice(base.length)).replace(/\\/$/, \"\") || undefined;\n};\n\n/** Creates the routes of loaded sources, with the page context of each page. */\nconst createSiteRoutes = (config: PagesConfig, sources: SourceData[]): SiteRoute[] => {\n const sections = createSections(config, sources);\n const site = createSiteContext(config);\n const shownSections = config.sections.length ? sections : [];\n\n return createRoutes(config.base, sections).map((route: Route) => {\n return {\n href: route.href,\n route:\n route.type === \"redirect\"\n ? route\n : {\n type: \"page\",\n content: route.page.content,\n toc: route.page.toc,\n sourceID: route.page.sourceID,\n indexed: route.page.content.type !== \"andesine\" && !route.page.searchHidden,\n markdown: createMarkdownPage(config, route.page),\n context: createPageContext({\n site,\n sections: shownSections,\n route,\n pageActions: config.pageActions,\n image: getSocialImage(config, route.href)\n })\n }\n };\n });\n};\nconst getStaticPaths = async (config: PagesConfig): Promise<StaticPath[]> => {\n const routes = createSiteRoutes(config, await loadStaticSources(config));\n\n return routes.map(({ href, route }) => {\n return {\n params: { path: toParam(href, config.base) },\n props: { route }\n };\n });\n};\nconst getMarkdownPaths = async (config: PagesConfig): Promise<MarkdownPath[]> => {\n const routes = createSiteRoutes(config, await loadStaticSources(config));\n\n return routes.flatMap(({ href, route }) => {\n return route.type === \"page\"\n ? [{ params: { path: toParam(href, config.base) }, props: { markdown: route.markdown } }]\n : [];\n });\n};\nconst toSocialData = (context: PageRouteData[\"context\"]): SocialData => {\n return {\n siteName: context.site.name,\n title: context.title,\n description: context.description,\n group: context.breadcrumbs.at(-1)?.label\n };\n};\nconst getSocialPaths = async (config: PagesConfig): Promise<SocialPath[]> => {\n const routes = createSiteRoutes(config, await loadStaticSources(config));\n\n return routes.flatMap(({ href, route }) => {\n return route.type === \"page\"\n ? [\n {\n params: { path: toParam(href, config.base) },\n props: { data: toSocialData(route.context) }\n }\n ]\n : [];\n });\n};\n/** The context of the not-found page, with the navigation of the first section. */\nconst getNotFoundContext = async (config: PagesConfig): Promise<PageContext> => {\n const sections = createSections(config, await loadStaticSources(config));\n\n const site = createSiteContext(config);\n const title = \"Page not found\";\n\n return {\n site,\n title,\n meta: createPageMeta(site, { title }),\n fragments: { summary: false, aside: false },\n layout: \"docs\",\n sections: config.sections.length ? toSectionContexts(sections) : [],\n links: [...site.links, ...(sections[0]?.links ?? [])],\n navigation: createNavigationItems(sections[0]?.navigation ?? [], []),\n breadcrumbs: [],\n headings: [],\n noindex: true,\n image: getSocialImage(config)\n };\n};\nconst toOutline = (headings: HeadingContext[], toc: boolean): HeadingContext[] => {\n return toc ? headings.filter((heading) => heading.depth >= 2 && heading.depth <= 3) : [];\n};\nconst renderRoute = async (\n route: PageRouteData,\n highlight: HighlightOptions\n): Promise<RenderedRoute> => {\n if (route.content.type === \"openapi\" && route.content.operation) {\n const { operation, model, links } = route.content;\n\n return {\n operation: await createOperationView(operation, model, {\n highlight,\n title: route.context.title,\n href: links.operations[operation.id]!\n }),\n page: { ...route.context, headings: [] }\n };\n }\n\n // Overview and tag pages show their Markdown.\n if (route.content.type === \"openapi\") {\n const prepared = await prepareMarkdown(\n toOpenAPIMarkdown(route.content, (href) => href),\n highlight\n );\n\n return {\n nodes: prepared.nodes,\n iconCSS: prepared.iconCSS,\n page: { ...route.context, headings: toOutline(prepared.headings, route.toc) }\n };\n }\n\n if (route.content.type === \"andesine\") {\n return {\n nodes: route.content.nodes,\n summary: route.content.summary,\n aside: route.content.aside,\n iconCSS: route.content.iconCSS,\n page: { ...route.context, headings: toOutline(route.content.headings, route.toc) }\n };\n }\n\n const { Content, headings } = (await render(route.content.entry)) as {\n Content: unknown;\n headings: MarkdownHeading[];\n };\n const outline = headings.map((heading) => {\n return {\n id: heading.slug,\n text: heading.text,\n depth: heading.depth\n };\n });\n\n return { Content, page: { ...route.context, headings: toOutline(outline, route.toc) } };\n};\n\nexport {\n createSiteRoutes,\n getStaticPaths,\n getMarkdownPaths,\n getSocialPaths,\n getNotFoundContext,\n renderRoute\n};\nexport type { SiteRoute, StaticPath, MarkdownPath, SocialPath, RenderedRoute };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { t as toSHA256 } from "./hash-D4piIIQ6.js";
|
|
2
|
+
import { i as toLine } from "./markdown-DKJSQxR2.js";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
//#region src/output/skill.ts
|
|
5
|
+
/** A skill name: lowercase letters, digits, and single hyphens, up to 64 characters. */
|
|
6
|
+
const toSkillName = (value) => {
|
|
7
|
+
return value.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z\d]+/g, "-").slice(0, 64).replace(/^-+|-+$/g, "") || "docs";
|
|
8
|
+
};
|
|
9
|
+
/** Reads the name and description of your own skill file, after the agentskills.io format. */
|
|
10
|
+
const readSkill = (content) => {
|
|
11
|
+
const frontmatter = /^(?:\uFEFF)?---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(content)?.[1] ?? "";
|
|
12
|
+
const metadata = parse(frontmatter);
|
|
13
|
+
const { name, description } = typeof metadata === "object" && metadata !== null ? metadata : {};
|
|
14
|
+
if (!(typeof name === "string" && name === toSkillName(name) && typeof description === "string" && !!description.trim())) throw new Error("The skill file needs frontmatter with a `name` (lowercase letters, digits, and hyphens) and a `description`.");
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
description,
|
|
18
|
+
content
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Creates a skill after the agentskills.io format: what the site covers, when to use it, and
|
|
23
|
+
* how to read the documentation.
|
|
24
|
+
*/
|
|
25
|
+
const createSkill = (config, catalog) => {
|
|
26
|
+
const url = (path) => new URL(`${config.base}${path}`, config.site).href;
|
|
27
|
+
const sections = catalog.sections.filter((section) => section.topics.length);
|
|
28
|
+
const topics = sections.flatMap((section) => section.topics.map((topic) => topic.label));
|
|
29
|
+
const description = `${config.description ? `${toLine(config.description)} ` : ""}Use when you work with ${toLine(config.name)} or need its documentation${topics.length ? `, for example: ${topics.join(", ")}` : ""}.`.slice(0, 1024);
|
|
30
|
+
const name = toSkillName(config.name);
|
|
31
|
+
const topicList = sections.map((section) => {
|
|
32
|
+
const links = section.topics.map((topic) => {
|
|
33
|
+
const summary = topic.page.description ? `: ${toLine(topic.page.description)}` : "";
|
|
34
|
+
return `- [${toLine(topic.label)}](${new URL(`${topic.page.href}index.md`, config.site).href})${summary}`;
|
|
35
|
+
});
|
|
36
|
+
return `### ${toLine(section.label)}\n\n${links.join("\n")}`;
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
name,
|
|
40
|
+
description,
|
|
41
|
+
content: `${[
|
|
42
|
+
`---\nname: ${name}\ndescription: ${JSON.stringify(description)}\n---`,
|
|
43
|
+
`# ${toLine(config.name)}`,
|
|
44
|
+
...config.description ? [toLine(config.description)] : [],
|
|
45
|
+
[
|
|
46
|
+
"## Read the documentation",
|
|
47
|
+
"",
|
|
48
|
+
`- Find pages in the index: ${url("llms.txt")}`,
|
|
49
|
+
`- Read all pages in one file: ${url("llms-full.txt")}`,
|
|
50
|
+
"- Read one page as Markdown: add `index.md` to its URL, or replace the last `/` with `.md`."
|
|
51
|
+
].join("\n"),
|
|
52
|
+
...topicList.length ? [`## Topics\n\n${topicList.join("\n\n")}`] : [],
|
|
53
|
+
...config.agents.instructions ? [`## Instructions\n\n${config.agents.instructions}`] : []
|
|
54
|
+
].join("\n\n")}\n`
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/** The skill of the site: your own file, or a generated one. */
|
|
58
|
+
const loadSkill = async (config, custom, loadCatalog) => {
|
|
59
|
+
return custom ? readSkill(custom) : createSkill(config, await loadCatalog());
|
|
60
|
+
};
|
|
61
|
+
/** The discovery index after the agentskills.io discovery schema 0.2.0. */
|
|
62
|
+
const createAgentSkillsIndex = async (config, skill) => {
|
|
63
|
+
return JSON.stringify({
|
|
64
|
+
$schema: "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
|
|
65
|
+
skills: [{
|
|
66
|
+
name: skill.name,
|
|
67
|
+
type: "skill-md",
|
|
68
|
+
description: skill.description,
|
|
69
|
+
url: `${config.base}.well-known/agent-skills/${skill.name}/SKILL.md`,
|
|
70
|
+
digest: `sha256:${await toSHA256(skill.content)}`
|
|
71
|
+
}]
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
/** The index that the `skills` CLI reads. */
|
|
75
|
+
const createSkillsIndex = (skill) => {
|
|
76
|
+
return JSON.stringify({ skills: [{
|
|
77
|
+
name: skill.name,
|
|
78
|
+
description: skill.description,
|
|
79
|
+
files: ["SKILL.md"]
|
|
80
|
+
}] });
|
|
81
|
+
};
|
|
82
|
+
//#endregion
|
|
83
|
+
export { toSkillName as a, readSkill as i, createSkillsIndex as n, loadSkill as r, createAgentSkillsIndex as t };
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=skill-CBTGUHQH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-CBTGUHQH.js","names":[],"sources":["../../src/output/skill.ts"],"sourcesContent":["import { parse } from \"yaml\";\nimport type { PagesConfig } from \"../config\";\nimport { toSHA256 } from \"../hash\";\nimport type { Catalog } from \"./catalog\";\nimport { toLine } from \"./markdown\";\n\ninterface Skill {\n name: string;\n description: string;\n content: string;\n}\n\n/** A skill name: lowercase letters, digits, and single hyphens, up to 64 characters. */\nconst toSkillName = (value: string): string => {\n return (\n value\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z\\d]+/g, \"-\")\n .slice(0, 64)\n .replace(/^-+|-+$/g, \"\") || \"docs\"\n );\n};\n/** Reads the name and description of your own skill file, after the agentskills.io format. */\nconst readSkill = (content: string): Skill => {\n const frontmatter = /^(?:\\uFEFF)?---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/.exec(content)?.[1] ?? \"\";\n const metadata: unknown = parse(frontmatter);\n const fields =\n typeof metadata === \"object\" && metadata !== null ? (metadata as Record<string, unknown>) : {};\n const { name, description } = fields;\n const isValid =\n typeof name === \"string\" &&\n name === toSkillName(name) &&\n typeof description === \"string\" &&\n !!description.trim();\n\n if (!isValid) {\n throw new Error(\n \"The skill file needs frontmatter with a `name` (lowercase letters, digits, and hyphens) and a `description`.\"\n );\n }\n\n return { name, description, content };\n};\n/**\n * Creates a skill after the agentskills.io format: what the site covers, when to use it, and\n * how to read the documentation.\n */\nconst createSkill = (config: PagesConfig, catalog: Catalog): Skill => {\n const url = (path: string): string => new URL(`${config.base}${path}`, config.site).href;\n const sections = catalog.sections.filter((section) => section.topics.length);\n const topics = sections.flatMap((section) => section.topics.map((topic) => topic.label));\n const summary = config.description ? `${toLine(config.description)} ` : \"\";\n const description =\n `${summary}Use when you work with ${toLine(config.name)} or need its documentation${\n topics.length ? `, for example: ${topics.join(\", \")}` : \"\"\n }.`.slice(0, 1024);\n const name = toSkillName(config.name);\n const topicList = sections.map((section) => {\n const links = section.topics.map((topic) => {\n const summary = topic.page.description ? `: ${toLine(topic.page.description)}` : \"\";\n\n return `- [${toLine(topic.label)}](${new URL(`${topic.page.href}index.md`, config.site).href})${summary}`;\n });\n\n return `### ${toLine(section.label)}\\n\\n${links.join(\"\\n\")}`;\n });\n const content = [\n `---\\nname: ${name}\\ndescription: ${JSON.stringify(description)}\\n---`,\n `# ${toLine(config.name)}`,\n ...(config.description ? [toLine(config.description)] : []),\n [\n \"## Read the documentation\",\n \"\",\n `- Find pages in the index: ${url(\"llms.txt\")}`,\n `- Read all pages in one file: ${url(\"llms-full.txt\")}`,\n \"- Read one page as Markdown: add `index.md` to its URL, or replace the last `/` with `.md`.\"\n ].join(\"\\n\"),\n ...(topicList.length ? [`## Topics\\n\\n${topicList.join(\"\\n\\n\")}`] : []),\n ...(config.agents.instructions ? [`## Instructions\\n\\n${config.agents.instructions}`] : [])\n ].join(\"\\n\\n\");\n\n return { name, description, content: `${content}\\n` };\n};\n/** The skill of the site: your own file, or a generated one. */\nconst loadSkill = async (\n config: PagesConfig,\n custom: string | undefined,\n loadCatalog: () => Promise<Catalog>\n): Promise<Skill> => {\n return custom ? readSkill(custom) : createSkill(config, await loadCatalog());\n};\n/** The discovery index after the agentskills.io discovery schema 0.2.0. */\nconst createAgentSkillsIndex = async (config: PagesConfig, skill: Skill): Promise<string> => {\n return JSON.stringify({\n $schema: \"https://schemas.agentskills.io/discovery/0.2.0/schema.json\",\n skills: [\n {\n name: skill.name,\n type: \"skill-md\",\n description: skill.description,\n url: `${config.base}.well-known/agent-skills/${skill.name}/SKILL.md`,\n digest: `sha256:${await toSHA256(skill.content)}`\n }\n ]\n });\n};\n/** The index that the `skills` CLI reads. */\nconst createSkillsIndex = (skill: Skill): string => {\n return JSON.stringify({\n skills: [{ name: skill.name, description: skill.description, files: [\"SKILL.md\"] }]\n });\n};\n\nexport {\n toSkillName,\n readSkill,\n createSkill,\n loadSkill,\n createAgentSkillsIndex,\n createSkillsIndex\n};\nexport type { Skill };\n"],"mappings":"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"}
|