diff --git a/README.adoc b/README.adoc deleted file mode 100644 index df2a1e6..0000000 --- a/README.adoc +++ /dev/null @@ -1,306 +0,0 @@ -// SPDX-License-Identifier: CC-BY-SA-4.0 -// Copyright (c) Jonathan D.A. Jewell -= launch-scaffolder -:author: Jonathan D.A. Jewell -:revdate: 2026-04-10 -:toc: left -:toclevels: 3 - -**Build cross-platform desktop launchers from a declarative A2ML spec.** - -image:https://img.shields.io/badge/OpenSSF-Best_Practices-green?logo=opensourcesecurity[OpenSSF Best Practices,link="https://www.bestpractices.dev/en/projects/new?repo_url=https://github.com/hyperpolymath/launch-scaffolder"] -image:https://img.shields.io/badge/License-MPL_2.0-blue.svg[License: MPL-2.0,link="https://opensource.org/licenses/MPL-2.0"] -image:https://api.thegreenwebfoundation.org/greencheckimage/github.com[Green Web,link="https://www.thegreenwebfoundation.org/green-web-check/?url=github.com"] -image:https://img.shields.io/badge/rust-1.85%2B-orange.svg[Rust 1.85+] -image:https://img.shields.io/badge/status-alpha-yellow.svg[Status: alpha] -image:https://img.shields.io/badge/mint-working-green.svg[Mint: working] -image:https://img.shields.io/badge/realign-working-green.svg[Realign: working] -image:https://img.shields.io/badge/provision-working-green.svg[Provision: working] -image:https://img.shields.io/badge/config-working-green.svg[Config: working] - -== What it does - -`launch-scaffolder` is a single Rust binary that generates, installs, and -maintains cross-platform desktop launcher scripts for any hyperpolymath -project (or any other project that adopts the hyperpolymath launcher -standard). It turns launcher scripts into **generated artefacts**, not -hand-edited files. - -Inputs: - -* `launcher-standard.a2ml` — a declarative description of what a compliant - launcher looks like (modes, file paths, permissions, integrity - requirements, per-platform behaviour). The canonical copy lives in the - `standards` monorepo at - `/var/mnt/eclipse/repos/developer-ecosystem/standards/launcher/launcher-standard.a2ml`. At - runtime the loader resolves in this order: -+ - . `--standard ` CLI flag - . `$LAUNCH_SCAFFOLDER_STANDARD` environment variable - . The canonical path above - . A baked-in copy compiled into the binary at build time (fallback only) -* `.launcher.a2ml` — per-app config (name, display, URL, command, - repo, icon, and an optional `[exceptions]` block). - -Output: - -* `-launcher.sh` — a fully spec-compliant cross-platform launcher - (Linux / macOS / Windows-via-Git-Bash). - -== Why this exists - -Without this tool, every hyperpolymath project maintains its own -hand-written `~600-line bash launcher script` that has to be kept in sync -with the current launcher standard by hand. In practice, drift is -guaranteed. The launcher standard evolves; the launchers don't. Fixing a -spec issue means editing 11+ files and hoping you caught them all. - -With this tool: - -* The standard is a single file. Changing it is a one-line edit. -* Every launcher is regenerated from the same standard + its own config. -* Bulk realignment after a spec change is one command: - `launch-scaffolder realign *.launcher.a2ml`. -* Launchers become reproducible, auditable artefacts — not hand-edited drift. -* "Not wasting tokens in future" — future AI sessions read one spec file, - not 11 near-identical launcher scripts. - -== Commands - -All four working subcommands, in the order you're likely to use them: - -[source,bash] ----- -# ─── mint ────────────────────────────────────────────────────────────────── -# Generate a launcher script from a config. Writes -# /-launcher.sh by default. -launch-scaffolder mint examples/stapeln.launcher.fixture.a2ml -launch-scaffolder mint /path/to/burble.launcher.a2ml -o /tmp/out.sh -launch-scaffolder mint /path/to/burble.launcher.a2ml --stdout - -# ─── realign ─────────────────────────────────────────────────────────────── -# Bulk re-mint: walk the estate (default = /var/mnt/eclipse/repos) and -# re-render every live `.launcher.a2ml` against the current standard -# + template. Idempotent — unchanged scripts stay unchanged. -launch-scaffolder realign # walk estate root -launch-scaffolder realign --search-root ~/my-projects # narrow walk -launch-scaffolder realign /path/to/one.launcher.a2ml # explicit configs -launch-scaffolder realign --dry-run # preview only -launch-scaffolder realign --check # CI mode: exit 1 on any diff -launch-scaffolder realign --keep-going # don't stop on errors - -# ─── provision ───────────────────────────────────────────────────────────── -# Install (--integ) or uninstall (--disinteg) a launcher's desktop entry, -# icon, and launcher binary on the current system. Writes .desktop files -# directly from the Rust binary rather than going via the generated shell -# script. Bulk runs (--all) prompt before touching $HOME. -launch-scaffolder provision --integ /path/to/burble.launcher.a2ml -launch-scaffolder provision --disinteg /path/to/burble.launcher.a2ml -launch-scaffolder provision --integ --all # everything in the estate -launch-scaffolder provision --integ --all --no-confirm --force -launch-scaffolder provision --integ --all --dry-run # preview only - -# ─── config ──────────────────────────────────────────────────────────────── -# Inspect or edit the `@a2ml-metadata` block embedded at the top of any -# generated launcher script. -launch-scaffolder config get ./stapeln-launcher.sh version -launch-scaffolder config get ./stapeln-launcher.sh standards-compliance -launch-scaffolder config validate ./stapeln-launcher.sh -launch-scaffolder config set ./stapeln-launcher.sh version 0.2.0 -# NOTE: `config set` rewrites the generated script in place and warns -# that `realign` will overwrite the change. The durable fix is to edit -# the source .launcher.a2ml and re-mint. ----- - -=== Generated script → binary delegation - -Generated `-launcher.sh` scripts carry their own `--integ` / -`--disinteg` arms (the original, pure-bash implementation). They now -also embed the absolute path of their source config as `CONFIG_FILE=...` -and, on invocation, fast-path back to -`launch-scaffolder provision --integ "$CONFIG_FILE"` when the binary is -on `PATH`. If the binary isn't present, the in-script shell fallback -runs instead. This means: the Rust binary is authoritative *when -available*, without making itself a hard dependency for integrated -launchers. - -== Architecture - -[source] ----- -launch-scaffolder/ -├── Cargo.toml # Workspace root -├── crates/ -│ ├── launcher-common/ # Shared library — all real logic -│ │ └── src/ -│ │ ├── lib.rs # Public API -│ │ ├── standard.rs # Parse launcher-standard.a2ml -│ │ │ # + LauncherStandard::resolve (shared -│ │ │ # 3-step precedence: flag → canonical -│ │ │ # → baked fallback) -│ │ ├── config.rs # Parse .launcher.a2ml -│ │ ├── template.rs # Render via Tera (embeds CONFIG_FILE) -│ │ ├── discovery.rs # Walk + prune + fixture-suffix filter -│ │ │ # (shared by realign + provision) -│ │ ├── integration.rs # Native Rust .desktop writer, -│ │ │ # icon/launcher install, gio, -│ │ │ # update-desktop-database -│ │ ├── metadata_block.rs # Parser + in-place rewriter for the -│ │ │ # embedded @a2ml-metadata block -│ │ ├── platform.rs # Linux/macOS/Windows dispatch (stub) -│ │ ├── integrity.rs # SHA-256 manifests (stub) -│ │ └── exceptions.rs # Standard + config + exception merge (stub) -│ └── launcher/ # Thin CLI binary -│ └── src/ -│ ├── main.rs # clap dispatch -│ ├── cmd_mint.rs # ✓ working -│ ├── cmd_realign.rs # ✓ working -│ ├── cmd_provision.rs # ✓ working (native Rust; option b) -│ ├── cmd_config.rs # ✓ working -│ └── cmd_standard.rs # stub -├── standards/ -│ └── launcher-standard.a2ml # Canonical standard (baked into binary) -├── templates/ -│ └── launcher.sh.tera # Bash launcher template rendered by Tera -├── examples/ -│ ├── README.md # Fixture-vs-live naming convention -│ └── stapeln.launcher.fixture.a2ml # Worked example (fixture suffix!) -├── docs/ -│ ├── launcher-exceptions-2026-04-10.md -│ ├── compliance-audit-2026-04-10.md -│ ├── branch-protection-remediation-2026-04-10.md -│ └── ruleset-audit-2026-04-10/ # Audit artefacts (read-only record) -└── tests/ - └── regression/ # Golden-file regression fixtures (planned) ----- - -=== Fixture-vs-live naming convention - -To distinguish test fixtures from live, estate-owned launcher configs, -**file-name suffixes carry the distinction** — directory names do not: - -[cols="1,2,1",options="header"] -|=== -| Purpose | File-name suffix | Picked up by estate walks? -| Live per-app config | `.launcher.a2ml` | **Yes** -| Fixture / worked example | `.launcher.fixture.a2ml` | **No** -|=== - -The discovery code in `launch-scaffolder-common::discovery::is_live_config` -enforces this rule. Fixture files can live anywhere — including inside -a consumer repo's `examples/` directory — without being swept up by -`realign` or `provision --all`. See `examples/README.md` for the full -contributor-facing version of the rule. - -=== Why Rust/SPARK - -Per the hyperpolymath language policy (see `standards/rhodium-standard-repositories/spec/LANGUAGE-POLICY.adoc`): - -* **Rust** is the preferred language for CLI tools — zero-dep binary, fast - cold start, strong types, excellent ecosystem (clap, tera, sha2, anyhow). -* **"Rust" always means "Rust with SPARK integration as the default stance"** - — this tool is Rust-primary now, with SPARK/Ada hooks planned for the - correctness-critical `integrity.rs` path (called via Zig FFI per the - hyperpolymath ABI/FFI standard). - -=== Why A2ML for inputs - -* A2ML is the hyperpolymath standard format for machine-readable config - and metadata, and every launcher already carries an A2ML metadata block - in its header. Using A2ML end-to-end means a launcher script can be - *parsed by this tool* to extract its config and re-minted. -* v0.1 uses TOML as the concrete syntax (A2ML is "TOML-like" per the - standards `.claude/CLAUDE.md`). v0.2 switches to proper A2ML once the - `a2ml-rs` parser reaches feature parity. - -== Status - -**Alpha, ~65% complete. Four of five subcommands fully wired end-to-end; -one remains a stub (`standard`). Last updated 2026-04-10 (phase -`phase-4-config-inspector`).** - -Implemented: - -* [x] Cargo workspace layout (two crates: `launch-scaffolder-common` + `launch-scaffolder`) -* [x] `standard` module — parses `launcher-standard.a2ml`; `LauncherStandard::resolve` hosts the shared 3-step precedence (flag → canonical → baked) -* [x] `config` module — parses `.launcher.a2ml` (TOML) with runtime-kind validation -* [x] `template` module — Tera renderer with full context; embeds `CONFIG_FILE` for in-script delegation -* [x] `discovery` module — shared walk + prune + fixture-suffix filter -* [x] `integration` module — native Rust `.desktop` writer, icon/launcher install, best-effort `gio` + `update-desktop-database` (Linux only; macOS/Windows return `IntegError::UnsupportedPlatform`) -* [x] `metadata_block` module — hand-rolled parser and in-place rewriter for the embedded `@a2ml-metadata` block -* [x] `templates/launcher.sh.tera` — parameterised over `runtime_kind ∈ {server-url, process, remote}`; `--integ` / `--disinteg` fast-path to `launch-scaffolder provision` when on PATH -* [x] **`mint`** subcommand — positional config, `-o/--out`, `--stdout`, `--no-chmod` -* [x] **`realign`** subcommand — estate walk with `--search-root` override, `--dry-run`, `--check` (CI), `--keep-going`, walk-error tolerant -* [x] **`provision`** subcommand — `--integ` / `--disinteg` with `--all`, `--force`, `--no-confirm`, `--dry-run`; bulk mode prompts before touching `$HOME` -* [x] **`config`** subcommand — `get` / `set` / `validate`; `set` preserves column alignment in the embedded metadata block -* [x] 17 unit tests passing across both crates -* [x] 7 launchers fully managed: aerie, burble, game-server-admin, nqc, panll, project-wharf, stapeln -* [x] 5 declared exceptions documented in `docs/launcher-exceptions-2026-04-10.md` -* [x] Fixture-vs-live file-naming convention documented and enforced -* [x] All 7 managed launchers regenerated with template delegation arms (2026-04-10) - -Remaining work (ordered by current priority in STATE.a2ml): - -* [ ] Golden-file regression tests pinning mint output for the 7 managed launchers -* [ ] macOS integration backend in `launch-scaffolder-common::integration` -* [ ] SPARK integration hook for `integrity.rs` via Zig FFI -* [ ] `standard` subcommand — still a scaffold stub -* [ ] `platform` module — still a stub (runtime dispatch handled inside the generated script today) -* [ ] `integrity` module — still a stub (pending SHA-256 manifest generator) -* [ ] `exceptions` module — still a stub (per-app override merge) -* [ ] Cross-platform CI (Linux/macOS/Windows matrix) -* [ ] Migration of the 5 declared exceptions once the template grows custom-mode hooks - -== Build - -[source,bash] ----- -# Standard cargo workflow -cargo build # debug build -cargo build --release # optimized, stripped, single-file binary -cargo test # run tests -cargo run -- --help # invoke the binary - -# Or via Justfile -just build -just test -just install # cargo install --path crates/launcher ----- - -== License - -This project is licensed under the Mozilla Public License, v. 2.0. See the `LICENSE` file for details. - -SPDX-License-Identifier: CC-BY-SA-4.0 - -== Author - -Jonathan D.A. Jewell (hyperpolymath) + -j.d.a.jewell@open.ac.uk - -== Relationship to other hyperpolymath projects - -Each consumer repo owns its own `.launcher.a2ml` config at its -repository root. `launch-scaffolder mint` writes the generated -`-launcher.sh` next to it. The pre-2026-04-10 pattern of pooling -launchers under `/var/mnt/eclipse/repos/.desktop-tools/` is deprecated; -`~/Desktop/Shortcuts/*.desktop` files have been repointed at the new -per-repo paths. - -**Scaffolder-managed consumers (as of 2026-04-10):** - -* **stapeln** — Visual Container Stack Designer (server-url, port 4010) -* **burble** — WebRTC voice + control plane (server-url, port 4020) -* **aerie** — network diagnostic suite (process) -* **game-server-admin** — multi-game server orchestration (process) -* **nqc** — NextGen Query Client, inside `nextgen-databases/` (process) -* **panll** — panels framework (server-url, port 8000) -* **project-wharf** — container/workload staging (process) - -**Declared exceptions** (still hand-written; see -`docs/launcher-exceptions-2026-04-10.md` for reasoning and migration triggers): - -* `hypatia`, `invariant-path`, `opsm`, `ambientops`, `idaptik` - -The bulk-realignment goal: once `realign` is implemented, one command will -re-mint every managed launcher in the estate against the current standard. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb923e5 --- /dev/null +++ b/README.md @@ -0,0 +1,372 @@ + + +**Build cross-platform desktop launchers from a declarative A2ML spec.** + +[![OpenSSF Best Practices](https://img.shields.io/badge/OpenSSF-Best_Practices-green?logo=opensourcesecurity)](https://www.bestpractices.dev/en/projects/new?repo_url=https://github.com/hyperpolymath/launch-scaffolder) +[![License: MPL-2.0](https://img.shields.io/badge/License-MPL_2.0-blue.svg)](https://opensource.org/licenses/MPL-2.0) +![Rust 1.85+](https://img.shields.io/badge/rust-1.85%2B-orange.svg) +![Status: alpha](https://img.shields.io/badge/status-alpha-yellow.svg) +![Mint: working](https://img.shields.io/badge/mint-working-green.svg) +![Realign: +working](https://img.shields.io/badge/realign-working-green.svg) +![Provision: +working](https://img.shields.io/badge/provision-working-green.svg) +![Config: +working](https://img.shields.io/badge/config-working-green.svg) + +# What it does + +`launch-scaffolder` is a single Rust binary that generates, installs, +and maintains cross-platform desktop launcher scripts for any +hyperpolymath project (or any other project that adopts the +hyperpolymath launcher standard). It turns launcher scripts into +**generated artefacts**, not hand-edited files. + +Inputs: + +- `launcher-standard.a2ml` — a declarative description of what a + compliant launcher looks like (modes, file paths, permissions, + integrity requirements, per-platform behaviour). The canonical copy + lives in the `standards` monorepo at + `/var/mnt/eclipse/repos/developer-ecosystem/standards/launcher/launcher-standard.a2ml`. + At runtime the loader resolves in this order: + + 1. `--standard` `` CLI flag + + 2. `$LAUNCH_SCAFFOLDER_STANDARD` environment variable + + 3. The canonical path above + + 4. A baked-in copy compiled into the binary at build time (fallback + only) + +- `.launcher.a2ml` — per-app config (name, display, URL, command, + repo, icon, and an optional `[exceptions]` block). + +Output: + +- `-launcher.sh` — a fully spec-compliant cross-platform launcher + (Linux / macOS / Windows-via-Git-Bash). + +# Why this exists + +Without this tool, every hyperpolymath project maintains its own +hand-written `~600-line` `bash` `launcher` `script` that has to be kept +in sync with the current launcher standard by hand. In practice, drift +is guaranteed. The launcher standard evolves; the launchers don’t. +Fixing a spec issue means editing 11+ files and hoping you caught them +all. + +With this tool: + +- The standard is a single file. Changing it is a one-line edit. + +- Every launcher is regenerated from the same standard + its own config. + +- Bulk realignment after a spec change is one command: + `launch-scaffolder` `realign` `*.launcher.a2ml`. + +- Launchers become reproducible, auditable artefacts — not hand-edited + drift. + +- "Not wasting tokens in future" — future AI sessions read one spec + file, not 11 near-identical launcher scripts. + +# Commands + +All four working subcommands, in the order you’re likely to use them: + +```bash +# ─── mint ────────────────────────────────────────────────────────────────── +# Generate a launcher script from a config. Writes +# /-launcher.sh by default. +launch-scaffolder mint examples/stapeln.launcher.fixture.a2ml +launch-scaffolder mint /path/to/burble.launcher.a2ml -o /tmp/out.sh +launch-scaffolder mint /path/to/burble.launcher.a2ml --stdout + +# ─── realign ─────────────────────────────────────────────────────────────── +# Bulk re-mint: walk the estate (default = /var/mnt/eclipse/repos) and +# re-render every live `.launcher.a2ml` against the current standard +# + template. Idempotent — unchanged scripts stay unchanged. +launch-scaffolder realign # walk estate root +launch-scaffolder realign --search-root ~/my-projects # narrow walk +launch-scaffolder realign /path/to/one.launcher.a2ml # explicit configs +launch-scaffolder realign --dry-run # preview only +launch-scaffolder realign --check # CI mode: exit 1 on any diff +launch-scaffolder realign --keep-going # don't stop on errors + +# ─── provision ───────────────────────────────────────────────────────────── +# Install (--integ) or uninstall (--disinteg) a launcher's desktop entry, +# icon, and launcher binary on the current system. Writes .desktop files +# directly from the Rust binary rather than going via the generated shell +# script. Bulk runs (--all) prompt before touching $HOME. +launch-scaffolder provision --integ /path/to/burble.launcher.a2ml +launch-scaffolder provision --disinteg /path/to/burble.launcher.a2ml +launch-scaffolder provision --integ --all # everything in the estate +launch-scaffolder provision --integ --all --no-confirm --force +launch-scaffolder provision --integ --all --dry-run # preview only + +# ─── config ──────────────────────────────────────────────────────────────── +# Inspect or edit the `@a2ml-metadata` block embedded at the top of any +# generated launcher script. +launch-scaffolder config get ./stapeln-launcher.sh version +launch-scaffolder config get ./stapeln-launcher.sh standards-compliance +launch-scaffolder config validate ./stapeln-launcher.sh +launch-scaffolder config set ./stapeln-launcher.sh version 0.2.0 +# NOTE: `config set` rewrites the generated script in place and warns +# that `realign` will overwrite the change. The durable fix is to edit +# the source .launcher.a2ml and re-mint. +``` + +## Generated script → binary delegation + +Generated `-launcher.sh` scripts carry their own `--integ` / +`--disinteg` arms (the original, pure-bash implementation). They now +also embed the absolute path of their source config as `CONFIG_FILE=…` +and, on invocation, fast-path back to `launch-scaffolder` `provision` +`--integ` `"$CONFIG_FILE"` when the binary is on `PATH`. If the binary +isn’t present, the in-script shell fallback runs instead. This means: +the Rust binary is authoritative **when available**, without making +itself a hard dependency for integrated launchers. + +# Architecture + + launch-scaffolder/ + ├── Cargo.toml # Workspace root + ├── crates/ + │ ├── launcher-common/ # Shared library — all real logic + │ │ └── src/ + │ │ ├── lib.rs # Public API + │ │ ├── standard.rs # Parse launcher-standard.a2ml + │ │ │ # + LauncherStandard::resolve (shared + │ │ │ # 3-step precedence: flag → canonical + │ │ │ # → baked fallback) + │ │ ├── config.rs # Parse .launcher.a2ml + │ │ ├── template.rs # Render via Tera (embeds CONFIG_FILE) + │ │ ├── discovery.rs # Walk + prune + fixture-suffix filter + │ │ │ # (shared by realign + provision) + │ │ ├── integration.rs # Native Rust .desktop writer, + │ │ │ # icon/launcher install, gio, + │ │ │ # update-desktop-database + │ │ ├── metadata_block.rs # Parser + in-place rewriter for the + │ │ │ # embedded @a2ml-metadata block + │ │ ├── platform.rs # Linux/macOS/Windows dispatch (stub) + │ │ ├── integrity.rs # SHA-256 manifests (stub) + │ │ └── exceptions.rs # Standard + config + exception merge (stub) + │ └── launcher/ # Thin CLI binary + │ └── src/ + │ ├── main.rs # clap dispatch + │ ├── cmd_mint.rs # ✓ working + │ ├── cmd_realign.rs # ✓ working + │ ├── cmd_provision.rs # ✓ working (native Rust; option b) + │ ├── cmd_config.rs # ✓ working + │ └── cmd_standard.rs # stub + ├── standards/ + │ └── launcher-standard.a2ml # Canonical standard (baked into binary) + ├── templates/ + │ └── launcher.sh.tera # Bash launcher template rendered by Tera + ├── examples/ + │ ├── README.md # Fixture-vs-live naming convention + │ └── stapeln.launcher.fixture.a2ml # Worked example (fixture suffix!) + ├── docs/ + │ ├── launcher-exceptions-2026-04-10.md + │ ├── compliance-audit-2026-04-10.md + │ ├── branch-protection-remediation-2026-04-10.md + │ └── ruleset-audit-2026-04-10/ # Audit artefacts (read-only record) + └── tests/ + └── regression/ # Golden-file regression fixtures (planned) + +## Fixture-vs-live naming convention + +To distinguish test fixtures from live, estate-owned launcher configs, +**file-name suffixes carry the distinction** — directory names do not: + +| Purpose | File-name suffix | Picked up by estate walks? | +|----|----|----| +| Live per-app config | `.launcher.a2ml` | **Yes** | +| Fixture / worked example | `.launcher.fixture.a2ml` | **No** | + +The discovery code in \`launch-scaffolder-common + +discovery +is_live_config\` enforces this rule. Fixture files can live anywhere — +including inside a consumer repo’s `examples/` directory — without being +swept up by `realign` or `provision` `--all`. See `examples/README.md` +for the full contributor-facing version of the rule. + +## Why Rust/SPARK + +Per the hyperpolymath language policy (see +`standards/rhodium-standard-repositories/spec/LANGUAGE-POLICY.adoc`): + +- **Rust** is the preferred language for CLI tools — zero-dep binary, + fast cold start, strong types, excellent ecosystem (clap, tera, sha2, + anyhow). + +- **"Rust" always means "Rust with SPARK integration as the default + stance"** — this tool is Rust-primary now, with SPARK/Ada hooks + planned for the correctness-critical `integrity.rs` path (called via + Zig FFI per the hyperpolymath ABI/FFI standard). + +## Why A2ML for inputs + +- A2ML is the hyperpolymath standard format for machine-readable config + and metadata, and every launcher already carries an A2ML metadata + block in its header. Using A2ML end-to-end means a launcher script can + be **parsed by this tool** to extract its config and re-minted. + +- v0.1 uses TOML as the concrete syntax (A2ML is "TOML-like" per the + standards `.claude/CLAUDE.md`). v0.2 switches to proper A2ML once the + `a2ml-rs` parser reaches feature parity. + +# Status + +**Alpha, ~65% complete. Four of five subcommands fully wired end-to-end; +one remains a stub (`standard`). Last updated 2026-04-10 (phase +`phase-4-config-inspector`).** + +Implemented: + +- [x] Cargo workspace layout (two crates: `launch-scaffolder-common` + + `launch-scaffolder`) + + \* \[x\] `standard` module — parses `launcher-standard.a2ml`; \`LauncherStandard + resolve\` hosts the shared 3-step precedence (flag → canonical → + baked) + +- [x] `config` module — parses `.launcher.a2ml` (TOML) with + runtime-kind validation + +- [x] `template` module — Tera renderer with full context; embeds + `CONFIG_FILE` for in-script delegation + +- [x] `discovery` module — shared walk + prune + fixture-suffix filter + + \* \[x\] `integration` module — native Rust `.desktop` writer, icon/launcher install, best-effort `gio` + `update-desktop-database` (Linux only; macOS/Windows return \`IntegError + UnsupportedPlatform\`) + +- [x] `metadata_block` module — hand-rolled parser and in-place rewriter + for the embedded `@a2ml-metadata` block + +- [x] `templates/launcher.sh.tera` — parameterised over `runtime_kind` + `∈` `{server-url,` `process,` `remote}`; `--integ` / `--disinteg` + fast-path to `launch-scaffolder` `provision` when on PATH + +- [x] **`mint`** subcommand — positional config, `-o/--out`, `--stdout`, + `--no-chmod` + +- [x] **`realign`** subcommand — estate walk with `--search-root` + override, `--dry-run`, `--check` (CI), `--keep-going`, walk-error + tolerant + +- [x] **`provision`** subcommand — `--integ` / `--disinteg` with + `--all`, `--force`, `--no-confirm`, `--dry-run`; bulk mode prompts + before touching `$HOME` + +- [x] **`config`** subcommand — `get` / `set` / `validate`; `set` + preserves column alignment in the embedded metadata block + +- [x] 17 unit tests passing across both crates + +- [x] 7 launchers fully managed: aerie, burble, game-server-admin, nqc, + panll, project-wharf, stapeln + +- [x] 5 declared exceptions documented in + `docs/launcher-exceptions-2026-04-10.md` + +- [x] Fixture-vs-live file-naming convention documented and enforced + +- [x] All 7 managed launchers regenerated with template delegation arms + (2026-04-10) + +Remaining work (ordered by current priority in STATE.a2ml): + +- [ ] Golden-file regression tests pinning mint output for the 7 managed + launchers + + \* \[ \] macOS integration backend in \`launch-scaffolder-common + integration\` + +- [ ] SPARK integration hook for `integrity.rs` via Zig FFI + +- [ ] `standard` subcommand — still a scaffold stub + +- [ ] `platform` module — still a stub (runtime dispatch handled inside + the generated script today) + +- [ ] `integrity` module — still a stub (pending SHA-256 manifest + generator) + +- [ ] `exceptions` module — still a stub (per-app override merge) + +- [ ] Cross-platform CI (Linux/macOS/Windows matrix) + +- [ ] Migration of the 5 declared exceptions once the template grows + custom-mode hooks + +# Build + +```bash +# Standard cargo workflow +cargo build # debug build +cargo build --release # optimized, stripped, single-file binary +cargo test # run tests +cargo run -- --help # invoke the binary + +# Or via Justfile +just build +just test +just install # cargo install --path crates/launcher +``` + +# License + +This project is licensed under the Mozilla Public License, v. 2.0. See +the `LICENSE` file for details. + +SPDX-License-Identifier: CC-BY-SA-4.0 + +# Author + +Jonathan D.A. Jewell (hyperpolymath)\ +[j.d.a.jewell@open.ac](j.d.a.jewell@open.ac).uk + +# Relationship to other hyperpolymath projects + +Each consumer repo owns its own `.launcher.a2ml` config at its +repository root. `launch-scaffolder` `mint` writes the generated +`-launcher.sh` next to it. The pre-2026-04-10 pattern of pooling +launchers under `/var/mnt/eclipse/repos/.desktop-tools/` is deprecated; +`~/Desktop/Shortcuts/*.desktop` files have been repointed at the new +per-repo paths. + +**Scaffolder-managed consumers (as of 2026-04-10):** + +- **stapeln** — Visual Container Stack Designer (server-url, port 4010) + +- **burble** — WebRTC voice + control plane (server-url, port 4020) + +- **aerie** — network diagnostic suite (process) + +- **game-server-admin** — multi-game server orchestration (process) + +- **nqc** — NextGen Query Client, inside `nextgen-databases/` (process) + +- **panll** — panels framework (server-url, port 8000) + +- **project-wharf** — container/workload staging (process) + +**Declared exceptions** (still hand-written; see +`docs/launcher-exceptions-2026-04-10.md` for reasoning and migration +triggers): + +- `hypatia`, `invariant-path`, `opsm`, `ambientops`, `idaptik` + +The bulk-realignment goal: once `realign` is implemented, one command +will re-mint every managed launcher in the estate against the current +standard.