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
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
cache-dependency-path: package-lock.json
- run: npm ci
- run: npm run check:content
- run: npm run check:catalog
- run: npm run build
- run: npm run check:site
- uses: actions/upload-pages-artifact@v5
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,13 @@ Node.js 22.12+ is required.
```bash
npm ci
npm run check:content
npm run check:catalog
npm run build
npm run check:site
npm run check:external
```

`npm run check` runs deterministic content/topology checks, the production build, and built-site metadata/internal-link/asset-budget checks. `check:external` is the separate network-dependent external-link pass.
`npm run check` runs the deterministic content/topology checks, production build, and built-site metadata/internal-link/asset-budget checks. `check:catalog` verifies the public catalog marker against the current catalog source commit and generation date; it requires network access. `check:external` performs the remaining network-dependent external-link pass separately.

The GitHub Pages workflow builds only this repository and publishes `dist/`. Pull requests run deterministic checks; deployment occurs only from `main` or an explicit workflow dispatch. Domain Workbenches and other repositories are never bundled into the site artifact.

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"scripts": {
"dev": "astro dev",
"build": "astro build",
"check:catalog": "node scripts/check-library-catalog.mjs",
"preview": "astro preview",
"astro": "astro",
"check:content": "node scripts/check-content.mjs",
Expand Down
7 changes: 7 additions & 0 deletions public/library-catalog-status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"catalog_url": "https://raw.githubusercontent.com/SagaSmithAI/SagaSmith-dnd-content-library/main/content-library/index.json",
"generated_on": "2026-09-09",
"source_commit": "fe7b14643136f42c6a9f61f2618f3c3b2cd9632c",
"surface": "metadata_only",
"published_at": "2026-09-10"
}
60 changes: 60 additions & 0 deletions scripts/check-library-catalog.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';

const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const statusPath = resolve(root, 'src/data/library-catalog-status.json');
const status = JSON.parse(await readFile(statusPath, 'utf8'));
const publicStatus = JSON.parse(
await readFile(resolve(root, 'public/library-catalog-status.json'), 'utf8'),
);
for (const field of ['catalog_url', 'generated_on', 'source_commit', 'surface', 'published_at']) {
if (status[field] !== publicStatus[field]) {
throw new Error(`catalog marker mismatch between src/data and public: ${field}`);
}
}

const catalogResponse = await fetch(status.catalog_url, {
headers: { 'user-agent': 'SagaSmithAI-site-catalog-check/1' },
});
if (!catalogResponse.ok) {
throw new Error(`catalog index request failed: ${catalogResponse.status}`);
}
const catalog = await catalogResponse.json();

const commitsResponse = await fetch(
'https://api.github.com/repos/SagaSmithAI/SagaSmith-dnd-content-library/commits?path=content-library/index.json&per_page=1',
{
headers: {
accept: 'application/vnd.github+json',
'user-agent': 'SagaSmithAI-site-catalog-check/1',
},
},
);
if (!commitsResponse.ok) {
throw new Error(`catalog source lookup failed: ${commitsResponse.status}`);
}
const commits = await commitsResponse.json();
const sourceCommit = commits?.[0]?.sha;
if (typeof sourceCommit !== 'string' || sourceCommit.length !== 40) {
throw new Error('catalog source lookup returned no commit');
}

if (status.generated_on !== catalog.generated_on) {
throw new Error(
`catalog date mismatch: marker=${status.generated_on}, index=${catalog.generated_on}`,
);
}
if (status.source_commit !== sourceCommit) {
throw new Error(
`catalog source mismatch: marker=${status.source_commit}, main=${sourceCommit}`,
);
}

console.log(
JSON.stringify({
fresh: true,
generated_on: status.generated_on,
source_commit: sourceCommit,
}),
);
7 changes: 7 additions & 0 deletions src/data/library-catalog-status.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"catalog_url": "https://raw.githubusercontent.com/SagaSmithAI/SagaSmith-dnd-content-library/main/content-library/index.json",
"generated_on": "2026-09-09",
"source_commit": "fe7b14643136f42c6a9f61f2618f3c3b2cd9632c",
"surface": "metadata_only",
"published_at": "2026-09-10"
}
10 changes: 6 additions & 4 deletions src/pages/library.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import SiteLayout from '../layouts/SiteLayout.astro';
import catalogStatus from '../data/library-catalog-status.json';
---
<SiteLayout
title="内容库与权利边界"
Expand All @@ -14,9 +15,9 @@ import SiteLayout from '../layouts/SiteLayout.astro';
<h1><span class="zh">可校验,不等于可随意分发。</span><span class="en">Verifiable does not mean freely distributable.</span></h1>
<p class="lede"><span class="zh">当前目录用不可变 identity、版本、大小与 SHA-256 描述 Content Pack。仓库可见性只让索引可以被审计;每个 Pack、来源文档与嵌入资产仍保留各自许可、署名和分发限制。</span><span class="en">The current catalog describes Content Packs with immutable identities, versions, sizes, and SHA-256 checksums. Repository visibility makes the index auditable; every Pack, source document, and embedded asset retains its own license, attribution, and distribution restrictions.</span></p>
</div>
<aside class="page-hero-aside" data-reveal>
<strong>CURRENT FORMAT</strong>
<p><code>sagasmith.content-package</code> v2<br /><code>.sagasmith-pack</code><br /><span class="zh">目录快照生成于 2026-08-16</span><span class="en">Catalog snapshot generated 2026-08-16</span></p>
<aside class="page-hero-aside catalog-current" data-reveal>
<strong>CURRENT CATALOG</strong>
<p><span class="zh">目录快照生成于 {catalogStatus.generated_on}</span><span class="en">Catalog snapshot generated {catalogStatus.generated_on}</span><br /><code>{catalogStatus.source_commit.slice(0, 12)}</code><br /><a href={catalogStatus.catalog_url} target="_blank" rel="noreferrer">Machine-readable index ↗</a></p>
</aside>
</header>

Expand All @@ -35,9 +36,10 @@ import SiteLayout from '../layouts/SiteLayout.astro';
<div class="stat"><strong>2</strong><span>D&amp;D ACTOR PRESETS</span></div>
</div>
<div class="button-row">
<a class="button primary" href="https://github.com/SagaSmithAI/SagaSmith-dnd-content-library/blob/main/content-library/index.json" target="_blank" rel="noreferrer"><span class="zh">查看机器索引</span><span class="en">Open machine index</span> ↗</a>
<a class="button primary" href={catalogStatus.catalog_url} target="_blank" rel="noreferrer"><span class="zh">查看机器索引</span><span class="en">Open machine index</span> ↗</a>
<a class="button" href="https://github.com/SagaSmithAI/SagaSmith-dnd-content-library" target="_blank" rel="noreferrer"><span class="zh">查看目录仓库</span><span class="en">Open catalog repository</span> ↗</a>
</div>
<p class="catalog-freshness"><span class="zh">页面仅展示元数据,不托管 Pack 归档;发布时间与源提交由构建时 freshness 检查核对。</span><span class="en">This page exposes metadata only and does not mirror Pack archives; the published date and source commit are checked during the site build.</span></p>
</section>

<section class="section shell">
Expand Down