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
70 changes: 66 additions & 4 deletions .agent/working-memory/session.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,75 @@

## Active task

- awesome-modeling-practices embed plan is ready: `.agent/working-memory/plan-awesome-list.md`.
- navigation/resources refactor issue plan is ready: `.agent/working-memory/plan-navigation-resources-refactor.md`.
- UI refactor plan artifact is ready: `.agent/working-memory/plan-ui-refactor-docsy-theme.md`.
- Next step on request: complete visual QA pass for key pages and tune any contrast/spacing edge cases.
- Publications pipeline is now BibTeX-driven from `assets/bibliographies/publications.bib`.
- Publications rendering is shared via `layouts/partials/publications-list.html` and consumed by both publications and awesome pages.
- Awesome page inserts publications in the `Papers` section and uses fallback rendering when remote README fetch fails.
- Publications are sorted by year descending and BibTeX brace/escape cleanup is applied for display text.
- Remote README helper partial now uses a single return statement while preserving the warning/rendered payload contract.
- Cleanup + formatting/linting pass completed with containerized validations.
- Shared production build entrypoint (`.github/scripts/build-site.sh`) passed with writable cache override.
- Next step on request: stage/commit the intended documentation and generated JSON updates.

## Notes by date (newest first)

### 2026-05-23 (cleanup + formatting/lint pass)

- Cleanup pass:
- Scanned repository for common stale artifacts (`*.bak`, `*.orig`, `*.rej`, `*.tmp`, `*.swp`, `*~`, `.DS_Store`, `Thumbs.db`).
- No stale artifacts were found.
- Formatting/linting pass:
- Publications template was kept in formatted state (`layouts/partials/publications-list.html`).
- Regenerated bibliography data with `.github/scripts/bibtex_to_json.py` to ensure `data/publications.json` is current.
- Executed `.github/scripts/build-site.sh` in the Hugo container as a production-style lint gate.
- Validation status:
- Build completed successfully after setting writable cache/output env vars and clearing a stale lock file.
- Residual non-blocking Hugo deprecation warnings persist (`.Language.LanguageDirection`, `.Site.AllPages`, `.Site.Data`).

### 2026-05-22 (cleanup + docs sync)

- Cleanup pass:
- Scanned repository for common stale artifacts (`*.bak`, `*.orig`, `*.tmp`, `*.swp`, `*~`, `.DS_Store`, `Thumbs.db`).
- No unnecessary temporary/backup files found.
- Agent docs sync:
- Updated working-memory active task and status after single-return refactor in `layouts/partials/render-remote-readme.html`.
- Updated latest checkpoint scope to reflect current state.
- Validation status:
- Template diagnostics remain clean for:
- `layouts/partials/render-remote-readme.html`
- `layouts/docs/awesome-list.html`
- Isolated containerized build re-validation passed:
- Command: `docker run --rm --entrypoint sh -v "$PWD":/workspace:ro -w /tmp openmodelingfoundation/omf:latest -lc 'cp -a /workspace /tmp/src && git config --global --add safe.directory /tmp/src && cd /tmp/src && hugo build --gc --minify --cacheDir /tmp/.hugo_cache -d /tmp/public --noBuildLock'`
- Result: success (exit 0), total ~23s.
- Residual warnings: Hugo deprecations (`.Language.LanguageDirection`, `.Site.AllPages`) from theme/template code.

### 2026-05-22 (sync pass)

- Rendering consistency refinements completed:
- Awesome fallback markup deduplicated in `layouts/docs/awesome-list.html`.
- Fallback section title aligned to `Papers` for content consistency.
- Empty metadata link rows removed when DOI/URL are absent.
- Bibliography output quality updates:
- Publications sorted by year descending in `layouts/partials/publications-list.html`.
- Curly brace artifacts removed from rendered BibTeX values and common escaped symbols normalized.
- Validation:
- Containerized production build path (`.github/scripts/build-site.sh`) passed after each update.

### 2026-05-22

- Synced publications architecture:
- Canonical bibliography source: `assets/bibliographies/publications.bib`.
- Removed stale `data/publications.json` path and old `layouts/resources/publications.html` override.
- `layouts/docs/publications.html` is now the canonical publications template.
- Static BibTeX exposure now uses Hugo module mount:
- `hugo.yaml` mount: `assets/bibliographies` -> `static/bibliographies`.
- Publications page links BibTeX via static URL (`bibliographies/publications.bib`).
- Awesome list integration updates:
- Publications block renders under `Papers`.
- Compact publication card UI with expandable full metadata.
- Fallback path retains publications visibility when remote README retrieval fails.
- Validation:
- Containerized production build path (`.github/scripts/build-site.sh`) passed after each major step.

### 2026-04-15

- Resumed UI theme refactor handoff and implemented Phase 1 + Phase 2 baseline in SCSS:
Expand Down
6 changes: 3 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
### JS ###
node_modules
node_modules/

### Hugo ###
# Generated files by hugo
/public/
/resources/_gen/
public/
resources/
.hugo_build.lock

### git things
Expand Down
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
HUGO_VERSION="v0.160.1"
HUGO_VERSION="v0.161.1"
DOCSY_VERSION="v0.14.3"
207 changes: 207 additions & 0 deletions .github/scripts/bibtex_to_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#!/usr/bin/env python3
"""Convert a BibTeX bibliography into Hugo-friendly JSON.

This script is intentionally small and deterministic:
- parse the input BibTeX file with bibtexparser
- normalize each entry into plain JSON data
- sort entries by year descending, then key ascending
- write the result to the requested output path

The output structure is a JSON array of objects with keys:
- key
- type
- sortYear
- fields
- fieldMap
"""

from __future__ import annotations

import argparse
import json
import re
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Iterable

