mirror of
https://github.com/abusoww/tuxmate.git
synced 2026-04-17 15:53:24 +02:00
444 lines
17 KiB
Markdown
444 lines
17 KiB
Markdown
# Contributing to TuxMate
|
|
|
|
## Quick Navigation
|
|
|
|
1. [Project Overview](#project-overview)
|
|
2. [Development Workflow](#development-workflow)
|
|
* [Initial Setup](#initial-setup)
|
|
* [Running with Docker](#running-with-docker)
|
|
* [Quality Assurance](#quality-assurance)
|
|
* [Verifying Install Scripts](#verifying-install-scripts)
|
|
3. [Adding Applications](#adding-applications)
|
|
* [Research Protocol](#1-mandatory-research-protocol)
|
|
* [Entry Structure](#2-entry-structure)
|
|
* [Unavailable Reason](#3-unavailable-reason-guidelines)
|
|
* [Platform Rules](#4-platform-specific-rules)
|
|
* [Arch Linux](#arch-linux)
|
|
* [NixOS](#nixos)
|
|
* [Ubuntu/Debian](#ubuntudebian)
|
|
* [Flatpak](#flatpak)
|
|
* [Snap](#snap)
|
|
* [Homebrew](#homebrew)
|
|
* [Universal Targets](#universal-targets-npm--script)
|
|
* [Icon System](#5-icon-system)
|
|
* [Valid Categories](#6-valid-categories)
|
|
4. [Adding Distributions](#adding-distributions)
|
|
5. [Pull Request Checklist](#pull-request-checklist)
|
|
* [Core Principles](#core-principles)
|
|
* [Verification Steps](#verification-steps)
|
|
6. [Templates](#templates)
|
|
* [Pull Request](#pull-request-template)
|
|
* [Bug Report](#issue-template-bug-report)
|
|
|
|
---
|
|
|
|
## Project Overview
|
|
|
|
* `src/lib/apps/*.json`: Main registry for applications (split by category).
|
|
* `src/lib/data.ts`: Main registry for distributions, categories, and Typescript types.
|
|
* `src/lib/aur-packages.json`: Whitelist for AUR packages that lack standard suffixes.
|
|
* `src/lib/nix-unfree.json`: Registry for unfree Nix packages.
|
|
* `src/lib/verified-flatpaks.json`: Auto-generated list of verified Flathub apps. **Do not edit.**
|
|
* `src/lib/verified-snaps.json`: Manual whitelist of verified Snap publishers.
|
|
|
|
---
|
|
|
|
## Development Workflow
|
|
|
|
### Initial Setup
|
|
|
|
```bash
|
|
git clone https://github.com/abusoww/tuxmate.git
|
|
cd tuxmate
|
|
npm install
|
|
npm run dev
|
|
```
|
|
The app will be available at `http://localhost:3000`.
|
|
|
|
<a id="running-with-docker"></a>
|
|
<details>
|
|
<summary>Running with Docker</summary>
|
|
|
|
You can run the full application using the official Docker image:
|
|
|
|
```bash
|
|
docker run -p 3000:80 ghcr.io/abusoww/tuxmate:latest
|
|
```
|
|
</details>
|
|
|
|
<a id="quality-assurance"></a>
|
|
<details>
|
|
<summary>Quality Assurance</summary>
|
|
|
|
Always run these before pushing:
|
|
* `npm run lint`: Check for code style issues.
|
|
* `npm run test`: Run unit test suite.
|
|
* `npm run build`: Verify production build.
|
|
</details>
|
|
|
|
<a id="verifying-install-scripts"></a>
|
|
<details>
|
|
<summary>Verifying Install Scripts</summary>
|
|
|
|
To verify that the *scripts generated by TuxMate* work correctly, run them in a clean container environment. This prevents messing up your local system.
|
|
|
|
1. Generate a script in the TuxMate UI (Dev mode).
|
|
2. Copy the script.
|
|
3. Run the corresponding distro container commands below and paste the script.
|
|
|
|
```bash
|
|
# Arch Linux
|
|
docker run -it --rm archlinux:latest bash -c "pacman -Sy && bash"
|
|
|
|
# Ubuntu
|
|
docker run -it --rm ubuntu:latest bash -c "apt update && bash"
|
|
|
|
# Fedora
|
|
docker run -it --rm fedora:latest bash -c "dnf check-update; bash"
|
|
```
|
|
</details>
|
|
|
|
---
|
|
|
|
## Adding Applications
|
|
|
|
All applications are defined in category-specific JSON files within [`src/lib/apps/`](src/lib/apps/).
|
|
|
|
### 1. Mandatory Research Protocol
|
|
|
|
**You MUST verify every package on these official sources before submitting:**
|
|
|
|
| Source | Scope | URL |
|
|
| :--- | :--- | :--- |
|
|
| **Repology** | Global Index | [repology.org](https://repology.org/) |
|
|
| **Arch Linux** | Official Repos | [archlinux.org/packages](https://archlinux.org/packages/) |
|
|
| **AUR** | User Repo | [aur.archlinux.org](https://aur.archlinux.org/) |
|
|
| **Debian** | Official Repos | [packages.debian.org](https://packages.debian.org/) |
|
|
| **Ubuntu** | Official Repos | [packages.ubuntu.com](https://packages.ubuntu.com/) |
|
|
| **Fedora** | Official Repos | [packages.fedoraproject.org](https://packages.fedoraproject.org/) |
|
|
| **OpenSUSE** | Official Repos | [software.opensuse.org](https://software.opensuse.org/) |
|
|
| **Nix** | Nixpkgs | [search.nixos.org](https://search.nixos.org/packages) |
|
|
| **Flathub** | Flatpaks | [flathub.org](https://flathub.org/) |
|
|
| **Snapcraft** | Snaps | [snapcraft.io](https://snapcraft.io/) |
|
|
| **Homebrew** | CLI & Casks | [formulae.brew.sh](https://formulae.brew.sh/) |
|
|
|
|
### 2. Entry Structure
|
|
|
|
```json
|
|
{
|
|
"id": "app-id", // Unique, lowercase, kebab-case
|
|
"name": "App Name", // Official display name
|
|
"description": "Short description", // Max ~60 characters
|
|
"category": "Category", // Must match valid categories
|
|
"icon": { // See Icon System section
|
|
"type": "iconify",
|
|
"set": "simple-icons",
|
|
"name": "python",
|
|
"color": "#3776AB"
|
|
},
|
|
"targets": {
|
|
"ubuntu": "exact-package-name", // apt package (official repos ONLY)
|
|
"arch": "exact-package-name", // pacman OR AUR package name
|
|
"flatpak": "com.vendor.AppId", // FULL Flatpak App ID (reverse DNS)
|
|
"snap": "snap-name", // Add --classic if needed
|
|
"homebrew": "formula-name", // Formula (CLI) or '--cask name' (GUI)
|
|
"npm": "@scope/package-name", // Global npm install (universal fallback)
|
|
"script": "curl -fsSL ... | bash" // Custom install script (universal fallback)
|
|
},
|
|
"note": "Context for universal targets", // Shown on hover for universal-fallback apps
|
|
"unavailableReason": "Markdown install instructions"
|
|
}
|
|
```
|
|
|
|
> [!NOTE]
|
|
> **Priority system**: Native distro targets (e.g., `arch`, `ubuntu`) always take precedence over universal targets (`npm`, `script`). If an app has both `arch: "ollama"` and `script: "curl ..."`, the script is only used when the user selects a distro where no native package exists.
|
|
|
|
### 3. Unavailable Reason Guidelines
|
|
|
|
This field renders Markdown when a target is missing. It serves as the manual fallback instruction.
|
|
|
|
**Requirements:**
|
|
1. **Actionable**: Avoid "Not available". State the alternative (e.g., "Install via Flatpak").
|
|
2. **Linked**: Hard-link the solution (Flathub page, upstream .deb URL, or Wiki guide).
|
|
3. **Format**: Use standard Markdown for links `[text](url)` and code `` `cmd` ``.
|
|
|
|
**Examples:**
|
|
|
|
| Status | Message | Why? |
|
|
| :--- | :--- | :--- |
|
|
| ❌ **Bad** | `'Not available.'` | Dead end. No solution provided. |
|
|
| ❌ **Bad** | `'Download from website.'` | Dead end. No solution provided. |
|
|
| ✅ **Good** | `'Not in official repos. Use the [Flatpak version](https://flathub.org/apps/com.spotify.Client) instead.'` | Directs to the preferred supported alternative. |
|
|
| ✅ **Good** | ```'Arch requires [multilib](https://wiki.archlinux.org/title/Official_repositories#multilib) enabled: uncomment `[multilib]` in `/etc/pacman.conf`, run `sudo pacman -Syu`, then `sudo pacman -S steam`.'``` | Exact steps to enable the required repo. |
|
|
|
|
### 4. Platform Specific Rules
|
|
|
|
#### Arch Linux
|
|
* **Official Packages**: Use the package name directly if found in `core` or `extra` (e.g., `firefox`).
|
|
* **Automatic AUR Detection**: `src/lib/aur.ts` automatically detects suffixes `-bin`, `-git`, or `-appimage`. Use the name directly (e.g., `brave-bin`).
|
|
* **Manual AUR Detection**: For AUR packages without suffixes (e.g., `google-chrome`), **you must add the name to** `src/lib/aur-packages.json`.
|
|
* Prefer `-bin` suffix packages in AUR (pre-built, faster install)
|
|
|
|
#### NixOS
|
|
Nixpkgs requires explicit user consent for unfree software.
|
|
1. Check the license on [search.nixos.org](https://search.nixos.org/packages).
|
|
2. If the license is unfree, add it to `src/lib/nix-unfree.json` if missing.
|
|
3. Add the package to the appropriate JSON file in `src/lib/apps/` normally.
|
|
|
|
#### Ubuntu/Debian
|
|
**Strict Repository Policy**: The generation scripts do **not** enable extra repositories (like PPAs or `non-free` by default). Packages must be available in the standard enabled repositories.
|
|
|
|
* **Allowed**:
|
|
* **Ubuntu**: Main, Restricted
|
|
* **Debian**: Main
|
|
* **Prohibited**:
|
|
* PPAs (Personal Package Archives).
|
|
* External `.deb` URLs.
|
|
* Packages requiring manual `sources.list` modification (unless detailed in `unavailableReason`).
|
|
|
|
#### Flatpak
|
|
* **ID Format**: Always use the full **Application ID** (reverse-DNS style).
|
|
* ✅ Correct: `org.mozilla.firefox`
|
|
* ❌ Wrong: `firefox`
|
|
* **Verification**: Find the exact ID at the bottom of the app's [Flathub page](https://flathub.org/).
|
|
* **Note**: `verified-flatpaks.json` is auto-generated; do not edit it manually.
|
|
|
|
#### Snap
|
|
* **Classic Confinement**: If the snap requires classic confinement (access to host system files), append `--classic`.
|
|
* Example: `code --classic`
|
|
* Check the install command on [snapcraft.io](https://snapcraft.io/) to confirm.
|
|
* **Verification**: If the publisher has a **"Verified" badge** on [Snapcraft](https://snapcraft.io/):
|
|
* Add the **publisher name** to `src/lib/verified-snaps.json`.
|
|
* This enables the "Verified" badge in the TuxMate UI.
|
|
|
|
#### Homebrew
|
|
Homebrew (macOS/Linux) has two package types. Check [formulae.brew.sh](https://formulae.brew.sh/) to find the correct one.
|
|
|
|
* **Formula**: Standard CLI tools and libraries.
|
|
* Usage: Use the package name directly.
|
|
* Example: `'wget'`, `'node'`, `'python@3.12'`
|
|
* **Cask**: GUI applications and large binaries (macOS only).
|
|
* Usage: Prefix with `--cask ` (note the space).
|
|
* Example: `'--cask firefox'`, `'--cask visual-studio-code'`
|
|
* **Validation**:
|
|
* Run `brew search <name>` locally to confirm type.
|
|
* We skip `--cask` targets on Linux installs automatically.
|
|
|
|
#### Universal Targets (npm & script)
|
|
|
|
Universal targets provide cross-distro installation via package managers or custom scripts. They serve as **fallbacks** — only used when no native distro target exists for the selected distribution.
|
|
|
|
* **`npm`**: Install via `npm install -g`. Requires Node.js runtime on the system.
|
|
* **`script`**: Raw shell command (typically a `curl | bash` installer). Runs directly.
|
|
|
|
> [!IMPORTANT]
|
|
> **Native targets always take priority.** If an app defines `arch: "ollama"` alongside `script: "curl ..."`, the script target is completely ignored when Arch is selected. The fallback only activates for distros without a native package.
|
|
|
|
**When to use each:**
|
|
|
|
| Target | Use Case | Example |
|
|
| :--- | :--- | :--- |
|
|
| `npm` | CLI tools distributed via npmjs.com | `"npm": "@google/gemini-cli"` |
|
|
| `script` | Apps with official install scripts | `"script": "curl -fsSL https://ollama.com/install.sh \| sh"` |
|
|
|
|
**Real examples from the codebase:**
|
|
|
|
```json
|
|
// Ollama: native on arch/fedora/nix/homebrew, falls back to script on ubuntu/debian
|
|
{
|
|
"id": "ollama",
|
|
"targets": {
|
|
"fedora": "ollama",
|
|
"arch": "ollama",
|
|
"nix": "ollama",
|
|
"homebrew": "ollama",
|
|
"script": "curl -fsSL https://ollama.com/install.sh | sh"
|
|
},
|
|
"note": "Falls back to official installer (ollama.com/install.sh) on distros without a native package."
|
|
}
|
|
|
|
// Gemini CLI: npm-only (plus homebrew)
|
|
{
|
|
"id": "gemini-cli",
|
|
"targets": {
|
|
"npm": "@google/gemini-cli",
|
|
"homebrew": "gemini-cli"
|
|
},
|
|
"note": "Requires Node.js runtime. Installed globally via npm where native packages are unavailable."
|
|
}
|
|
```
|
|
|
|
**The `note` field:**
|
|
* Used to explain the universal target behavior to users (shown on hover).
|
|
* **Required** when using `npm` or `script` targets.
|
|
* Keep concise and professional. Examples:
|
|
* ✅ `"Falls back to official installer (ollama.com/install.sh) on distros without a native package."`
|
|
* ✅ `"Requires Node.js runtime. Installed globally via npm where native packages are unavailable."`
|
|
* ❌ `"Installed globally via npm."` *(too terse, doesn't explain when or why)*
|
|
|
|
**Script safety rules:**
|
|
1. Only use **official** installer scripts from the app's own domain.
|
|
2. Always use `curl -fsSL` flags (fail silently on errors, follow redirects, show errors).
|
|
3. Never combine multiple pipes or add `sudo` — the install script handles privileges itself.
|
|
4. Verify the script URL is stable and maintained by the upstream project.
|
|
|
|
### 5. Icon System
|
|
|
|
Every app needs an icon! Our JSON format makes it super simple to add icons using [Iconify](https://iconify.design/).
|
|
|
|
We store icons as structured objects in the JSON. You just need to provide the set, name, and color:
|
|
```json
|
|
"icon": {
|
|
"type": "iconify",
|
|
"set": "simple-icons",
|
|
"name": "python",
|
|
"color": "#3776AB"
|
|
}
|
|
```
|
|
|
|
#### The 3 Main Icon Sets We Use:
|
|
1. **Simple Icons** (`"set": "simple-icons"`)
|
|
* Used for major brands and single-color logos (like Discord or Python).
|
|
* *You must provide a hex `"color"` for these.*
|
|
2. **Logos** (`"set": "logos"`)
|
|
* Used when an app has a multi-colored, official logo.
|
|
* *You don't need a `"color"` for these.*
|
|
3. **Material Design** (`"set": "mdi"`)
|
|
* Used for generic utilities (like a terminal or a magnifying glass).
|
|
* *You must provide a hex `"color"` for these.*
|
|
|
|
#### Can't find it on Iconify?
|
|
If an app's icon isn't on Iconify, you can use a direct link to an image (SVG preferred, or a high-res PNG).
|
|
Just change the `"type"` to `"url"`:
|
|
```json
|
|
"icon": {
|
|
"type": "url",
|
|
"url": "https://raw.githubusercontent.com/..."
|
|
}
|
|
```
|
|
* ✅ **DO:** Use a stable link (like the app's official GitHub repo raw image, or Wikimedia).
|
|
* ❌ **DON'T:** Use temporary image hosts (like Imgur) or hotlink-protected websites.
|
|
|
|
### 6. Valid Categories
|
|
|
|
Use **exactly** one of these:
|
|
* Web Browsers • Communication • Media • Creative • Gaming • Office
|
|
* Dev: Languages • Dev: Editors • Dev: Tools
|
|
* Terminal • CLI Tools • AI Tools • VPN & Network • Security • File Sharing • System
|
|
|
|
---
|
|
|
|
## Adding Distributions
|
|
|
|
Adding a new distribution involves three main steps:
|
|
|
|
### 1. Register the Distribution
|
|
Edit [`src/lib/data.ts`](src/lib/data.ts):
|
|
1. Add the new ID to the `DistroId` type definition.
|
|
2. Add a new object to the `distros` array with:
|
|
* `id`: unique identifier.
|
|
* `name`: Display name.
|
|
* `iconUrl`: Icon for the distro selector.
|
|
* `color`: Brand color.
|
|
* `installPrefix`: The default command prefix (e.g., `sudo dnf install -y`).
|
|
|
|
### 2. Create the Generator Script
|
|
Create a new file `src/lib/scripts/<distroId>.ts`. This file must export a function (e.g., `generateFedoraScript`) that takes `PackageInfo[]` and returns the generated shell script string.
|
|
* Use helpers from `shared.ts` like `generateAsciiHeader` and `PackageInfo`.
|
|
* Implement logic to check if a package is already installed.
|
|
* Implement the installation command loop using `with_retry` for robustness.
|
|
* See `src/lib/scripts/fedora.ts` or `ubuntu.ts` for clean examples.
|
|
|
|
### 3. Integrate the Generator
|
|
1. Export your new function in [`src/lib/scripts/index.ts`](src/lib/scripts/index.ts).
|
|
2. Import it in [`src/lib/generateInstallScript.ts`](src/lib/generateInstallScript.ts).
|
|
3. Add a case for your `distroId` in the `switch` statement inside `generateInstallScript`.
|
|
4. Also add the simple one-liner command logic in `generateSimpleCommand` within the same file.
|
|
|
|
---
|
|
|
|
## 🔀 Pull Request Checklist
|
|
|
|
### Core Principles
|
|
|
|
> [!IMPORTANT]
|
|
> **Your PR will be rejected if you violate these rules:**
|
|
>
|
|
> 1. **Verify Everything**: Submit only verified package names. Guessing is prohibited.
|
|
> 2. **Official First**: Use official repository packages over third-party options.
|
|
> 3. **No Unofficial Repos**: Do not include PPAs, COPRs, or unofficial repositories.
|
|
> 4. **Full IDs**: Use full IDs for Flatpaks (e.g., `org.mozilla.firefox`).
|
|
> 5. **Strict Casing**: Package names are case-sensitive.
|
|
> 6. **Link Integrity**: Ensure all links in `unavailableReason` are direct and working.
|
|
|
|
### Verification Steps
|
|
**Verify before submitting:**
|
|
- [ ] Package names verified on official search pages (Repology, Arch, etc).
|
|
- [ ] Case sensitivity checked (especially openSUSE).
|
|
- [ ] Arch packages verified (Official vs AUR).
|
|
- [ ] No PPAs used for Debian/Ubuntu; Main/Universe only.
|
|
- [ ] Flatpak IDs are full reverse-DNS style.
|
|
- [ ] Snap `--classic` flag verification.
|
|
- [ ] Nix unfree packages added to JSON.
|
|
- [ ] Homebrew Casks prefixed correctly.
|
|
- [ ] Universal targets: `npm`/`script` only used as fallbacks, `note` field provided.
|
|
- [ ] Script URLs verified as official, stable endpoints.
|
|
- [ ] `npm run lint` & `npm run test` passed.
|
|
|
|
---
|
|
|
|
## 📝 Templates
|
|
|
|
### Pull Request Template
|
|
|
|
```markdown
|
|
## Summary
|
|
Brief description of changes.
|
|
|
|
## Changes
|
|
| App Name | Category | Sources |
|
|
|----------|----------|---------|
|
|
| Example | Dev: Tool| apt, pacman |
|
|
|
|
## Verification
|
|
> Package names verified against official sources.
|
|
|
|
| Source | Link |
|
|
|--------|------|
|
|
| Repology | [Link](...) |
|
|
| Arch | [Link](...) |
|
|
| ... | ... |
|
|
|
|
## Testing
|
|
- [ ] `npm run dev` working
|
|
- [ ] `npm run build` passed
|
|
- [ ] `npm run test` passed
|
|
- [ ] `npm run lint` passed
|
|
|
|
|
|
## Screenshots (if applicable)
|
|
|
|
<!-- Add screenshots for UI changes -->
|
|
|
|
```
|
|
|
|
### Issue Template (Bug Report)
|
|
|
|
```markdown
|
|
## 🐛 Bug Report
|
|
|
|
**Environment**:
|
|
- OS: [e.g. Arch Linux]
|
|
- Browser: [e.g. Firefox 120]
|
|
|
|
**Steps to Reproduce**:
|
|
1. ...
|
|
2. ...
|
|
|
|
**Details**:
|
|
|
|
|
|
**Logs/Screenshots**:
|
|
[Paste console logs or attach screenshots]
|
|
```
|