Replace Quarto site with static HTML generator

- Add site/generate.py: static site with search, filtering, sorting, dark mode
- Add site/static/style.css and main.js for the new frontend
- Extend parse.py: fetch CRAN published dates, PyPI release dates, and
  discover GitHub repos from CRAN pages as fallback data sources
- Migrate from Poetry to uv (pyproject.toml + uv.lock)
- Update CI workflow to use uv and generate.py pipeline
- Add CONTRIBUTING.md with entry format guidelines
- Add "Submit a Project" button to site nav
- Update review-pr skill with all accepted entry formats
- Update CLAUDE.md to reflect new architecture
- Remove Quarto files (_quarto.yml, *.qmd, sync-site skill, poetry.lock)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Wilson Freitas
2026-03-22 18:13:55 -03:00
co-authored by Claude Opus 4.6
parent 157e6cbd79
commit 5a6f90cc85
21 changed files with 15890 additions and 2336 deletions
+64 -20
View File
@@ -21,40 +21,73 @@ Use the GitHub MCP tools to read the PR details. If the PR has merge conflicts,
Read the PR diff. Focus only on changes to `README.md`. If the PR modifies files other than `README.md` (like `parse.py`, `site/`, etc.), flag this as unusual — most contributions should only touch `README.md`.
### Step 4: Validate each added entry
### Step 4: Automatic rejection checks
Reject the PR immediately (close with a polite comment) if any of these apply:
- **Multiple projects in one PR** — each PR should add exactly one project.
- **Empty PR description** — the contributor must explain what they're adding.
- **Duplicate** — the project name or URL is already in `README.md` or in a recently closed PR.
- **Archived or abandoned** — the project has no activity in 12+ months.
### Step 5: Validate each added entry
For every new line added to `README.md`, check the following:
#### 4a. Entry format
#### 5a. Entry format
Each entry MUST match this exact pattern:
Each entry MUST match one of these accepted formats:
**GitHub project:**
```
- [Project Name](https://url) - Short description ending with a period.
- [Project Name](https://github.com/owner/repo) - Short description ending with a period.
```
Specifically:
**Project with website and GitHub repo:**
```
- [Project Name](https://project-site.com) - Short description ending with a period. [GitHub](https://github.com/owner/repo)
```
**CRAN project (with optional GitHub link):**
```
- [Package Name](https://cran.r-project.org/package=pkgname) - Short description ending with a period.
- [Package Name](https://cran.r-project.org/package=pkgname) - Short description ending with a period. [GitHub](https://github.com/owner/repo)
```
**PyPI project (with optional GitHub link):**
```
- [package-name](https://pypi.org/project/package-name/) - Short description ending with a period.
- [package-name](https://pypi.org/project/package-name/) - Short description ending with a period. [GitHub](https://github.com/owner/repo)
```
The core regex used by `parse.py` to extract entries is: `^\s*- \[(.*)\]\((.*)\) - (.*)$`
Specifically check:
- Starts with `- ` (dash + space)
- Followed by a markdown link `[Name](URL)`
- Followed by ` - ` (space, dash, space)
- Followed by a description that ends with a period `.`
The regex used by `parse.py` to extract entries is: `^\s*- \[(.*)\]\((.*)\) - (.*)$`
- The period must come before the optional `[GitHub](url)` link
- The `[GitHub]` link, if present, must use the exact format `[GitHub](https://github.com/owner/repo)`
If the entry doesn't match, report exactly what's wrong (missing period, wrong separator, etc.).
#### 4b. URL validation
#### 5b. URL validation
- **GitHub URLs are preferred.** If the URL points to `github.com`, that's ideal — no warning needed.
- **Non-GitHub URLs**: If the URL points somewhere else (PyPI, personal site, docs site, etc.), flag it with a warning: "This is not a GitHub URL. GitHub repos are preferred because they allow automated tracking of activity and archive status. Consider whether a GitHub link exists for this project."
- Check that the URL looks well-formed (starts with `https://`).
- **GitHub URLs are preferred.** If the primary URL points to `github.com`, that's ideal.
- **CRAN URLs** (`cran.r-project.org`) are acceptable for R packages.
- **PyPI URLs** (`pypi.org`) are acceptable for Python packages.
- **Non-GitHub URLs with `[GitHub]` link**: If the primary URL is a project website but includes a `[GitHub](url)` link in the description, that's the preferred format for non-GitHub projects.
- **Non-GitHub URLs without `[GitHub]` link**: Flag with a suggestion to add a `[GitHub](url)` link if one exists, since GitHub repos enable automated tracking of stars and activity.
- All URLs must use `https://`.
#### 4c. Section placement
#### 5c. Section placement
Look at which `##` (language) and `###` (category) heading the entry was added under. Evaluate whether the project fits that section based on its description and URL:
Look at which `##` (language) and `###` (category) heading the entry was added under. Evaluate whether the project fits that section:
- Does the project's language match the section? (e.g., a Python library should be under `## Python`)
- Does the project's purpose match the category? (e.g., a backtesting framework should be under `### Trading & Backtesting`, not `### Indicators`)
- Commercial/proprietary projects must go under `## Commercial & Proprietary Services`.
- If the placement seems wrong, suggest a better section.
The current sections in the README are:
@@ -67,13 +100,20 @@ The current sections in the README are:
**Cross-language**: Frameworks, Reproducing Works Training & Books
**Commercial & Proprietary Services**
If the project doesn't fit any existing section, suggest the closest match or recommend creating a new subsection (rare).
#### 4d. Duplicate check
#### 5d. Duplicate check
Grep the current `README.md` for the project name and URL to ensure it's not already listed.
### Step 5: Summarize findings
#### 5e. Quality check
- **Active**: Project should show recent activity (commits within the last 12 months).
- **Documented**: Project should have a clear README with usage examples.
### Step 6: Summarize findings
Present a clear summary:
@@ -87,22 +127,26 @@ Entries reviewed: <count>
<For each entry>
- [Name](URL) - Description
Format: OK / ISSUE: <details>
URL: GitHub / WARNING: Non-GitHub URL (<domain>)
URL: GitHub / CRAN / PyPI / WARNING: <details>
Section: OK (<section>) / SUGGESTION: Move to <section>
Duplicate: No / YES: Already listed at line <N>
Quality: OK / WARNING: <details>
</For each entry>
Conflicts: None / YES: Needs rebase
Verdict: APPROVE / NEEDS CHANGES
Verdict: APPROVE / NEEDS CHANGES / REJECT
```
### Step 6: Take action
### Step 7: Take action
- **If everything passes**: Ask the user for confirmation, then approve and merge the PR.
- **If there are issues**: Leave a constructive review comment on the PR listing what needs to be fixed. Be polite and specific — these are open-source contributors.
- **If there are fixable issues**: Leave a constructive review comment on the PR listing what needs to be fixed. Be polite and specific — these are open-source contributors. Link to `CONTRIBUTING.md` for reference.
- **If it should be rejected** (automatic rejection criteria): Close the PR with a polite explanation and link to `CONTRIBUTING.md`.
When leaving comments, be friendly and grateful for the contribution. Example tone:
> Thanks for the contribution! A couple of things to address before we can merge:
> - The description should end with a period.
> - Consider linking to the GitHub repo instead of the docs site so we can track activity.
> - Consider adding a `[GitHub](url)` link so we can track activity.
>
> Please see our [contributing guidelines](https://github.com/wilsonfreitas/awesome-quant/blob/master/CONTRIBUTING.md) for the accepted entry formats.
-79
View File
@@ -1,79 +0,0 @@
---
name: sync-site
description: Sync site/index.qmd with README.md content. Use this skill whenever README.md has been updated and the site needs to reflect those changes — after merging PRs, editing entries, adding libraries, or any modification to README.md. Also triggers for "update site", "sync site", "deploy site", "update qmd", or mentions of site/index.qmd being out of date.
---
# Sync Site
Update `site/index.qmd` to match the current `README.md` content, then commit and push.
## How it works
`site/index.qmd` is composed of two parts:
1. **YAML frontmatter** (lines 1-11) — Quarto metadata that never changes. Preserve it exactly as-is.
2. **Body content** — Everything from `## Python` to the end of the file. This must match `README.md` from the `## Python` heading onward.
The preamble in README.md (title, badges, language table of contents) is intentionally excluded from `index.qmd` because the Quarto frontmatter replaces it.
## Steps
### 1. Extract the frontmatter from index.qmd
Read `site/index.qmd` and capture everything up to and including the closing `---` and the blank line + description + badge lines that follow it (lines 1-16).
The header looks like this:
```
---
title: "Awesome Quant"
...
---
A curated list of insanely awesome libraries, packages and resources for Quants (Quantitative Finance).
[![](https://awesome.re/badge.svg)](https://awesome.re)
```
### 2. Extract the body from README.md
Read `README.md` and capture everything starting from the line `## Python` (inclusive) to the end of the file.
### 3. Combine and write
Concatenate the frontmatter header and the README body, then write to `site/index.qmd`.
Use a shell script for reliability:
```bash
# Extract line number where "## Python" starts in README.md
START=$(grep -n '^## Python' README.md | head -1 | cut -d: -f1)
# Extract frontmatter + preamble from index.qmd (up to the badge line)
END=$(grep -n 'awesome.re/badge' site/index.qmd | head -1 | cut -d: -f1)
# Combine: header from qmd + body from README
{ head -n "$END" site/index.qmd; echo; tail -n +"$START" README.md; } > site/index.qmd.tmp
mv site/index.qmd.tmp site/index.qmd
```
### 4. Verify
Run a quick diff to confirm the update looks correct:
```bash
# Show line count to sanity-check
wc -l site/index.qmd
# Optionally diff the body portion to confirm they match
diff <(tail -n +"$START" README.md) <(sed -n "$((END+2)),\$p" site/index.qmd)
```
### 5. Commit and push
Stage, commit, and push the change:
```bash
git add site/index.qmd
git commit -m "Sync site/index.qmd with README.md"
git push origin main
```