diff --git a/.github/workflows/validate-recipes.yml b/.github/workflows/validate-recipes.yml new file mode 100644 index 0000000..db0c974 --- /dev/null +++ b/.github/workflows/validate-recipes.yml @@ -0,0 +1,41 @@ +# Bundle recipe validation — enforces the recipe contract on every PR that +# touches recipes/. A contributor adds recipes/.json and this decides if +# it's mergeable, with no maintainer code change for the common case. +# +# Runs on macOS because the validator resolves every package with `brew info` +# (macOS runners ship Homebrew), and checks tap-trust + link reachability. +# See memory-bank/releases/0.7.0/bundles/recipe-contract.md for the contract +# and .../m5-live-refresh-and-contributions.md for the pipeline. + +name: Validate Recipes + +on: + pull_request: + paths: + - "recipes/**" + - "scripts/validate-recipes.mjs" + - ".github/workflows/validate-recipes.yml" + push: + branches: [main] + paths: + - "recipes/**" + - "scripts/validate-recipes.mjs" + +jobs: + validate: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + - name: brew --version (Homebrew is preinstalled on macOS runners) + run: brew --version + - name: Validate recipes (structure + brew resolution + strict links) + run: node scripts/validate-recipes.mjs --strict-links + - name: Confirm all bundles.json copies are in sync with recipes + run: | + git diff --exit-code bundles.json src-tauri/data/bundles.json native/Sources/BrewBrowserKit/Resources/bundles.json || { + echo "::error::A bundles.json copy is stale — run 'node scripts/validate-recipes.mjs' and commit the result (it writes all three copies)."; + exit 1; + } diff --git a/CONTRIBUTING-bundles.md b/CONTRIBUTING-bundles.md new file mode 100644 index 0000000..86182e2 --- /dev/null +++ b/CONTRIBUTING-bundles.md @@ -0,0 +1,35 @@ +# Contributing a Bundle recipe + +A **bundle** is a curated one-click stack (packages) with post-install guidance, capability-gated so it's only recommended on machines that can run it. Recipes are plain JSON files anyone can add via PR — no app code change needed for a valid recipe. + +## Add one in 4 steps +1. **Copy** an existing recipe as a starting point: + ``` + cp recipes/media.json recipes/my-bundle.json + ``` +2. **Edit** the fields (see the full contract: [`memory-bank/releases/0.7.0/bundles/recipe-contract.md`](memory-bank/releases/0.7.0/bundles/recipe-contract.md)). The essentials: + - `id` — kebab-case, unique, **stable** (it's the persistence key). + - `name`, `tagline`, `category` (`AI` | `Graphics` | `Media` | `Development` | `Data` | `Productivity`). + - `description` (optional) — a 2–4 sentence "intent" paragraph (what this bundle is / who it's for / why these tools), **distinct** from the short `tagline` and from `caveats`. 40–600 chars. + - `packages` — each `{ "name": "", "kind": "formula" | "cask" }`. **Must resolve via `brew info`.** If any package is in a third-party tap (not `homebrew/core`/`homebrew/cask`), set the top-level `"tap": "user/repo"`. + - `requires` (optional) — `minRamGB` / `recommendedRamGB` / `minDiskGB` / `arch` / `gpu`. Omit for "runs anywhere". See [`capability-baselines.md`](memory-bank/releases/0.7.0/bundles/capability-baselines.md) for how to pick numbers. + - `setup` (optional) — post-install steps. `service` / `open` / `reveal` run in-app; **`command` steps MUST set `"external": true`** and are copy-only (the app never runs arbitrary shell). + - `links` — further reading, **https only**. +3. **Validate locally** (needs Homebrew + Node 20+): + ``` + node scripts/validate-recipes.mjs # structure + brew resolution + links + node scripts/validate-recipes.mjs --strict-links # what CI runs + ``` + This also regenerates `bundles.json`. **Commit `bundles.json` along with your recipe.** +4. **Open a PR.** The `Validate Recipes` CI check runs the same validator and posts a pass/fail table. Green = mergeable. + +## The rules CI enforces +- Schema-valid; `id` unique + kebab-case. +- Every package resolves via `brew info` to its declared `kind`; third-party taps declared. +- `requires`: `minRamGB ≤ recommendedRamGB`, positive integers, valid `arch`/`gpu`. +- `command` setup steps are `external: true`; `open` urls are http(s). +- `links` are https and reachable (a real 4xx/5xx fails; a bot-block/TLS throw is a warning). +- `bundles.json` matches the recipes (regenerate + commit). + +## Scope +Bundles are **brew-installable stacks with guidance**. A recipe may not auto-run external commands, and a stack whose value is entirely non-brew won't be accepted. If part of the setup is external (a model download, a `docker run`), express it as a copy-only `command` step or a `note`. diff --git a/bundles.json b/bundles.json new file mode 100644 index 0000000..efb58b1 --- /dev/null +++ b/bundles.json @@ -0,0 +1,570 @@ +{ + "schemaVersion": 1, + "bundles": [ + { + "id": "agentic-web-dev", + "name": "Agentic Web Dev", + "tagline": "Terminal-first AI coding with opencode, Zed, and a real local server", + "description": "A terminal-first, AI-assisted web development environment. opencode is an open, model-agnostic coding agent — it works with Anthropic, OpenAI, Google, local Ollama, and dozens more — planning and editing across your whole project from the terminal. Zed is a Rust-native editor that opens instantly with built-in AI; Node and pnpm run and build your app, Git tracks changes, Caddy serves it locally over HTTPS, and OrbStack runs databases and services in fast containers. An agent does the heavy lifting while you keep a fast editor and a real local server.", + "category": "Development", + "icon": "agentic", + "packages": [ + { + "name": "opencode", + "kind": "formula" + }, + { + "name": "zed", + "kind": "cask" + }, + { + "name": "node", + "kind": "formula" + }, + { + "name": "pnpm", + "kind": "formula" + }, + { + "name": "git", + "kind": "formula" + }, + { + "name": "caddy", + "kind": "formula" + }, + { + "name": "orbstack", + "kind": "cask" + } + ], + "requires": { + "minRamGB": 8, + "recommendedRamGB": 16, + "minDiskGB": 8, + "arch": "apple-silicon", + "gpu": "none" + }, + "setup": [ + { + "kind": "note", + "text": "opencode needs a model/provider configured before first use — point it at Anthropic, OpenAI, Google, a local Ollama server, or any other supported provider." + }, + { + "kind": "command", + "run": "opencode auth login", + "label": "Configure an opencode provider (you run this)", + "external": true + }, + { + "kind": "note", + "text": "Caddy and OrbStack manage their own services — start Caddy from the Services tab and launch OrbStack to run containers." + } + ], + "caveats": "opencode requires a configured model/provider (API key or a local Ollama) — no provider is bundled. OrbStack is macOS-only and best on Apple Silicon.", + "links": [ + { + "label": "opencode", + "url": "https://opencode.ai" + }, + { + "label": "Zed", + "url": "https://zed.dev" + }, + { + "label": "Caddy", + "url": "https://caddyserver.com" + }, + { + "label": "OrbStack", + "url": "https://orbstack.dev" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "databases", + "name": "Local Databases", + "tagline": "PostgreSQL + Redis, managed as services", + "description": "A local relational + cache stack managed as background services. PostgreSQL is the default production-grade SQL database; Redis handles caching, queues, and sessions. Bundled GUI clients — TablePlus (Mac-native polish) and DBeaver (free and cross-platform) — let you browse tables, run queries, and inspect keys without living in the terminal. Start and stop the services from the Services tab; data grows on disk over time.", + "category": "Data", + "icon": "database", + "packages": [ + { + "name": "postgresql@16", + "kind": "formula" + }, + { + "name": "redis", + "kind": "formula" + }, + { + "name": "tableplus", + "kind": "cask" + }, + { + "name": "dbeaver-community", + "kind": "cask" + } + ], + "requires": { + "minRamGB": 4, + "recommendedRamGB": 8, + "minDiskGB": 5, + "arch": "any", + "gpu": "none" + }, + "setup": [ + { + "kind": "service", + "service": "postgresql@16", + "label": "Start PostgreSQL" + }, + { + "kind": "service", + "service": "redis", + "label": "Start Redis" + } + ], + "caveats": "Databases grow with your data. Manage start/stop from the Services tab.", + "links": [ + { + "label": "PostgreSQL", + "url": "https://www.postgresql.org" + }, + { + "label": "Redis", + "url": "https://redis.io" + }, + { + "label": "TablePlus", + "url": "https://tableplus.com" + }, + { + "label": "DBeaver", + "url": "https://dbeaver.io" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "graphics", + "name": "Graphics & Design", + "tagline": "Vector, raster, and digital painting — Inkscape, GIMP, Krita", + "description": "A complete open-source creative suite — vector, raster, and digital painting in three focused tools. Inkscape handles scalable vector art and SVG; GIMP 3.0 covers photo editing and compositing; Krita is a painter's canvas built for illustration and concept art. A capable, zero-cost alternative to the Adobe trio for design, illustration, and image work.", + "category": "Graphics", + "icon": "palette", + "packages": [ + { + "name": "inkscape", + "kind": "cask" + }, + { + "name": "gimp", + "kind": "cask" + }, + { + "name": "krita", + "kind": "cask" + } + ], + "caveats": "Three full desktop apps (~2–3 GB combined). Runs on any supported Mac.", + "links": [ + { + "label": "Inkscape", + "url": "https://inkscape.org" + }, + { + "label": "GIMP", + "url": "https://www.gimp.org" + }, + { + "label": "Krita", + "url": "https://krita.org" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "image-gen", + "name": "Image Generation", + "tagline": "Local Stable Diffusion / Flux with ComfyUI", + "description": "Generate images locally with Stable Diffusion, SDXL, and Flux — no cloud, no per-image cost. Draw Things is the fast, no-terminal, Apple-Silicon-native starting point; ComfyUI is the node-based workbench for complex, repeatable pipelines. Together they cover both 'type a prompt and go' and 'build a custom multi-stage workflow.' Models are large downloads you fetch yourself.", + "category": "AI", + "icon": "image", + "packages": [ + { + "name": "draw-things", + "kind": "cask" + }, + { + "name": "comfy", + "kind": "cask" + } + ], + "requires": { + "minRamGB": 16, + "recommendedRamGB": 24, + "minDiskGB": 30, + "arch": "apple-silicon", + "gpu": "required" + }, + "capabilityNotes": { + "16": "SDXL comfortably; Flux fp8 with offloading", + "24": "Flux fp8 comfortably", + "48": "Flux fp16" + }, + "setup": [ + { + "kind": "note", + "text": "Start with Draw Things for a no-terminal on-ramp; use ComfyUI when you need node-based pipelines. Either way you download checkpoint models yourself — they are NOT installed by brew (SDXL ~7 GB, Flux ~24 GB)." + }, + { + "kind": "command", + "run": "open -a \"Draw Things\"", + "label": "Launch Draw Things (you run this)", + "external": true + }, + { + "kind": "command", + "run": "open -a ComfyUI", + "label": "Launch ComfyUI (you run this)", + "external": true + } + ], + "caveats": "Installs the apps only — models (Stable Diffusion, SDXL, Flux) are large downloads you fetch and manage yourself.", + "links": [ + { + "label": "Draw Things", + "url": "https://drawthings.ai" + }, + { + "label": "ComfyUI (GitHub)", + "url": "https://github.com/comfyanonymous/ComfyUI" + }, + { + "label": "comfy.org", + "url": "https://www.comfy.org" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "lamp", + "name": "LAMP Stack", + "tagline": "Apache, MySQL, and PHP — the classic web server stack", + "description": "The classic web development stack: Apache serves your site, MySQL stores your data, and PHP runs your application code. It's the backbone of WordPress, Drupal, Laravel, and countless server-rendered apps — install all three as background services and you have a full local web server in one step. Best for PHP developers and anyone running or learning traditional web apps.", + "category": "Development", + "icon": "server", + "packages": [ + { + "name": "httpd", + "kind": "formula" + }, + { + "name": "mysql", + "kind": "formula" + }, + { + "name": "php", + "kind": "formula" + } + ], + "requires": { + "minRamGB": 4, + "recommendedRamGB": 8, + "minDiskGB": 5, + "arch": "any", + "gpu": "none" + }, + "setup": [ + { + "kind": "service", + "service": "httpd", + "label": "Start Apache (httpd)" + }, + { + "kind": "service", + "service": "mysql", + "label": "Start MySQL" + }, + { + "kind": "command", + "run": "mysql_secure_installation", + "label": "Secure your MySQL install (you run this)", + "external": true + }, + { + "kind": "note", + "text": "Enable PHP in Apache: add the PHP module to httpd.conf (LoadModule php_module …) and set a PHP handler, then restart Apache. See the PHP + Apache docs below." + } + ], + "caveats": "Apache and MySQL run as background services on your machine. PHP is wired into Apache via httpd.conf manually — follow the setup steps.", + "links": [ + { + "label": "Apache HTTP Server docs", + "url": "https://httpd.apache.org/docs/" + }, + { + "label": "PHP docs", + "url": "https://www.php.net/docs.php" + }, + { + "label": "MySQL docs", + "url": "https://dev.mysql.com/doc/" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "lemp", + "name": "LEMP Stack", + "tagline": "Nginx, MariaDB, and PHP-FPM — a fast, modern web stack", + "description": "A modern take on the classic web stack: Nginx serves your site with high concurrency, MariaDB (a drop-in MySQL replacement) stores your data, and PHP-FPM runs your application code. It's the go-to setup for Laravel, WordPress, and high-traffic PHP apps that want Nginx's performance. Install all three as background services for a fast local web server in one step.", + "category": "Development", + "icon": "server", + "packages": [ + { + "name": "nginx", + "kind": "formula" + }, + { + "name": "mariadb", + "kind": "formula" + }, + { + "name": "php", + "kind": "formula" + } + ], + "requires": { + "minRamGB": 4, + "recommendedRamGB": 8, + "minDiskGB": 5, + "arch": "any", + "gpu": "none" + }, + "setup": [ + { + "kind": "service", + "service": "nginx", + "label": "Start Nginx" + }, + { + "kind": "service", + "service": "mariadb", + "label": "Start MariaDB" + }, + { + "kind": "service", + "service": "php", + "label": "Start PHP-FPM" + }, + { + "kind": "command", + "run": "mariadb-secure-installation", + "label": "Secure your MariaDB install (you run this)", + "external": true + }, + { + "kind": "note", + "text": "Wire PHP-FPM into Nginx: add a fastcgi_pass (e.g. 127.0.0.1:9000) to your server block, then reload Nginx. See the Nginx + PHP-FPM docs below." + } + ], + "caveats": "Nginx, MariaDB, and PHP-FPM run as background services. PHP-FPM must be wired into your Nginx server block manually — follow the setup steps.", + "links": [ + { + "label": "Nginx docs", + "url": "https://nginx.org/en/docs/" + }, + { + "label": "PHP-FPM docs", + "url": "https://www.php.net/manual/en/install.fpm.php" + }, + { + "label": "MariaDB docs", + "url": "https://mariadb.org/documentation/" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "local-llm", + "name": "Local LLMs", + "tagline": "Run models locally with Ollama + a web UI", + "description": "Run open-weight models entirely on your own machine — private, offline-capable, no API bills. Ollama pulls and serves models with one command and exposes an OpenAI-compatible API on localhost:11434; Open WebUI adds a polished browser chat UI on top. Best for developers and privacy-conscious users who want ChatGPT-style workflows without sending data to the cloud.", + "category": "AI", + "icon": "brain", + "packages": [ + { + "name": "ollama", + "kind": "formula" + }, + { + "name": "open-webui", + "kind": "cask" + } + ], + "requires": { + "minRamGB": 8, + "recommendedRamGB": 16, + "minDiskGB": 12, + "arch": "any", + "gpu": "preferred" + }, + "capabilityNotes": { + "8": "Small (~7–8B Q4) models only; larger will swap", + "16": "13–14B models comfortably", + "24": "26–32B class (Qwen, Gemma)", + "48": "70B models" + }, + "setup": [ + { + "kind": "service", + "service": "ollama", + "label": "Start the Ollama server" + }, + { + "kind": "command", + "run": "ollama pull llama3.2", + "label": "Pull a starter model (you run this)", + "external": true + }, + { + "kind": "open", + "url": "http://localhost:8080", + "label": "Open Open WebUI" + } + ], + "caveats": "Installs the tools; you still download models yourself (several GB each). Apple Silicon unified memory counts as VRAM — more RAM = bigger models.", + "links": [ + { + "label": "Ollama docs", + "url": "https://docs.ollama.com" + }, + { + "label": "Open WebUI", + "url": "https://openwebui.com" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "media", + "name": "Media Toolkit", + "tagline": "Transcode, download, and play — ffmpeg, yt-dlp, mpv", + "description": "A complete command-line media pipeline. FFmpeg transcodes and streams virtually any format, yt-dlp downloads audio and video from thousands of sites, and mpv plays it all with scriptable precision. HandBrake adds one-command, preset-based encoding (like 'Fast 1080p30') when you don't want to hand-write ffmpeg filter graphs. Lightweight and runs on any Mac or Linux box.", + "category": "Media", + "icon": "clapperboard", + "packages": [ + { + "name": "ffmpeg", + "kind": "formula" + }, + { + "name": "yt-dlp", + "kind": "formula" + }, + { + "name": "mpv", + "kind": "formula" + }, + { + "name": "handbrake", + "kind": "formula" + } + ], + "setup": [ + { + "kind": "command", + "run": "ffmpeg -version", + "label": "Verify ffmpeg (you run this)", + "external": true + } + ], + "caveats": "Command-line tools. Lightweight; runs on any supported Mac or Linux.", + "links": [ + { + "label": "FFmpeg", + "url": "https://ffmpeg.org" + }, + { + "label": "yt-dlp", + "url": "https://github.com/yt-dlp/yt-dlp" + }, + { + "label": "mpv", + "url": "https://mpv.io" + }, + { + "label": "HandBrake", + "url": "https://handbrake.fr" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + }, + { + "id": "web-dev", + "name": "Web Dev Starter", + "tagline": "Node.js + pnpm — the modern JS toolchain", + "description": "Everything you need to clone a repo, install dependencies, and push your first commit — the modern JavaScript baseline. Node.js is the safe-default runtime and pnpm is the fast, disk-efficient package manager; Git and the GitHub CLI cover version control, pull requests, and Actions from the terminal. For an AI-assisted, agent-driven setup, see the Agentic Web Dev bundle.", + "category": "Development", + "icon": "code", + "packages": [ + { + "name": "node", + "kind": "formula" + }, + { + "name": "pnpm", + "kind": "formula" + }, + { + "name": "git", + "kind": "formula" + }, + { + "name": "gh", + "kind": "formula" + } + ], + "setup": [ + { + "kind": "command", + "run": "node -v && pnpm -v && git -v && gh --version", + "label": "Verify the toolchain (you run this)", + "external": true + } + ], + "caveats": "Installs the runtimes; project dependencies are per-project (pnpm install).", + "links": [ + { + "label": "Node.js", + "url": "https://nodejs.org" + }, + { + "label": "pnpm", + "url": "https://pnpm.io" + }, + { + "label": "Git", + "url": "https://git-scm.com" + }, + { + "label": "GitHub CLI", + "url": "https://cli.github.com" + } + ], + "maintainer": "brew-browser", + "addedIn": "0.7.0" + } + ] +} diff --git a/memory-bank/releases/0.7.0/README.md b/memory-bank/releases/0.7.0/README.md new file mode 100644 index 0000000..4c1b5bc --- /dev/null +++ b/memory-bank/releases/0.7.0/README.md @@ -0,0 +1,84 @@ +# Release 0.7.0 / native 0.3.0 + +**Status:** 🚧 In progress — contents on `main` (unreleased), headline feature (Bundles) in planning. +**Baseline:** 0.6.0 / native 0.2.0 (tag `v0.6.0`). +**Version step:** minor — new user-facing feature (pin/unpin; Bundles to follow). Split-track per [decisions.md](../../decisions.md): Tauri/web (+Linux) `0.6.0 → 0.7.0`, native macOS `0.2.0 → 0.3.0`. Same feature set under two numbers; release notes state the equivalence ("native 0.3.0 ≙ Tauri 0.7.0"). Single git tag `v0.7.0`. + +> Directory named `0.7.0` (primary/Tauri version); native carries `0.3.0`. + +--- + +## What's in it (merged to `main` since `v0.6.0`) + +Grouped by theme; every item is a merged PR on `main` unless marked. + +### Headline feature +- **Pin / unpin packages (#141)** — hold a package back from "Update all", both shells, formulae **and** casks. Closes **#90**, **#134**. Includes the Library panel refresh: **Pinned** filter tab, per-tab counts removed, bottom status bar (leads with the active filter's count), cask-aware `pinnedCount`. + +### In-app brew control (pre-session, on main) +- **In-app command options (#109)** — reactive recovery UI (adopt/overwrite/force-remove) + Advanced disclosure (greedy upgrade, autoremove). Addresses #98 (reactive), #47, #13, #102, #100. +- **Doctor + Cleanup (#82, #83)** — `brew doctor` + `brew cleanup --prune=all` on the Storage card; `--scrub` opt-in (default off). Issue #80. + +### Vulnerability scanning hardening +- **Exposure parity + GHSA enrichment port (#107)** — native gains `source: live/cache` label + `VulnsEnrich`; fixes the Tauri over-count (`replace_full_scan`); unified card wording. +- **Vuln scan tap-names + JSON salvage (#103)** — #62/#92: accept tap-qualified formula names, salvage JSON from banner noise. + Homebrew-analytics privacy env. +- **Native catalog empty-response guard (#108)** — parity with #101. +- **GHSA advisory `references` shape (#110)** — ✅ merged 2026-07-12. Repairs enrichment (references are a string array, not `[{url}]`; was a silent no-op). Verified end-to-end (live fetch = `Some` with 9 refs). + +### UX / correctness fixes (this session) +- **Native list scales, no sidebar clip (#142)** — content-column min widths fit the 420pt floor. +- **Install-trend sparkline scale (#143)** — stop mixing `count30d` (cumulative) with `estimatedDailyInstalls` (daily); kills the cliff artifact. Both shells. +- **Tauri vulnerable-footer nav (#144)** — footer jumps to Library → Vulnerable (was Dashboard). Parity. +- **Native outdated tap-name undercount (#145)** — tap-installed outdated packages were dropped from the Outdated filter (Swift 8 vs Tauri 9); normalized via `bareToken`. Same tap-name class as #92. + +### Community / upstream +- **Catalog reject-empty-response (#101, @Arvuno)** — reviewed + merged. + +### Report hygiene + docs +- **Report-button brew-vs-app gating (#91)** — the report button shows only for genuine app errors, stopping misfiled `[brew-browser] X failed` issues at the source. +- Docs: #94 (memory-bank session), #93 (landing favicon), #86 (tap-trust install docs), #84 (credit @modeezie), #77 (version-wrap + native release tooling). + +--- + +## Headline feature — Bundles / Recipes (BUILT + refined 2026-07-13) +Curated **one-click package stacks** with post-install setup guidance, **capability-gated** by a zero-install system profile (RAM/arch/GPU/disk) so an 8GB Mac isn't told to install a local-LLM stack it can't run. "Bundles" nav section; brew-native install auto-runs, external steps (model pulls, etc.) are copy-paste. Both shells. **Contributor-friendly:** recipes are validated JSON files anyone can PR against a published contract. + +**Plan docs (2026-07-12):** overview in **[bundles-plan.md](./bundles-plan.md)**; contributor contract + July-2026 capability baselines + 5 milestone build docs under **[`bundles/`](./bundles/)**: +- [recipe-contract.md](./bundles/recipe-contract.md) · [capability-baselines.md](./bundles/capability-baselines.md) +- M1 [capability-engine](./bundles/m1-capability-engine.md) → M2 [contract-and-loader](./bundles/m2-recipe-contract-and-loader.md) → M3 [browse-and-install](./bundles/m3-browse-and-install.md) → M4 [setup-guidance](./bundles/m4-setup-guidance.md) → M5 [live-refresh-and-contributions](./bundles/m5-live-refresh-and-contributions.md) + +**Post-M5 refinement (2026-07-13, this session, both shells):** +- **List + Details pane** — Bundles moved from a card-grid + modal to the app's canonical master-list + right-side Details pane (matches Library/Trending exactly: no auto-select, pane closed on entry, ✕/section-switch closes). Tauri = shell-level resizable `