Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions src/lib/skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,11 @@ export async function getSkillGitInfo(skill: Skill): Promise<SkillGitInfo> {
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<string> {
return (await getSkillGitInfo(skill)).updatedAt;
}

/**
* Returns the raw SKILL.md source (frontmatter + body). Used by the raw
Expand Down Expand Up @@ -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<string> {
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.
Expand Down
35 changes: 19 additions & 16 deletions src/pages/api/skills.json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
4 changes: 2 additions & 2 deletions src/pages/feed.xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
6 changes: 3 additions & 3 deletions src/pages/llms-full.txt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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('');
Expand All @@ -34,7 +34,7 @@ export const GET: APIRoute = async () => {
parts.push(
`<!-- skill: ${skill.data.name} | category: ${skill.data.metadata.category} | ` +
`html: ${absUrl(`/skills/${skill.id}/`)} | markdown: ${absUrl(`/.well-known/skills/${skill.data.name}/SKILL.md`)} | ` +
`json: ${absUrl(`/api/skills/${skill.id}.json`)} | source: ${githubUrl(skill.id)} | ` +
`json: ${absUrl(`/api/skills/${skill.id}.json`)} | source: ${githubCommitUrl(skill.id, sha)} | ` +
`updated: ${updated} | license: ${SITE.license.spdx} -->`,
);
parts.push('');
Expand Down
9 changes: 5 additions & 4 deletions src/pages/skills/[slug]/SKILL.md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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 =
`<!-- source: ${absUrl(`/skills/${slug}/`)} | origin: ${githubUrl(slug)} | ` +
`<!-- source: ${absUrl(`/skills/${slug}/`)} | origin: ${sourceUrl} | ` +
`publisher: ${SITE.author.name} | license: ${SITE.license.spdx} | updated: ${updatedAt} -->\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,
},
});
Expand Down
Loading