diff --git a/src/lib/skills.ts b/src/lib/skills.ts index 9ad69d9..f933a36 100644 --- a/src/lib/skills.ts +++ b/src/lib/skills.ts @@ -69,15 +69,11 @@ export async function getSkillGitInfo(skill: Skill): Promise { try { const { stdout } = await execFileAsync('git', ['log', '-1', '--format=%H|%aI', '--', abs]); const [sha, date] = stdout.trim().split('|'); - if (sha && date) return { sha, updatedAt: date }; + if (sha && date) return { sha, updatedAt: new Date(date).toISOString() }; } catch { /* fall through */ } return { sha: 'main', updatedAt: new Date().toISOString() }; } -/** @deprecated Use getSkillGitInfo instead. */ -export async function getSkillUpdatedAt(skill: Skill): Promise { - return (await getSkillGitInfo(skill)).updatedAt; -} /** * Returns the raw SKILL.md source (frontmatter + body). Used by the raw @@ -109,14 +105,6 @@ export function githubCommitUrl(slug: string, sha: string): string { return `https://github.com/dfinity/icskills/blob/${sha}/skills/${slug}/SKILL.md`; } -/** - * Returns the full SHA of the last git commit that touched a skill's SKILL.md. - * Falls back to 'main' if git is unavailable or the file has no history. - */ -export async function getSkillCommitHash(skill: Skill): Promise { - return (await getSkillGitInfo(skill)).sha; -} - /** * List all files in a skill's directory, with SKILL.md first. * Used by the .well-known/skills/index.json endpoint. diff --git a/src/pages/api/skills.json.ts b/src/pages/api/skills.json.ts index 9f4c8e2..4940813 100644 --- a/src/pages/api/skills.json.ts +++ b/src/pages/api/skills.json.ts @@ -2,27 +2,30 @@ // and from llms.txt. A single fetch tells a scraper everything on the site. import type { APIRoute } from 'astro'; -import { getAllSkills, getSkillUpdatedAt, githubUrl, skillUrl } from '../../lib/skills'; +import { getAllSkills, getSkillGitInfo, githubCommitUrl, skillUrl } from '../../lib/skills'; import { SITE, absUrl } from '../../lib/site'; export const GET: APIRoute = async () => { const skills = await getAllSkills(); const items = await Promise.all( - skills.map(async (skill) => ({ - name: skill.data.name, - title: skill.data.metadata.title, - category: skill.data.metadata.category, - description: skill.data.description, - license: skill.data.license ?? SITE.license.spdx, - compatibility: skill.data.compatibility ?? null, - updated: await getSkillUpdatedAt(skill), - urls: { - html: absUrl(skillUrl(skill.id)), - markdown: absUrl(`/.well-known/skills/${skill.id}/SKILL.md`), - json: absUrl(`/api/skills/${skill.id}.json`), - source: githubUrl(skill.id), - }, - })), + skills.map(async (skill) => { + const { sha, updatedAt } = await getSkillGitInfo(skill); + return { + name: skill.data.name, + title: skill.data.metadata.title, + category: skill.data.metadata.category, + description: skill.data.description, + license: skill.data.license ?? SITE.license.spdx, + compatibility: skill.data.compatibility ?? null, + updated: updatedAt, + urls: { + html: absUrl(skillUrl(skill.id)), + markdown: absUrl(`/.well-known/skills/${skill.id}/SKILL.md`), + json: absUrl(`/api/skills/${skill.id}.json`), + source: githubCommitUrl(skill.id, sha), + }, + }; + }), ); const payload = { diff --git a/src/pages/feed.xml.ts b/src/pages/feed.xml.ts index 0df781a..9dc54e1 100644 --- a/src/pages/feed.xml.ts +++ b/src/pages/feed.xml.ts @@ -3,13 +3,13 @@ import type { APIRoute } from 'astro'; import rss from '@astrojs/rss'; -import { getAllSkills, getSkillUpdatedAt, skillUrl } from '../lib/skills'; +import { getAllSkills, getSkillGitInfo, skillUrl } from '../lib/skills'; import { SITE, absUrl } from '../lib/site'; export const GET: APIRoute = async (context) => { const all = await getAllSkills(); const withDates = await Promise.all( - all.map(async (s) => ({ skill: s, updated: await getSkillUpdatedAt(s) })), + all.map(async (s) => { const { updatedAt } = await getSkillGitInfo(s); return { skill: s, updated: updatedAt }; }), ); withDates.sort((a, b) => b.updated.localeCompare(a.updated)); diff --git a/src/pages/llms-full.txt.ts b/src/pages/llms-full.txt.ts index 727f32a..fccd5fc 100644 --- a/src/pages/llms-full.txt.ts +++ b/src/pages/llms-full.txt.ts @@ -2,7 +2,7 @@ // provenance headers. One fetch gives a training scraper the entire corpus. import type { APIRoute } from 'astro'; -import { getAllSkills, getSkillRawMarkdown, getSkillUpdatedAt, githubUrl } from '../lib/skills'; +import { getAllSkills, getSkillGitInfo, getSkillRawMarkdown, githubCommitUrl } from '../lib/skills'; import { SITE, absUrl } from '../lib/site'; export const GET: APIRoute = async () => { @@ -25,7 +25,7 @@ export const GET: APIRoute = async () => { parts.push(''); for (const skill of all) { - const updated = await getSkillUpdatedAt(skill); + const { sha, updatedAt: updated } = await getSkillGitInfo(skill); const raw = await getSkillRawMarkdown(skill); parts.push('---'); parts.push(''); @@ -34,7 +34,7 @@ export const GET: APIRoute = async () => { parts.push( ``, ); parts.push(''); diff --git a/src/pages/skills/[slug]/SKILL.md.ts b/src/pages/skills/[slug]/SKILL.md.ts index 8e34d88..4523e77 100644 --- a/src/pages/skills/[slug]/SKILL.md.ts +++ b/src/pages/skills/[slug]/SKILL.md.ts @@ -4,7 +4,7 @@ // comment so the origin stays visible even if the file is copy-pasted. import type { APIRoute } from 'astro'; -import { getAllSkills, getSkillRawMarkdown, getSkillUpdatedAt, githubUrl } from '../../../lib/skills'; +import { getAllSkills, getSkillGitInfo, getSkillRawMarkdown, githubCommitUrl } from '../../../lib/skills'; import { SITE, absUrl } from '../../../lib/site'; export async function getStaticPaths() { @@ -19,15 +19,16 @@ export const GET: APIRoute = async ({ props }) => { if (!skill) return new Response('Not found', { status: 404 }); const body = await getSkillRawMarkdown(skill); - const updatedAt = await getSkillUpdatedAt(skill); + const { sha, updatedAt } = await getSkillGitInfo(skill); + const sourceUrl = githubCommitUrl(slug, sha); const attribution = - `\n`; return new Response(attribution + body, { headers: { 'Content-Type': 'text/markdown; charset=utf-8', - 'X-Content-Source': githubUrl(slug), + 'X-Content-Source': sourceUrl, 'X-License': SITE.license.spdx, }, });