mirror of
https://github.com/awizemann/scarf.git
synced 2026-05-10 10:36:35 +00:00
chore: audit follow-ups from plan review
Four small fixes surfaced by a side-by-side plan-vs-shipped pass: - README.md: adds the Template Catalog section the plan called out — links to the live site URL, the install flows (web / file / Finder), and templates/CONTRIBUTING.md for authors. Placed right before the existing Contributing section, with a catalog-specific cross-link at the end of that section too. - CLAUDE.md: adds the Template Catalog section so future agent sessions know the regenerator pipeline exists, how it relates to release.sh + wiki.sh, and what the schema-sync rule is when DashboardWidget or ProjectTemplateManifest change. - scarf/scarfTests/ProjectTemplateTests.swift: fixes the stale ProjectTemplateExampleTemplateTests docstring still referencing `examples/templates/` (the example moved to `templates/awizemann/` in 70f7cea). - .github/workflows/validate-template-pr.yml: untangles the self- contradictory Python-version comment. The validator is 3.9+ compatible; CI uses 3.11 for faster runner caching. Same stdlib surface, same code paths — just clearer about why. All tests still green: 22 Swift tests in 7 suites, 16 Python tests, catalog check passes on the site-status-checker example. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,9 +36,10 @@ jobs:
|
|||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
# Stdlib-only script; any modern Python works. 3.9 matches the
|
# The validator is stdlib-only and tested against 3.9+ (the
|
||||||
# system Python on current macOS so we exercise the same code
|
# system Python on current macOS, what most maintainers run
|
||||||
# path maintainers hit locally.
|
# locally). CI uses 3.11 for faster cold-cache times on
|
||||||
|
# GitHub Actions runners — same stdlib APIs, same code paths.
|
||||||
python-version: '3.11'
|
python-version: '3.11'
|
||||||
|
|
||||||
- name: Run validator unit tests
|
- name: Run validator unit tests
|
||||||
|
|||||||
@@ -104,3 +104,26 @@ Key services: [ProjectTemplateService.swift](scarf/scarf/Core/Services/ProjectTe
|
|||||||
**Uninstall semantics:** driven by the lock file. Only files listed in `lock.projectFiles` are removed from the project dir; user-added files (e.g. a `sites.txt` created on first run) are preserved. If every file in the dir was installed by the template, the dir is removed too; otherwise the dir stays with just the user's files. Skills namespace is always removed wholesale (it's isolated). Cron jobs are removed via `hermes cron remove <id>` after resolving each lock-recorded name. Memory block is stripped between the `begin`/`end` markers, leaving the rest of MEMORY.md intact. No "undo" — uninstall is destructive; to re-install, run the install flow again. Uninstall UI lives on the project-list context menu and the dashboard header (only shown when the selected project has a lock file).
|
**Uninstall semantics:** driven by the lock file. Only files listed in `lock.projectFiles` are removed from the project dir; user-added files (e.g. a `sites.txt` created on first run) are preserved. If every file in the dir was installed by the template, the dir is removed too; otherwise the dir stays with just the user's files. Skills namespace is always removed wholesale (it's isolated). Cron jobs are removed via `hermes cron remove <id>` after resolving each lock-recorded name. Memory block is stripped between the `begin`/`end` markers, leaving the rest of MEMORY.md intact. No "undo" — uninstall is destructive; to re-install, run the install flow again. Uninstall UI lives on the project-list context menu and the dashboard header (only shown when the selected project has a lock file).
|
||||||
|
|
||||||
**Never** let a template write to `config.yaml`, `auth.json`, sessions, or any credential path — the v1 installer refuses. If you extend the format, treat the preview sheet as load-bearing: the user's only trust boundary is that the sheet is honest about everything that's about to be written.
|
**Never** let a template write to `config.yaml`, `auth.json`, sessions, or any credential path — the v1 installer refuses. If you extend the format, treat the preview sheet as load-bearing: the user's only trust boundary is that the sheet is honest about everything that's about to be written.
|
||||||
|
|
||||||
|
## Template Catalog
|
||||||
|
|
||||||
|
Shipped community templates live at `templates/<author>/<name>/` (one level down — `templates/CONTRIBUTING.md` explains the submission flow for authors). The catalog site is generated from this directory and served at `awizemann.github.io/scarf/templates/` alongside the Sparkle appcast — the two coexist on the `gh-pages` branch but touch completely disjoint paths.
|
||||||
|
|
||||||
|
Pipeline:
|
||||||
|
|
||||||
|
- **Validator + regenerator:** [tools/build-catalog.py](tools/build-catalog.py) is stdlib-only Python (3.9+). It walks `templates/*/*/`, validates every `.scarftemplate` against its manifest claim (mirrors the Swift `ProjectTemplateService.verifyClaims` invariants), enforces a 5 MB bundle-size cap, scans for high-confidence secret patterns, checks `staging/` matches the built bundle byte-for-byte, and emits `templates/catalog.json`. Tested by [tools/test_build_catalog.py](tools/test_build_catalog.py) — 16 tests covering every validation path.
|
||||||
|
- **Wrapper:** [scripts/catalog.sh](scripts/catalog.sh) mirrors the `scripts/wiki.sh` shape with `check / build / preview / serve / publish` subcommands. `publish` runs a second-pass secret-scan against the rendered site before committing + pushing `gh-pages`.
|
||||||
|
- **Site source:** `site/index.html.tmpl` + `site/template.html.tmpl` are `{{TOKEN}}`-substitution templates. `site/widgets.js` (~300 lines of vanilla JS) is the dogfood — renders a `ProjectDashboard` JSON into HTML using the same widget vocabulary the Swift app uses, so each template's detail page shows a live preview of its post-install dashboard.
|
||||||
|
- **Install-URL hosting:** raw-served from `main` at `https://raw.githubusercontent.com/awizemann/scarf/main/templates/<author>/<name>/<name>.scarftemplate`. No per-template Releases ceremony.
|
||||||
|
- **CI gate:** [.github/workflows/validate-template-pr.yml](.github/workflows/validate-template-pr.yml) runs the Python validator + its own test suite on every PR that touches `templates/`, the validator, or its tests. Failures post a comment on the PR with the last 3 KB of the validator log.
|
||||||
|
|
||||||
|
Maintainer workflow on merge to main:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/catalog.sh build # regenerate templates/catalog.json + .gh-pages-worktree/templates/
|
||||||
|
./scripts/catalog.sh publish # secret-scan rendered output + commit + push gh-pages
|
||||||
|
```
|
||||||
|
|
||||||
|
Same cadence as `scripts/release.sh` (manual, auditable, no auto-deploy). Runs stay isolated: release.sh only touches `appcast.xml` on gh-pages; catalog.sh only touches `templates/` on gh-pages. Never push catalog output on a release cadence or vice versa.
|
||||||
|
|
||||||
|
**Schema is Swift-primary.** When `ProjectDashboardWidget.type` gains a new case or `ProjectTemplateManifest` adds a field, update Swift first, then mirror into `tools/build-catalog.py` (`SUPPORTED_WIDGET_TYPES`, `_validate_manifest`, `_validate_contents_claim`) so the web validator stays honest. The Python test suite's real-bundle test catches drift on the example template but not on the full widget vocabulary — add a synthetic fixture to `test_build_catalog.py` for any new widget type.
|
||||||
|
|||||||
@@ -395,6 +395,16 @@ Signing prerequisites (one-time):
|
|||||||
- `scarf-notary` keychain profile registered via `xcrun notarytool store-credentials`
|
- `scarf-notary` keychain profile registered via `xcrun notarytool store-credentials`
|
||||||
- Sparkle EdDSA private key in Keychain item `https://sparkle-project.org` (back this up — without it, shipped apps can never receive updates)
|
- Sparkle EdDSA private key in Keychain item `https://sparkle-project.org` (back this up — without it, shipped apps can never receive updates)
|
||||||
|
|
||||||
|
## Template Catalog
|
||||||
|
|
||||||
|
Community-contributed Scarf project templates live under [`templates/`](templates/) in this repo and are browsable at **[awizemann.github.io/scarf/templates/](https://awizemann.github.io/scarf/templates/)** with live dashboard previews and one-click `scarf://install?url=…` links.
|
||||||
|
|
||||||
|
- **Install from the web** — click "Install with Scarf" on any template's detail page; the app takes over from there.
|
||||||
|
- **Install from a local file** — Scarf → Projects → Templates → Install from File…, or double-click any `.scarftemplate` in Finder.
|
||||||
|
- **Author a template** — see [`templates/CONTRIBUTING.md`](templates/CONTRIBUTING.md) for the full walkthrough. Fork, drop a template under `templates/<your-github-handle>/<your-name>/`, open a PR; CI validates the bundle automatically.
|
||||||
|
|
||||||
|
The catalog's site is a static HTML + vanilla JS build generated by [`tools/build-catalog.py`](tools/build-catalog.py) and driven by [`scripts/catalog.sh`](scripts/catalog.sh) (check / build / preview / publish). Appcast and main landing page are independent — updating the catalog never disturbs Sparkle.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome. Please open an issue to discuss what you'd like to change before submitting a PR.
|
Contributions are welcome. Please open an issue to discuss what you'd like to change before submitting a PR.
|
||||||
@@ -405,6 +415,8 @@ Contributions are welcome. Please open an issue to discuss what you'd like to ch
|
|||||||
4. Push to the branch (`git push origin feature/my-feature`)
|
4. Push to the branch (`git push origin feature/my-feature`)
|
||||||
5. Open a Pull Request
|
5. Open a Pull Request
|
||||||
|
|
||||||
|
For template submissions, see [`templates/CONTRIBUTING.md`](templates/CONTRIBUTING.md) — same flow, with a catalog-specific checklist + automated CI validation.
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you find Scarf useful, consider buying me a coffee.
|
If you find Scarf useful, consider buying me a coffee.
|
||||||
|
|||||||
@@ -484,9 +484,9 @@ import Foundation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates every `.scarftemplate` shipped under `examples/templates/` in
|
/// Validates every `.scarftemplate` shipped under `templates/<author>/<name>/`
|
||||||
/// the repo. A template whose manifest, `contents` claim, or file set is
|
/// in the repo. A template whose manifest, `contents` claim, or file set is
|
||||||
/// out of sync will fail here — so the examples can't silently rot.
|
/// out of sync will fail here — so shipped templates can't silently rot.
|
||||||
@Suite struct ProjectTemplateExampleTemplateTests {
|
@Suite struct ProjectTemplateExampleTemplateTests {
|
||||||
|
|
||||||
@Test func siteStatusCheckerParsesAndPlans() throws {
|
@Test func siteStatusCheckerParsesAndPlans() throws {
|
||||||
|
|||||||
Reference in New Issue
Block a user