📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -8,6 +8,7 @@ const DIST_DIR = path.join(ROOT_DIR, 'dist');
|
||||
const PUBLIC_DIR = path.join(ROOT_DIR, 'public');
|
||||
const TEMPLATE_PATH = path.join(DIST_DIR, 'index.html');
|
||||
const SKILLS_PATH = path.join(PUBLIC_DIR, 'skills.json');
|
||||
const SEO_LANDING_PAGES_PATH = path.join(ROOT_DIR, 'src', 'data', 'seoLandingPages.json');
|
||||
|
||||
const HOME_CATALOG_COUNT_FALLBACK = 1689;
|
||||
const PRERENDER_SOCIAL_IMAGE = 'social-card.svg';
|
||||
@@ -18,13 +19,18 @@ const FAQ_ITEMS = [
|
||||
{
|
||||
question: 'What is Antigravity Awesome Skills?',
|
||||
answer:
|
||||
'Antigravity Awesome Skills is an installable GitHub library of 1,689+ reusable SKILL.md playbooks for AI coding assistants. It supports Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and related hosts through direct skill installs, specialized plugins, bundles, workflows, and a searchable catalog.',
|
||||
'Antigravity Awesome Skills is an installable GitHub library of 1,700+ reusable SKILL.md playbooks for AI coding assistants. It supports Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and related hosts through direct skill installs, specialized plugins, bundles, workflows, and a searchable catalog.',
|
||||
},
|
||||
{
|
||||
question: 'How do I install Antigravity Awesome Skills?',
|
||||
answer:
|
||||
'Install the library with npx antigravity-awesome-skills. Use tool-specific flags such as --codex, --cursor, --gemini, --claude, or --antigravity when you want the installer to target a specific skills directory already used by your assistant runtime.',
|
||||
},
|
||||
{
|
||||
question: 'Is Antigravity Awesome Skills a GitHub repository?',
|
||||
answer:
|
||||
'Yes. The GitHub repository at https://github.com/sickn33/antigravity-awesome-skills is the canonical source for the skill library, installer, specialized plugins, bundles, workflows, and documentation. The hosted catalog is the searchable browsing surface for that repository.',
|
||||
},
|
||||
{
|
||||
question: 'What are AAS specialized plugins?',
|
||||
answer:
|
||||
@@ -177,11 +183,161 @@ function safeText(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function normalizeMatchText(value) {
|
||||
return safeText(value)
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function getLandingPageMatchTerms(page) {
|
||||
return [
|
||||
page.slug,
|
||||
page.eyebrow,
|
||||
page.h1,
|
||||
page.summary,
|
||||
page.primaryIntent,
|
||||
...(Array.isArray(page.keywords) ? page.keywords : []),
|
||||
...(Array.isArray(page.relatedTerms) ? page.relatedTerms : []),
|
||||
];
|
||||
}
|
||||
|
||||
function scoreLandingPageForSkill(page, skill) {
|
||||
const haystack = normalizeMatchText([
|
||||
skill.id,
|
||||
skill.name,
|
||||
skill.description,
|
||||
skill.category,
|
||||
skill.source,
|
||||
skill.path,
|
||||
].filter(Boolean).join(' '));
|
||||
const category = normalizeMatchText(skill.category);
|
||||
const relatedCategories = Array.isArray(page.relatedCategories)
|
||||
? page.relatedCategories.map(normalizeMatchText)
|
||||
: [];
|
||||
let score = relatedCategories.includes(category) ? 12 : 0;
|
||||
|
||||
for (const term of getLandingPageMatchTerms(page)) {
|
||||
const normalizedTerm = normalizeMatchText(term);
|
||||
|
||||
if (!normalizedTerm || normalizedTerm.length < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (haystack.includes(normalizedTerm)) {
|
||||
score += Math.min(12, 3 + normalizedTerm.split(' ').length * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchedTokens = normalizedTerm
|
||||
.split(' ')
|
||||
.filter((token) => token.length >= 4 && haystack.includes(token));
|
||||
|
||||
score += Math.min(6, matchedTokens.length);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
function getRelatedLandingPagesForSkill(landingPages, skill, limit = 3) {
|
||||
const maxItems = Math.max(0, limit);
|
||||
|
||||
if (maxItems === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const scoredPages = landingPages
|
||||
.map((page, index) => ({
|
||||
page,
|
||||
index,
|
||||
score: scoreLandingPageForSkill(page, skill),
|
||||
}))
|
||||
.sort((a, b) => {
|
||||
if (a.score !== b.score) {
|
||||
return b.score - a.score;
|
||||
}
|
||||
|
||||
return a.index - b.index;
|
||||
});
|
||||
const selected = scoredPages.filter(({ score }) => score > 0).map(({ page }) => page);
|
||||
|
||||
for (const { page } of scoredPages) {
|
||||
if (selected.length >= maxItems) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!selected.includes(page)) {
|
||||
selected.push(page);
|
||||
}
|
||||
}
|
||||
|
||||
return selected.slice(0, maxItems);
|
||||
}
|
||||
|
||||
function buildStaticLinkList(links) {
|
||||
return links
|
||||
.map((link) => `<li><a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a></li>`)
|
||||
.join('');
|
||||
}
|
||||
|
||||
function buildPrerenderFallback({ heading, description, links }) {
|
||||
const items = buildStaticLinkList(links);
|
||||
|
||||
return [
|
||||
'<main data-prerender-fallback="true">',
|
||||
`<h1>${escapeHtml(heading)}</h1>`,
|
||||
`<p>${escapeHtml(description)}</p>`,
|
||||
items ? `<nav aria-label="Related topic guides"><ul>${items}</ul></nav>` : '',
|
||||
'</main>',
|
||||
].join('');
|
||||
}
|
||||
|
||||
function buildTopicFallback({ page, landingPages, siteBaseUrl }) {
|
||||
const relatedLinks = landingPages
|
||||
.filter((landing) => landing.slug && landing.slug !== page.slug)
|
||||
.slice(0, 3)
|
||||
.map((landing) => ({
|
||||
href: routeToUrl(`/topics/${encodeURIComponent(landing.slug)}`, siteBaseUrl),
|
||||
label: landing.h1,
|
||||
}));
|
||||
|
||||
return buildPrerenderFallback({
|
||||
heading: page.h1,
|
||||
description: page.summary,
|
||||
links: relatedLinks,
|
||||
});
|
||||
}
|
||||
|
||||
function buildSkillFallback({ skill, landingPages, siteBaseUrl }) {
|
||||
const relatedLinks = getRelatedLandingPagesForSkill(landingPages, skill).map((page) => ({
|
||||
href: routeToUrl(`/topics/${encodeURIComponent(page.slug)}`, siteBaseUrl),
|
||||
label: page.h1,
|
||||
}));
|
||||
|
||||
return buildPrerenderFallback({
|
||||
heading: `@${safeText(skill.name) || safeText(skill.id) || 'Skill'}`,
|
||||
description: safeText(skill.description) || 'Installable skill from Antigravity Awesome Skills.',
|
||||
links: relatedLinks,
|
||||
});
|
||||
}
|
||||
|
||||
function setRootFallback(html, fallbackHtml) {
|
||||
const rootPattern = /<div\s+id=["']root["']><\/div>/i;
|
||||
|
||||
if (!fallbackHtml || !rootPattern.test(html)) {
|
||||
return html;
|
||||
}
|
||||
|
||||
return html.replace(rootPattern, `<div id="root">${fallbackHtml}</div>`);
|
||||
}
|
||||
|
||||
function buildHomeMeta({ catalogCount, imageUrl, canonicalUrl }) {
|
||||
const visibleCount = Math.max(catalogCount, HOME_CATALOG_COUNT_FALLBACK);
|
||||
const formattedCount = visibleCount.toLocaleString('en-US');
|
||||
const title = `Antigravity Awesome Skills | ${formattedCount}+ AI coding skills and plugins`;
|
||||
const description = `Explore ${formattedCount}+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and other AI coding assistants.`;
|
||||
const title = `Antigravity Awesome Skills GitHub | ${formattedCount}+ AI coding skills`;
|
||||
const description = `Explore the GitHub library of ${formattedCount}+ installable agentic skills, specialized plugins, bundles, and workflows for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and other AI coding assistants.`;
|
||||
const catalogBaseUrl = canonicalUrl.replace(/\/$/, '');
|
||||
const sourceCodeEntity = {
|
||||
'@context': 'https://schema.org',
|
||||
@@ -204,6 +360,9 @@ function buildHomeMeta({ catalogCount, imageUrl, canonicalUrl }) {
|
||||
'Cursor skills',
|
||||
'Gemini CLI skills',
|
||||
'Antigravity skills',
|
||||
'Antigravity CLI skills',
|
||||
'GitHub AI skills repository',
|
||||
'AI agent skills GitHub',
|
||||
'specialized plugins',
|
||||
'SKILL.md',
|
||||
],
|
||||
@@ -376,6 +535,122 @@ function buildPluginsMeta({ pluginCount, imageUrl, canonicalUrl }) {
|
||||
};
|
||||
}
|
||||
|
||||
function buildTopicLandingMeta({ page, imageUrl, canonicalUrl }) {
|
||||
const catalogBaseUrl = canonicalUrl.replace(/\/topics\/[^/]+\/?$/, '');
|
||||
const keywords = Array.isArray(page.keywords) ? page.keywords.join(', ') : '';
|
||||
const sourceCodeEntity = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareSourceCode',
|
||||
name: SITE_NAME,
|
||||
description: 'Installable GitHub library of agentic skills, specialized plugins, bundles, and workflows for AI coding assistants.',
|
||||
url: REPOSITORY_URL,
|
||||
sameAs: [
|
||||
canonicalUrl,
|
||||
HOSTED_CATALOG_URL,
|
||||
'https://www.npmjs.com/package/antigravity-awesome-skills',
|
||||
],
|
||||
mainEntityOfPage: canonicalUrl,
|
||||
codeRepository: REPOSITORY_URL,
|
||||
applicationCategory: 'DeveloperApplication',
|
||||
keywords: [
|
||||
...(Array.isArray(page.keywords) ? page.keywords : []),
|
||||
'specialized plugins',
|
||||
'SKILL.md',
|
||||
],
|
||||
isAccessibleForFree: true,
|
||||
programmingLanguage: {
|
||||
'@type': 'ComputerLanguage',
|
||||
name: 'Markdown',
|
||||
url: 'https://en.wikipedia.org/wiki/Markdown',
|
||||
},
|
||||
license: `${REPOSITORY_URL}/blob/main/LICENSE`,
|
||||
};
|
||||
|
||||
return {
|
||||
title: page.title,
|
||||
description: page.description,
|
||||
canonicalUrl,
|
||||
ogTitle: page.title,
|
||||
ogDescription: page.description,
|
||||
ogImage: imageUrl,
|
||||
twitterCard: 'summary_large_image',
|
||||
jsonLd: [
|
||||
{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebPage',
|
||||
name: page.h1,
|
||||
headline: page.h1,
|
||||
description: page.description,
|
||||
url: canonicalUrl,
|
||||
isPartOf: {
|
||||
'@type': 'WebSite',
|
||||
name: SITE_NAME,
|
||||
url: catalogBaseUrl,
|
||||
sameAs: REPOSITORY_URL,
|
||||
},
|
||||
about: sourceCodeEntity,
|
||||
keywords,
|
||||
mainEntity: {
|
||||
'@type': 'ItemList',
|
||||
name: `${page.eyebrow} topics`,
|
||||
itemListElement: Array.isArray(page.sections)
|
||||
? page.sections.map((section, index) => ({
|
||||
'@type': 'ListItem',
|
||||
position: index + 1,
|
||||
name: section.heading,
|
||||
description: section.body,
|
||||
}))
|
||||
: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BreadcrumbList',
|
||||
itemListElement: [
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 1,
|
||||
name: SITE_NAME,
|
||||
item: HOSTED_CATALOG_URL,
|
||||
},
|
||||
{
|
||||
'@type': 'ListItem',
|
||||
position: 2,
|
||||
name: page.h1,
|
||||
item: canonicalUrl,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Organization',
|
||||
'@id': `${REPOSITORY_URL}#organization`,
|
||||
name: SITE_NAME,
|
||||
url: REPOSITORY_URL,
|
||||
sameAs: [
|
||||
'https://x.com/AASkills_',
|
||||
'https://www.npmjs.com/package/antigravity-awesome-skills',
|
||||
HOSTED_CATALOG_URL,
|
||||
],
|
||||
},
|
||||
{
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
name: SITE_NAME,
|
||||
url: catalogBaseUrl,
|
||||
sameAs: REPOSITORY_URL,
|
||||
inLanguage: 'en',
|
||||
potentialAction: {
|
||||
'@type': 'SearchAction',
|
||||
target: `${catalogBaseUrl}/?q={search_term_string}`,
|
||||
'query-input': 'required name=search_term_string',
|
||||
},
|
||||
},
|
||||
sourceCodeEntity,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function applySeoMeta(templateHtml, meta) {
|
||||
let output = templateHtml;
|
||||
const title = safeText(meta.title);
|
||||
@@ -403,9 +678,9 @@ function applySeoMeta(templateHtml, meta) {
|
||||
return output;
|
||||
}
|
||||
|
||||
function writePrerenderedRoute(routePath, templateHtml, meta) {
|
||||
function writePrerenderedRoute(routePath, templateHtml, meta, fallbackHtml = '') {
|
||||
const filePath = routeToFilePath(routePath);
|
||||
const rendered = applySeoMeta(templateHtml, meta);
|
||||
const rendered = setRootFallback(applySeoMeta(templateHtml, meta), fallbackHtml);
|
||||
const directory = path.dirname(filePath);
|
||||
ensureDirectory(directory);
|
||||
fs.writeFileSync(filePath, rendered, 'utf-8');
|
||||
@@ -426,6 +701,21 @@ function readCatalog() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function readSeoLandingPages() {
|
||||
if (!fs.existsSync(SEO_LANDING_PAGES_PATH)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const raw = fs.readFileSync(SEO_LANDING_PAGES_PATH, 'utf-8');
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error('SEO landing pages data must be an array.');
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function main() {
|
||||
if (!fs.existsSync(TEMPLATE_PATH)) {
|
||||
throw new Error(`Built index file not found at ${TEMPLATE_PATH}. Run npm run build before prerender.`);
|
||||
@@ -433,6 +723,7 @@ function main() {
|
||||
|
||||
const template = fs.readFileSync(TEMPLATE_PATH, 'utf-8');
|
||||
const skills = readCatalog();
|
||||
const landingPages = readSeoLandingPages();
|
||||
const siteBaseUrl = getSiteBaseUrl();
|
||||
const topCount = parseCount(process.env.PRERENDER_TOP_SKILL_COUNT || process.env.TOP_SKILL_COUNT, 40);
|
||||
const topSkillPaths = selectTopSkillEntries(skills, topCount);
|
||||
@@ -456,6 +747,26 @@ function main() {
|
||||
});
|
||||
writePrerenderedRoute('/plugins', template, pluginsMeta);
|
||||
|
||||
for (const page of landingPages) {
|
||||
if (!page?.slug) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const routePath = `/topics/${encodeURIComponent(page.slug)}`;
|
||||
const canonicalUrl = routeToUrl(routePath, siteBaseUrl);
|
||||
const landingMeta = buildTopicLandingMeta({
|
||||
page,
|
||||
imageUrl: socialImage,
|
||||
canonicalUrl,
|
||||
});
|
||||
writePrerenderedRoute(
|
||||
routePath,
|
||||
template,
|
||||
landingMeta,
|
||||
buildTopicFallback({ page, landingPages, siteBaseUrl }),
|
||||
);
|
||||
}
|
||||
|
||||
for (const skillRoute of topSkillPaths) {
|
||||
const decodedId = decodeURIComponent(skillRoute.replace(/^\/skill\//, ''));
|
||||
const skill = skillMap.get(decodedId);
|
||||
@@ -470,7 +781,12 @@ function main() {
|
||||
imageUrl: socialImage,
|
||||
canonicalUrl,
|
||||
});
|
||||
writePrerenderedRoute(skillRoute, template, skillMeta);
|
||||
writePrerenderedRoute(
|
||||
skillRoute,
|
||||
template,
|
||||
skillMeta,
|
||||
buildSkillFallback({ skill, landingPages, siteBaseUrl }),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user