diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
new file mode 100644
index 0000000..dc89f8e
--- /dev/null
+++ b/.gitea/workflows/ci.yml
@@ -0,0 +1,35 @@
+name: CI
+
+on:
+ push:
+ branches: ["**"]
+ pull_request:
+ branches: ["master"]
+
+jobs:
+ build-and-anchors:
+ runs-on: ubuntu-latest
+ container:
+ image: node:20-bookworm-slim
+
+ steps:
+ - name: Install git (needed by checkout)
+ run: |
+ apt-get update
+ apt-get install -y --no-install-recommends git ca-certificates
+ git --version
+
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install deps
+ run: npm ci
+
+ - name: Inline scripts syntax check
+ run: node scripts/check-inline-js.mjs
+
+ - name: Build
+ run: npm run build
+
+ - name: Anchors contract
+ run: npm run test:anchors
diff --git a/package.json b/package.json
index 887c576..0f990e5 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"postbuild": "npx pagefind --site dist",
"import": "node scripts/import-docx.mjs",
"apply:ticket": "node scripts/apply-ticket.mjs",
+ "test": "npm run build && npm run test:anchors && node scripts/check-inline-js.mjs",
"test:anchors": "node scripts/check-anchors.mjs",
"test:anchors:update": "node scripts/check-anchors.mjs --update"
},
diff --git a/scripts/check-inline-js.mjs b/scripts/check-inline-js.mjs
new file mode 100644
index 0000000..a160801
--- /dev/null
+++ b/scripts/check-inline-js.mjs
@@ -0,0 +1,70 @@
+#!/usr/bin/env node
+import fs from "node:fs/promises";
+import path from "node:path";
+import os from "node:os";
+import { spawnSync } from "node:child_process";
+
+const ROOT = process.cwd();
+const SRC = path.join(ROOT, "src");
+
+async function* walk(dir) {
+ const entries = await fs.readdir(dir, { withFileTypes: true });
+ for (const e of entries) {
+ const full = path.join(dir, e.name);
+ if (e.isDirectory()) yield* walk(full);
+ else yield full;
+ }
+}
+
+function extractInlineScripts(astroText) {
+ // capture
+ const re = /