diff --git a/.agent/skills/astro-wiki-deploy/SKILL.md b/.agent/skills/astro-wiki-deploy/SKILL.md new file mode 100644 index 0000000..0c2f78f --- /dev/null +++ b/.agent/skills/astro-wiki-deploy/SKILL.md @@ -0,0 +1,195 @@ +--- +name: astro-wiki-deploy +description: Deploy the Colibri wiki (astro/wiki/) to wiki.clawdie.si via the CMS jail. Plain Astro — no Starlight. Covers content staging, build, deploy, and the 6 pitfalls discovered during the initial deployment (26.jun.2026). +--- + +# Astro Wiki Deploy + +Deploy the plain-Astro Colibri wiki to `https://wiki.clawdie.si`. + +## Architecture + +``` +colibri/ + docs/wiki/ ← canonical content (23 EN + 23 SL .md files) + astro/wiki/ ← Astro build pipeline (minimal, no Starlight) + src/pages/ + index.astro — EN landing (flat list) + [...slug].astro — EN dynamic route (reads src/content/*.md) + sl/index.astro — SL landing + sl/[...slug].astro — SL dynamic route (reads src/content/sl/*.md) +``` + +CMS jail builds the site, host nginx serves it. Same pattern as docs.clawdie.si. + +## Full deploy flow + +```sh +# 1. Stage content into Astro project (source of truth → build input) +cd /home/clawdie/ai/colibri +rm -rf astro/wiki/src/content +cp -r docs/wiki astro/wiki/src/content + +# 2. Copy source into CMS jail +sudo cp -r astro/wiki/src \ + /usr/local/bastille/jails/cms/root/usr/home/clawdie/clawdie-wiki/ + +# 3. Build inside jail (rm -rf dist for clean state — see pitfall #4) +sudo bastille cmd cms sh -c ' + cd /usr/home/clawdie/clawdie-wiki && + rm -rf dist node_modules/.astro && + ASTRO_SITE_URL="https://wiki.clawdie.si" npm run build' + +# 4. Deploy to jail webroot +sudo bastille cmd cms sh -c ' + rm -rf /usr/local/www/wiki.clawdie.si && + mkdir -p /usr/local/www/wiki.clawdie.si && + cp -r /usr/home/clawdie/clawdie-wiki/dist/* /usr/local/www/wiki.clawdie.si/' + +# 5. Cross jail boundary to host webroot (tar is the reliable bridge) +sudo bastille cmd cms sh -c \ + 'tar -czf /tmp/wiki-dist.tar.gz -C /usr/local/www/wiki.clawdie.si .' +sudo cp /usr/local/bastille/jails/cms/root/tmp/wiki-dist.tar.gz /tmp/ +sudo rm -rf /usr/local/www/wiki.clawdie.si +sudo mkdir -p /usr/local/www/wiki.clawdie.si +sudo tar -xzf /tmp/wiki-dist.tar.gz -C /usr/local/www/wiki.clawdie.si/ +sudo chown -R clawdie:clawdie /usr/local/www/wiki.clawdie.si + +# 6. Verify +curl -sk --resolve wiki.clawdie.si:443:127.0.0.1 https://wiki.clawdie.si/ | head -5 +curl -sk --resolve wiki.clawdie.si:443:127.0.0.1 https://wiki.clawdie.si/sl/ | head -5 +``` + +## First-time setup (CMS jail) + +```sh +# Stage the Astro project into the jail once +sudo mkdir -p /usr/local/bastille/jails/cms/root/usr/home/clawdie/clawdie-wiki +sudo cp -r astro/wiki/package.json astro/wiki/astro.config.mjs \ + /usr/local/bastille/jails/cms/root/usr/home/clawdie/clawdie-wiki/ + +# Install dependencies inside jail +sudo bastille cmd cms sh -c 'cd /usr/home/clawdie/clawdie-wiki && npm install' +``` + +## Pitfalls + +### 1. `const` declarations outside function scope fail in Astro SSR + +**Symptom:** `WIKI_DIR is not defined` at build time, but the variable is +clearly declared. + +**Cause:** Astro's frontmatter script compilation scopes top-level `const` +differently in SSR context. Variables declared outside `getStaticPaths()` or +the template function may not be accessible. + +**Fix:** Move all `const` declarations that are needed in `getStaticPaths()` +inside the function body. For variables needed in the template (after +frontmatter), declare them at module level but only those that Astro's +compiler can reach — simple string literals and path.resolve calls work. + +```js +// ❌ BROKEN — WIKI_DIR is undefined in compiled output +const WIKI_DIR = path.resolve("src/content"); +export function getStaticPaths() { ... } + +// ✅ WORKS — declared inside function scope +export function getStaticPaths() { + const WIKI_DIR = path.resolve("src/content"); + ... +} +``` + +### 2. YAML frontmatter with unquoted colons breaks content parsing + +**Symptom:** `bad indentation of a mapping entry` at line N:XX during build. + +**Cause:** Slovenian (and English) titles/descriptions often contain colons +(`:`). YAML interprets unquoted colons as key-value separators. This breaks +Astro's content collection parsing. + +**Fix:** Quote ALL frontmatter values that contain colons, double-quotes, +or special characters: + +```yaml +# ❌ BROKEN +title: Agentska oprema: zot + Colibri + +# ✅ WORKS +title: "Agentska vprega: pi, zot & Colibri" +``` + +Also: descriptions with nested double-quotes need single-quote wrappers: + +```yaml +# ❌ BROKEN — inner quotes terminate the string +description: "Sprememba ni "končana" brez..." + +# ✅ WORKS — single-quote wrapper, inner double-quotes preserved +description: 'Sprememba ni "končana" brez...' +``` + +### 3. SL content auto-generates stale routes + +**Symptom:** `src/pages/sl/index.astro` appears in the build output with +hardcoded paths like `scandir '/usr/docs/wiki'` even after removing +`src/content/sl/`. + +**Cause:** Astro's content collection auto-generation creates `sl/` routes +from `src/content/sl/`. These auto-generated routes use different path +resolution and can persist in the dist cache between builds. + +**Fix:** +1. Create explicit `src/pages/sl/index.astro` and `src/pages/sl/[...slug].astro` + routes that read from `src/content/sl/` directly. +2. Remove any auto-generated `sl/` directory from `src/pages/sl/` if it + appears. +3. ALWAYS `rm -rf dist node_modules/.astro` between builds (see pitfall #4). + +### 4. Stale dist cache preserves old route generation + +**Symptom:** Fixed source code, but the same error persists after rebuild. + +**Cause:** Astro caches compiled routes in `dist/` and `.astro/`. A previous +failed build can leave stale compiled `.mjs` files that shadow the fixed +source. + +**Fix:** Always clean before rebuilding: +```sh +rm -rf dist node_modules/.astro && npm run build +``` + +### 5. `import.meta.url` path resolution fails in Astro SSR + +**Symptom:** Paths resolved via `fileURLToPath(import.meta.url)` point to +compiled `.mjs` files in `dist/`, not the source `.astro` files. + +**Cause:** Astro compiles `.astro` to `.mjs` and runs from `dist/`. The +`import.meta.url` in the compiled module points to the compiled path, not +the project root. + +**Fix:** Use `path.resolve("src/content")` — `process.cwd()` during build +is the project root (`astro/wiki/`), so relative paths work correctly. +Do not use `import.meta.url` for content path resolution. + +### 6. H1 fallback for pages without YAML frontmatter + +**Symptom:** Page `` shows the slug (e.g., "agent-harness") instead +of the actual heading ("Agent harness: pi, zot & Colibri"). + +**Cause:** The title extraction only checks `frontmatter.title`, falling back +to the URL slug. Pages with only a markdown H1 (`# Title`) and no YAML +frontmatter get slug-based titles. + +**Fix:** Add H1 regex extraction as a third fallback: +```js +const title = (frontmatter.title || content.match(/^#\s+(.+)$/m)?.[1] || slug) + .replace(/^["']|["']$/g, ""); +``` + +### 7. Nginx: missing SSL cert blocks startup (see nginx skill) + +Before the first deploy, nginx needs a placeholder cert to start. See the +**nginx** skill §"Adding a new public static HTTPS site — full flow" and +§Troubleshooting "BIO_new_file() failed". The wiki deployment follows the +same pattern: placeholder cert → ACME challenge → real cert.