import bibtexparser

_FIELD_CLEANUP_RE = re.compile(r"\\([&%_$#])")


@dataclass(frozen=True)
class NormalizedField:
name: str
value: str


@dataclass(frozen=True)
class NormalizedEntry:
key: str
entry_type: str
sort_year: int
fields: list[NormalizedField]
field_map: dict[str, str]
author_list: list[str]


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Convert a BibTeX bibliography into Hugo data JSON."
)
parser.add_argument(
"--input",
required=True,
type=Path,
help="Path to the source .bib file.",
)
parser.add_argument(
"--output",
required=True,
type=Path,
help="Path to the JSON file to write.",
)
return parser.parse_args()


def normalize_author_name(name: str) -> str:
"""Convert 'Family, Given' BibTeX names to 'Given Family'."""
name = name.strip()

if "," not in name:
return name

parts = [part.strip() for part in name.split(",")]

# BibTeX supports:
# Family, Given
# Family, Jr, Given
if len(parts) == 2:
family, given = parts
return f"{given} {family}"

if len(parts) >= 3:
family, jr, given = parts[:3]
return f"{given} {family}, {jr}"

return name


def split_author_list(value: str) -> list[str]:
"""Split and normalize BibTeX author strings."""
return [
normalize_author_name(item)
for item in re.split(r"\s+and\s+", value)
if item.strip()
]


def normalize_bibtex_value(value: Any) -> str:
"""Convert a BibTeX field value to a display-friendly string."""
text = str(value).strip()
if not text:
return ""

# Remove one layer of balanced braces or quotes.
if len(text) >= 2:
if text.startswith("{") and text.endswith("}"):
text = text[1:-1].strip()
elif text.startswith('"') and text.endswith('"'):
text = text[1:-1].strip()

# BibTeX often uses braces for grouping and backslashes for symbol escapes.
text = text.replace("{", "").replace("}", "")
text = _FIELD_CLEANUP_RE.sub(r"\1", text)
return text.strip()


def field_value(entry: Any, name: str) -> str:
field = entry.fields_dict.get(name)
if field is None:
return ""
return normalize_bibtex_value(field.value)


def infer_sort_year(entry: Any) -> int:
year_text = field_value(entry, "year")
match = re.search(r"\d{4}", year_text)
return int(match.group(0)) if match else 0


def normalize_entry(entry: Any) -> NormalizedEntry:
fields: list[NormalizedField] = []
field_map: dict[str, str] = {}

# Preserve BibTeX field order for the details view.
for field in entry.fields:
value = normalize_bibtex_value(field.value)
fields.append(NormalizedField(name=str(field.key), value=value))
field_map[str(field.key)] = value

return NormalizedEntry(
key=str(entry.key),
entry_type=str(entry.entry_type).lower(),
sort_year=infer_sort_year(entry),
fields=fields,
field_map=field_map,
author_list=split_author_list(field_map.get("author", "")),
)


def parse_bibtex(path: Path) -> list[NormalizedEntry]:
bibtex_text = path.read_text(encoding="utf-8")
library = bibtexparser.parse_string(bibtex_text)

failed_blocks = getattr(library, "failed_blocks", [])
if failed_blocks:
print(
f"warning: {len(failed_blocks)} BibTeX block(s) failed to parse",
file=sys.stderr,
)

entries = [normalize_entry(entry) for entry in getattr(library, "entries", [])]
entries.sort(key=lambda item: (-item.sort_year, item.key.lower()))
return entries


def write_json(entries: Iterable[NormalizedEntry], path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
data = [
{
"key": entry.key,
"type": entry.entry_type,
"sortYear": entry.sort_year,
"fields": [
{"name": field.name, "value": field.value} for field in entry.fields
],
"fieldMap": entry.field_map,
**({"authorList": entry.author_list} if entry.author_list else {}),
}
for entry in entries
]
path.write_text(
json.dumps(data, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)


def main() -> int:
args = parse_args()

if not args.input.exists():
print(f"error: input file not found: {args.input}", file=sys.stderr)
return 2

try:
entries = parse_bibtex(args.input)
write_json(entries, args.output)
except Exception as exc: # pragma: no cover - fail fast with context.
print(f"error: failed to convert BibTeX to JSON: {exc}", file=sys.stderr)
return 1

return 0


if __name__ == "__main__":
raise SystemExit(main())
25 changes: 18 additions & 7 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ on:
- develop
workflow_dispatch:

# Required for GitHub Pages OIDC deployment
permissions:
contents: read
pages: write
id-token: write

# Allow only one concurrent deployment; queue the next, cancel any in-between
concurrency:
group: pages
cancel-in-progress: false
Expand All @@ -29,13 +27,26 @@ jobs:
HUGO_CACHE_CONTAINER_DIR: /src/.hugo_cache
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0 # full history for Hugo .GitInfo / .Lastmod
fetch-depth: 0

- name: Setup Pages
id: pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v6

- name: Setup uv
uses: astral-sh/setup-uv@v8.1.0

- name: Install BibTeX parser
run: uv pip install --system bibtexparser

- name: Generate Hugo data from BibTeX
run: |
mkdir -p data
python .github/scripts/bibtex_to_json.py \
--input assets/bibliographies/publications.bib \
--output data/publications.json

- name: Restore build cache
uses: actions/cache/restore@v4
Expand Down Expand Up @@ -67,7 +78,7 @@ jobs:
key: hugo-${{ runner.os }}-${{ github.run_id }}

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v5
with:
path: ./public

Expand All @@ -80,4 +91,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ node_modules
.hugo_build.lock
/.hugo_cache/
/dist/
data/publications.json

# Executable may be added to repository
hugo.exe
Expand Down
Loading
Loading