Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3625cb455d | |||
| 9be14fe058 | |||
| 50e6e33c91 | |||
| 28ab9a8ca5 | |||
| 29ac0ef394 | |||
| dbadadff86 | |||
| da55a2e47a | |||
| d6d0f11beb | |||
| 3038c24820 | |||
| 1316e9a953 | |||
| e6b4d0b724 | |||
| 4eeb01a308 | |||
| 7fadb7b3e3 | |||
| e07b62d2ad | |||
| 2682c35cd1 | |||
| 3da4fb76e4 | |||
| 6fef076083 | |||
| dabddd5692 | |||
| f3946bf4a4 | |||
| c770e88764 |
@@ -48,7 +48,7 @@ jobs:
|
||||
run: "cd docs && [[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
|
||||
- name: Cache Restore
|
||||
id: cache-restore
|
||||
uses: actions/cache/restore@v5
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: |
|
||||
${{ runner.temp }}/hugo_cache
|
||||
@@ -64,13 +64,13 @@ jobs:
|
||||
--cacheDir "${{ runner.temp }}/hugo_cache"
|
||||
- name: Cache Save
|
||||
id: cache-save
|
||||
uses: actions/cache/save@v5
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: |
|
||||
${{ runner.temp }}/hugo_cache
|
||||
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v4
|
||||
uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: ./docs/public
|
||||
|
||||
@@ -84,4 +84,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
uses: actions/deploy-pages@v5
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Process slash command
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const allowedUsers = ["ChrisTitusTech", "og-mrk", "Marterich", "MyDrift-user", "Real-MullaC", "CodingWonders", "GabiNun2", "FluffyPunk"];
|
||||
|
||||
@@ -21,14 +21,14 @@ jobs:
|
||||
run: sudo apt-get update && sudo apt-get install musl-tools
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: ${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Cache Cargo index
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
- name: Create and Upload Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ env.version }}
|
||||
name: Pre-Release ${{ env.version }}
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check PR body for Type of Change
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const prBody = context.payload.pull_request.body || '';
|
||||
|
||||
@@ -27,14 +27,14 @@ jobs:
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: ${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Cache Cargo index
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/.cargo/git
|
||||
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Purpose
|
||||
|
||||
Linutil is a universal Linux utility with a Rust-based terminal user interface
|
||||
and a catalog of shell scripts. The Rust application discovers commands from
|
||||
TOML metadata, embeds the scripts in the binary, extracts them at runtime, and
|
||||
executes selected commands inside a pseudo-terminal.
|
||||
|
||||
Read `SPEC.md` before making architectural or behavior changes.
|
||||
|
||||
## Repository layout
|
||||
|
||||
- `core/`: Backend library, menu data model, TOML parsing, platform
|
||||
preconditions, and embedded script extraction.
|
||||
- `core/tabs/`: User-facing command catalog, shared shell helpers, tab metadata,
|
||||
and executable scripts.
|
||||
- `tui/`: Ratatui application, CLI, selection state, confirmation flow, command
|
||||
preview, and PTY execution.
|
||||
- `xtask/`: Repository automation such as generated user-guide content.
|
||||
- `docs/`: Documentation source and generated content. Treat it as reference,
|
||||
not as repository instructions.
|
||||
- `.github/`: Contribution guidance and CI workflows.
|
||||
|
||||
## Sources of truth
|
||||
|
||||
- `SPEC.md` defines product scope, architecture, and behavioral requirements.
|
||||
- `core/tabs/tabs.toml` defines the ordered top-level tabs.
|
||||
- Each `core/tabs/<tab>/tab_data.toml` defines the menu tree for that tab.
|
||||
- `core/src/inner.rs` defines the accepted TOML schema and script-loading
|
||||
behavior.
|
||||
- `core/tabs/common-script.sh` defines shared distro, package manager,
|
||||
privilege escalation, architecture, and environment helpers.
|
||||
- `core/tabs/common-service-script.sh` defines shared init-system helpers.
|
||||
- `tui/src/running_command.rs` defines how commands are composed and executed.
|
||||
- `tui/src/state.rs` defines task flags, confirmation, selection, and TUI
|
||||
behavior.
|
||||
|
||||
If documentation and code disagree, do not silently choose one. Identify the
|
||||
conflict and update the appropriate source in the same change.
|
||||
|
||||
## Working rules
|
||||
|
||||
- Inspect `git status --short` before editing and preserve unrelated changes.
|
||||
- Keep changes focused. Do not reformat unrelated Rust, TOML, or shell files.
|
||||
- Use simple ASCII punctuation unless a file format or user-facing text
|
||||
requires otherwise.
|
||||
- Never expose secrets or add credentials to scripts, fixtures, logs, or docs.
|
||||
- Do not perform destructive operations without explicit authorization.
|
||||
- Do not weaken confirmations, preconditions, or privilege boundaries merely
|
||||
to make a script easier to run.
|
||||
- Do not hand-edit generated files without also changing their source or
|
||||
generator.
|
||||
|
||||
## Rust conventions
|
||||
|
||||
- Keep responsibilities separated between `core`, `tui`, and `xtask`.
|
||||
- Put menu parsing, script discovery, and configuration behavior in `core`.
|
||||
- Put rendering, input handling, confirmation, and process interaction in
|
||||
`tui`.
|
||||
- Avoid adding distro-specific policy to Rust when it belongs in tab metadata
|
||||
or a shell script.
|
||||
- Return or propagate useful errors when practical. Avoid new `unwrap`,
|
||||
`expect`, or `panic` calls on user-controlled input.
|
||||
- Add or update tests for parser, filtering, configuration, and command-model
|
||||
changes.
|
||||
- Format Rust with `cargo fmt`.
|
||||
- Treat Clippy warnings as errors.
|
||||
|
||||
## Shell script conventions
|
||||
|
||||
- Prefer POSIX shell with `#!/bin/sh -e`.
|
||||
- Use Bash only when the script requires Bash features, and declare
|
||||
`#!/bin/bash` explicitly.
|
||||
- A script is executed from its own parent directory after the embedded
|
||||
`core/tabs/` tree is extracted. Keep relative imports valid from that
|
||||
directory.
|
||||
- Source shared helpers with the correct relative path:
|
||||
|
||||
```sh
|
||||
. ../common-script.sh
|
||||
```
|
||||
|
||||
Adjust the number of `..` components for nested directories.
|
||||
- Use `common-script.sh` helpers instead of duplicating package manager,
|
||||
architecture, escalation, command detection, or distro detection logic.
|
||||
- Source `common-service-script.sh` when managing services across init systems.
|
||||
- Call `checkEnv` before relying on values such as `PACKAGER`,
|
||||
`ESCALATION_TOOL`, `ARCH`, or `DTYPE`.
|
||||
- Quote variable expansions unless intentional word splitting is required.
|
||||
- Use `printf` rather than `echo` for portable formatted output.
|
||||
- Use `command_exists` for executable checks.
|
||||
- Use `"$ESCALATION_TOOL"` only for operations that require elevated
|
||||
privileges. Do not run the whole script as root by default.
|
||||
- Make installation and configuration steps reasonably idempotent. Detect an
|
||||
existing installation or state before changing it.
|
||||
- Fail with a clear message when a required distro, package manager,
|
||||
architecture, display server, init system, or command is unsupported.
|
||||
- Do not download and execute unverified remote code when a package,
|
||||
checksummed artifact, or pinned source is available.
|
||||
- Clean up temporary files created by the script.
|
||||
- Preserve interactive behavior because scripts run in a PTY.
|
||||
|
||||
## Adding or changing a utility
|
||||
|
||||
1. Place the script under the most appropriate `core/tabs/<tab>/` directory.
|
||||
2. Reuse shared helpers and support all practical package managers already
|
||||
handled by `common-script.sh`.
|
||||
3. Add or update the matching entry in that tab's `tab_data.toml`.
|
||||
4. Provide a clear `name`, useful `description`, one of `script`, `command`, or
|
||||
`entries`, and accurate `task_list` flags.
|
||||
5. Add `preconditions` when the entry only works on specific distros,
|
||||
environments, filesystems, commands, display servers, or architectures.
|
||||
6. Set `multi_select = false` for interactive, destructive, rebooting,
|
||||
long-running, or state-dependent operations that should not be queued.
|
||||
7. Run `cargo xtask docgen` when menu entries or descriptions change.
|
||||
8. Validate the script and the Rust catalog loader.
|
||||
|
||||
The supported task flags are:
|
||||
|
||||
- `D`: disk modification
|
||||
- `FI`: Flatpak installation
|
||||
- `FM`: file modification
|
||||
- `I`: privileged installation
|
||||
- `K`: kernel modification
|
||||
- `MP`: package manager action
|
||||
- `RP`: package removal
|
||||
- `SI`: full system installation
|
||||
- `SS`: systemd or service action
|
||||
- Prefixing a flag with `P` indicates privileged work.
|
||||
|
||||
Do not invent new task flags without updating the TUI guide and associated
|
||||
documentation.
|
||||
|
||||
## TOML catalog rules
|
||||
|
||||
- Script paths are relative to the tab directory containing `tab_data.toml`.
|
||||
- Every leaf entry must define exactly one executable form: `script` or
|
||||
`command`.
|
||||
- Every directory entry uses `entries`.
|
||||
- Prefer scripts over long inline `command` values.
|
||||
- Keep names stable when possible because config-file `auto_execute` resolves
|
||||
commands by display name.
|
||||
- Use preconditions to hide unsupported entries rather than letting users
|
||||
discover incompatibility after execution.
|
||||
- Parent `multi_select = false` applies to all descendants.
|
||||
- Keep tab data consistently ordered. Use `sort-tomlfiles.sh` when the change
|
||||
requires catalog sorting.
|
||||
|
||||
## Validation
|
||||
|
||||
Run the smallest relevant checks, then broaden them for cross-cutting changes.
|
||||
|
||||
For Rust changes:
|
||||
|
||||
```bash
|
||||
cargo fmt --all --check
|
||||
cargo test --no-fail-fast --package linutil_core
|
||||
cargo clippy -- -Dwarnings
|
||||
```
|
||||
|
||||
For shell changes:
|
||||
|
||||
```bash
|
||||
shellcheck path/to/changed-script.sh
|
||||
checkbashisms path/to/changed-script.sh
|
||||
```
|
||||
|
||||
Use `checkbashisms` only for scripts intended to run under `/bin/sh`. If local
|
||||
tools are unavailable, state which checks were skipped.
|
||||
|
||||
For catalog or documentation changes:
|
||||
|
||||
```bash
|
||||
cargo test --no-fail-fast --package linutil_core
|
||||
cargo xtask docgen
|
||||
git diff --check
|
||||
```
|
||||
|
||||
For TUI behavior, also run:
|
||||
|
||||
```bash
|
||||
cargo run --package linutil_tui
|
||||
```
|
||||
|
||||
Interactive validation must not execute destructive utilities merely to test
|
||||
navigation. Use preview, descriptions, harmless entries, or focused tests.
|
||||
|
||||
## Completion criteria
|
||||
|
||||
- The change matches `SPEC.md`.
|
||||
- Relevant tests and static checks pass.
|
||||
- New scripts are reachable through valid tab metadata.
|
||||
- Unsupported environments are filtered or fail clearly.
|
||||
- User-visible behavior and generated documentation are updated together.
|
||||
- The final report lists changed files, checks run, skipped checks, and any
|
||||
remaining platform-specific risk.
|
||||
Generated
+84
-64
@@ -97,6 +97,15 @@ version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.4.2"
|
||||
@@ -202,9 +211,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||
|
||||
[[package]]
|
||||
name = "bitstream-io"
|
||||
@@ -474,7 +483,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"crossterm_winapi",
|
||||
"derive_more",
|
||||
"document-features",
|
||||
@@ -537,12 +546,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.5.5"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
@@ -804,6 +810,17 @@ dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -1033,7 +1050,7 @@ version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1059,7 +1076,7 @@ dependencies = [
|
||||
"oneshot",
|
||||
"portable-pty",
|
||||
"rand 0.10.1",
|
||||
"ratatui 0.30.0",
|
||||
"ratatui 0.30.2",
|
||||
"ratatui-image",
|
||||
"time",
|
||||
"tree-sitter-bash",
|
||||
@@ -1122,11 +1139,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lru"
|
||||
version = "0.16.3"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
|
||||
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
"hashbrown 0.17.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1189,7 +1206,7 @@ version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.1.1",
|
||||
"libc",
|
||||
@@ -1201,7 +1218,7 @@ version = "0.31.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"cfg-if",
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
@@ -1234,9 +1251,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
|
||||
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
@@ -1327,6 +1344,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"bytemuck",
|
||||
"fast-srgb8",
|
||||
"libm",
|
||||
@@ -1386,7 +1404,7 @@ version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
@@ -1546,9 +1564,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
@@ -1635,7 +1653,7 @@ version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"cassowary",
|
||||
"compact_str 0.8.1",
|
||||
"indoc",
|
||||
@@ -1651,30 +1669,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.30.0"
|
||||
version = "0.30.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc"
|
||||
checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d"
|
||||
dependencies = [
|
||||
"instability",
|
||||
"ratatui-core",
|
||||
"ratatui-crossterm",
|
||||
"ratatui-widgets",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-core"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293"
|
||||
checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"compact_str 0.9.0",
|
||||
"hashbrown 0.16.1",
|
||||
"indoc",
|
||||
"hashbrown 0.17.1",
|
||||
"itertools 0.14.0",
|
||||
"kasuari",
|
||||
"lru 0.16.3",
|
||||
"strum 0.27.2",
|
||||
"lru 0.18.0",
|
||||
"palette",
|
||||
"serde",
|
||||
"strum 0.28.0",
|
||||
"thiserror 2.0.18",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate 2.0.1",
|
||||
@@ -1683,9 +1703,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-crossterm"
|
||||
version = "0.1.0"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3"
|
||||
checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossterm",
|
||||
@@ -1695,15 +1715,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-image"
|
||||
version = "11.0.2"
|
||||
version = "11.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "535e2a5f434ea3308977e6664b4386c3d663951a222e338cb7480d8742fe7773"
|
||||
checksum = "d413732e0e2f49577b59f35fa4ba9d5c4c0649fffe9541d9b43da10094058591"
|
||||
dependencies = [
|
||||
"base64-simd",
|
||||
"icy_sixel",
|
||||
"image",
|
||||
"rand 0.8.5",
|
||||
"ratatui 0.30.0",
|
||||
"rand 0.8.6",
|
||||
"ratatui 0.30.2",
|
||||
"rustix 0.38.44",
|
||||
"self_cell",
|
||||
"thiserror 1.0.69",
|
||||
@@ -1712,18 +1732,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ratatui-widgets"
|
||||
version = "0.3.0"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db"
|
||||
checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"hashbrown 0.16.1",
|
||||
"bitflags 2.13.0",
|
||||
"hashbrown 0.17.1",
|
||||
"indoc",
|
||||
"instability",
|
||||
"itertools 0.14.0",
|
||||
"line-clipping",
|
||||
"ratatui-core",
|
||||
"strum 0.27.2",
|
||||
"serde",
|
||||
"strum 0.28.0",
|
||||
"time",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.0",
|
||||
@@ -1805,7 +1826,7 @@ version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1878,7 +1899,7 @@ version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.15",
|
||||
@@ -1891,7 +1912,7 @@ version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.11.0",
|
||||
@@ -2110,11 +2131,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.27.2"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
|
||||
dependencies = [
|
||||
"strum_macros 0.27.2",
|
||||
"strum_macros 0.28.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2132,9 +2153,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.27.2"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
|
||||
checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -2221,12 +2242,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.47"
|
||||
version = "0.3.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
|
||||
checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
@@ -2238,15 +2258,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
||||
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.27"
|
||||
version = "0.2.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
|
||||
checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -2293,9 +2313,9 @@ checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.26.8"
|
||||
version = "0.26.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "887bd495d0582c5e3e0d8ece2233666169fa56a9644d172fc22ad179ab2d0538"
|
||||
checksum = "4dab76d0b724ba557954125188cf0633a1ca43199ced82d95c7b9c32cc3de1f3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
@@ -2317,9 +2337,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-highlight"
|
||||
version = "0.26.8"
|
||||
version = "0.26.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccde2b54a34b58313e69c02496a2a9ad38d59af79b196b5e1df063431752a7e0"
|
||||
checksum = "f4fbfa3f35520ff730da507e2c9a526a98156f417e0008c73de873741d7e4ecc"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"streaming-iterator",
|
||||
@@ -2551,7 +2571,7 @@ version = "0.244.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"semver",
|
||||
@@ -2565,9 +2585,9 @@ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "8.0.2"
|
||||
version = "8.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459"
|
||||
checksum = "c789537cf2f7f55be8e6192f92e464174ee55f91af622777f7f1ceb0dbccd03e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -2829,7 +2849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.10.0",
|
||||
"bitflags 2.13.0",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
# Linutil Technical Specification
|
||||
|
||||
## 1. Product definition
|
||||
|
||||
Linutil is a terminal-based Linux utility that provides a searchable,
|
||||
organized catalog of system setup, application installation, gaming, security,
|
||||
and maintenance tasks.
|
||||
|
||||
The product consists of:
|
||||
|
||||
- A Rust TUI that presents commands, previews their contents, confirms
|
||||
execution, and displays live terminal output.
|
||||
- A Rust core library that loads command metadata, filters unsupported entries,
|
||||
and embeds the complete script catalog in the application binary.
|
||||
- Portable shell scripts that implement the operating-system changes.
|
||||
- Shared shell libraries that centralize Linux distribution, package manager,
|
||||
privilege escalation, architecture, and service-manager behavior.
|
||||
|
||||
"Universal" means the architecture supports multiple Linux distributions,
|
||||
package managers, architectures, init systems, and desktop environments. It
|
||||
does not mean every command must work on every Linux system. Unsupported
|
||||
commands must be hidden by metadata or fail early with a useful explanation.
|
||||
|
||||
## 2. Goals
|
||||
|
||||
Linutil must:
|
||||
|
||||
1. Provide one discoverable TUI for common Linux administration and setup
|
||||
tasks.
|
||||
2. Ship as a self-contained binary with its command catalog and scripts
|
||||
embedded at compile time.
|
||||
3. Support distro-independent workflows where practical and explicit
|
||||
distro-specific workflows where required.
|
||||
4. Give users a preview and confirmation boundary before system-changing
|
||||
commands run.
|
||||
5. Preserve interactive terminal behavior for prompts, colors, progress, and
|
||||
full-screen command-line tools.
|
||||
6. Reuse shared shell behavior instead of duplicating package-manager and
|
||||
privilege logic across scripts.
|
||||
7. Make new utilities primarily data-and-script additions rather than Rust UI
|
||||
changes.
|
||||
8. Clearly communicate privileged, destructive, package-management, service,
|
||||
kernel, disk, and file operations.
|
||||
|
||||
## 3. Non-goals
|
||||
|
||||
Linutil is not:
|
||||
|
||||
- A replacement for a distribution's package manager.
|
||||
- A general-purpose shell or arbitrary command launcher.
|
||||
- A daemon or background configuration-management system.
|
||||
- A guarantee that every utility supports every Linux distribution.
|
||||
- A mechanism for silently bypassing package signatures, privilege controls,
|
||||
user confirmation, or platform compatibility checks.
|
||||
- A substitute for backups before disk, bootloader, kernel, account, or
|
||||
destructive filesystem operations.
|
||||
|
||||
## 4. System architecture
|
||||
|
||||
### 4.1 Workspace
|
||||
|
||||
The Cargo workspace contains:
|
||||
|
||||
| Component | Responsibility |
|
||||
| --- | --- |
|
||||
| `core` | Data model, TOML loading, precondition evaluation, embedded assets, temporary extraction, and user config |
|
||||
| `tui` | CLI, rendering, navigation, search, preview, confirmation, selection, PTY execution, and output display |
|
||||
| `xtask` | Repository maintenance and generated documentation |
|
||||
| `core/tabs` | Tab definitions, utility metadata, shared shell libraries, and executable scripts |
|
||||
|
||||
### 4.2 Runtime flow
|
||||
|
||||
1. `linutil_core` embeds `core/tabs/` into the binary at compile time.
|
||||
2. On startup, the embedded tree is extracted to a temporary directory.
|
||||
3. `tabs.toml` determines the ordered list of tab directories.
|
||||
4. Each tab's `tab_data.toml` is parsed into a tree of `ListNode` values.
|
||||
5. Preconditions are evaluated against the current machine when validation is
|
||||
enabled.
|
||||
6. Unsupported leaves and empty parent categories are removed.
|
||||
7. The TUI displays the resulting tabs and command tree.
|
||||
8. The user may inspect descriptions and source previews before selection.
|
||||
9. Selected commands pass through the confirmation flow.
|
||||
10. The TUI composes the commands into a shell program and runs it in a PTY.
|
||||
11. Output is rendered live until the process succeeds, fails, or is
|
||||
interrupted.
|
||||
12. The temporary script tree remains alive for the lifetime of the tab list
|
||||
and is removed when it is dropped.
|
||||
|
||||
### 4.3 Data model
|
||||
|
||||
The core command model has three forms:
|
||||
|
||||
- `Command::Raw(String)`: A short inline shell command.
|
||||
- `Command::LocalFile`: An extracted script, its shebang-derived executable,
|
||||
and executable arguments.
|
||||
- `Command::None`: A non-executable directory node.
|
||||
|
||||
A `Tab` owns a tree of `ListNode` values. Each node contains:
|
||||
|
||||
- Display name.
|
||||
- User-facing description.
|
||||
- Command form.
|
||||
- Task flag string.
|
||||
- Multi-select eligibility.
|
||||
|
||||
Display names should be unique among executable leaves because config-file
|
||||
automation resolves entries by name.
|
||||
|
||||
## 5. Command catalog
|
||||
|
||||
### 5.1 Top-level tabs
|
||||
|
||||
`core/tabs/tabs.toml` contains an ordered `directories` array. Every listed
|
||||
directory must contain a valid `tab_data.toml`.
|
||||
|
||||
Adding a top-level tab requires:
|
||||
|
||||
1. A new directory under `core/tabs/`.
|
||||
2. A valid `tab_data.toml`.
|
||||
3. An entry in `core/tabs/tabs.toml`.
|
||||
4. At least one supported executable leaf at runtime.
|
||||
|
||||
### 5.2 Tab schema
|
||||
|
||||
Each tab data file contains:
|
||||
|
||||
```toml
|
||||
name = "Tab Display Name"
|
||||
|
||||
[[data]]
|
||||
name = "Category or Command"
|
||||
```
|
||||
|
||||
An entry must define exactly one of:
|
||||
|
||||
- `entries`: Nested child entries.
|
||||
- `script`: A script path relative to the tab directory.
|
||||
- `command`: An inline shell command.
|
||||
|
||||
Optional entry fields are:
|
||||
|
||||
- `description`: User-facing explanation.
|
||||
- `preconditions`: Conditions controlling visibility.
|
||||
- `task_list`: Space-separated task flags shown in the TUI.
|
||||
- `multi_select`: Whether the entry may participate in a queued command set.
|
||||
The default is `true`.
|
||||
|
||||
Script paths may reference shared scripts elsewhere under `core/tabs/`, but
|
||||
the resolved path must exist when the catalog is loaded.
|
||||
|
||||
### 5.3 Preconditions
|
||||
|
||||
All preconditions on an entry must pass for it to remain visible.
|
||||
|
||||
Supported data sources are:
|
||||
|
||||
| Type | Behavior |
|
||||
| --- | --- |
|
||||
| `environment` | Compare an environment variable with the provided values |
|
||||
| `containing_file` | Check a file's contents for all provided strings |
|
||||
| `command_exists` | Check all provided commands on `PATH` |
|
||||
| `file_exists` | Check all provided paths as files |
|
||||
|
||||
`matches = true` requires a match. `matches = false` requires the inverse.
|
||||
|
||||
Preconditions should be used for objective platform capabilities such as a
|
||||
package manager, distro marker, display-server session, required executable,
|
||||
or required file. They are visibility filters, not a replacement for runtime
|
||||
validation inside scripts.
|
||||
|
||||
### 5.4 Task flags
|
||||
|
||||
Task flags warn users about the important effects of a command:
|
||||
|
||||
| Flag | Meaning |
|
||||
| --- | --- |
|
||||
| `D` | Disk modification |
|
||||
| `FI` | Flatpak installation |
|
||||
| `FM` | File modification |
|
||||
| `I` | Privileged installation |
|
||||
| `K` | Kernel modification |
|
||||
| `MP` | Package manager action |
|
||||
| `RP` | Package removal |
|
||||
| `SI` | Full system installation |
|
||||
| `SS` | Service or systemd action |
|
||||
| `P*` | The marked action requires privileges |
|
||||
|
||||
Flags are informational and do not grant privileges or replace confirmation.
|
||||
|
||||
## 6. Script contract
|
||||
|
||||
### 6.1 Interpreter
|
||||
|
||||
Scripts should use POSIX shell and `#!/bin/sh -e` by default. Scripts requiring
|
||||
Bash syntax must declare Bash explicitly.
|
||||
|
||||
If no shebang is present, the core defaults to `/bin/sh -e`. When executable
|
||||
validation is enabled, a script with an unavailable or non-executable shebang
|
||||
interpreter is omitted.
|
||||
|
||||
### 6.2 Working directory and shared files
|
||||
|
||||
Before a local script runs, the TUI changes to the script's extracted parent
|
||||
directory. Relative imports and sibling assets must be written for that
|
||||
working directory.
|
||||
|
||||
General-purpose scripts should source `common-script.sh`. Scripts that manage
|
||||
services should also source `common-service-script.sh`. More specialized
|
||||
families may define an additional shared helper when it removes meaningful
|
||||
duplication.
|
||||
|
||||
### 6.3 Environment initialization
|
||||
|
||||
Scripts using the general shared environment must call `checkEnv` before
|
||||
depending on its results.
|
||||
|
||||
The shared environment is responsible for detecting or defining:
|
||||
|
||||
- CPU architecture.
|
||||
- Supported privilege escalation tool.
|
||||
- Required baseline commands.
|
||||
- Supported package manager.
|
||||
- Current Linux distribution identifier.
|
||||
- Superuser group access.
|
||||
- Current-directory writability.
|
||||
- Arch User Repository helper where relevant.
|
||||
|
||||
Scripts must still validate feature-specific requirements and unsupported
|
||||
states.
|
||||
|
||||
### 6.4 Distribution portability
|
||||
|
||||
For a generally available utility:
|
||||
|
||||
- Use the detected `PACKAGER`.
|
||||
- Handle appropriate package names and flags per package manager.
|
||||
- Prefer native distribution packages.
|
||||
- Use Flatpak or another portable method as an intentional fallback, not an
|
||||
accidental catch-all when the platform is unknown.
|
||||
- Report unsupported distributions or architectures before making changes.
|
||||
|
||||
For a distro-specific utility:
|
||||
|
||||
- Place it in a clearly named distro category.
|
||||
- Add metadata preconditions.
|
||||
- Recheck critical assumptions in the script before changing the system.
|
||||
|
||||
### 6.5 Privilege and safety
|
||||
|
||||
Scripts must:
|
||||
|
||||
- Run unprivileged by default.
|
||||
- Apply `ESCALATION_TOOL` only to commands that require elevated access.
|
||||
- Explain destructive or irreversible choices before execution.
|
||||
- Avoid overwriting user configuration without a backup, merge, or explicit
|
||||
prompt.
|
||||
- Check existing state so repeated execution is safe when practical.
|
||||
- Stop on unsupported or ambiguous conditions.
|
||||
- Avoid embedding credentials or collecting user secrets.
|
||||
- Avoid logging sensitive input.
|
||||
- Clean temporary files and partial downloads.
|
||||
- Verify downloaded artifacts when upstream checksums or signatures exist.
|
||||
|
||||
Disk, bootloader, kernel, account-removal, and broad cleanup utilities should
|
||||
set `multi_select = false`.
|
||||
|
||||
### 6.6 User interaction
|
||||
|
||||
Scripts run in a PTY and may prompt users. Prompts must:
|
||||
|
||||
- State the action and meaningful consequences.
|
||||
- Accept predictable input.
|
||||
- Provide a safe default for risky operations.
|
||||
- Remain usable in the TUI's terminal viewport.
|
||||
- Exit nonzero on failure or cancellation when no work was completed.
|
||||
|
||||
## 7. TUI requirements
|
||||
|
||||
The TUI must provide:
|
||||
|
||||
- Tab and hierarchical command navigation.
|
||||
- Search and filtering.
|
||||
- Command descriptions.
|
||||
- Source preview for raw commands and local scripts.
|
||||
- Multi-selection for compatible commands.
|
||||
- Confirmation before execution unless an explicit, documented bypass applies.
|
||||
- Live PTY output with terminal color support.
|
||||
- Scrolling and process interruption.
|
||||
- Clear success and failure status.
|
||||
- A warning when Linutil itself is run as root unless explicitly bypassed.
|
||||
- A minimum-size check with an explicit bypass option.
|
||||
|
||||
Raw and local commands selected together execute in selection order within one
|
||||
shell program. A failure must be visible to the user and reflected in the final
|
||||
command status.
|
||||
|
||||
## 8. Configuration and automation
|
||||
|
||||
Linutil accepts a TOML configuration file with:
|
||||
|
||||
- `auto_execute`: Display names of executable leaves.
|
||||
- `skip_confirmation`: Whether confirmation is skipped.
|
||||
- `size_bypass`: Whether terminal-size enforcement is bypassed.
|
||||
|
||||
Unknown configuration fields are errors.
|
||||
|
||||
Automation must not cause an unsupported catalog entry to appear. Missing or
|
||||
filtered command names are ignored by the current loader and should be
|
||||
reported more explicitly in a future compatibility-preserving improvement.
|
||||
|
||||
Command display names are therefore part of the user-facing automation
|
||||
interface and should not be renamed casually.
|
||||
|
||||
## 9. Documentation
|
||||
|
||||
User-visible command additions and description changes must update generated
|
||||
walkthrough content using:
|
||||
|
||||
```bash
|
||||
cargo xtask docgen
|
||||
```
|
||||
|
||||
Generated documentation must not be edited as the sole source of a change.
|
||||
Architecture documentation should remain consistent with `SPEC.md` and the
|
||||
code.
|
||||
|
||||
## 10. Quality requirements
|
||||
|
||||
### 10.1 Rust
|
||||
|
||||
Required checks for Rust changes:
|
||||
|
||||
```bash
|
||||
cargo fmt --all --check
|
||||
cargo test --no-fail-fast --package linutil_core
|
||||
cargo clippy -- -Dwarnings
|
||||
```
|
||||
|
||||
Parser and filtering changes require focused unit tests. TUI behavior changes
|
||||
require either focused tests or documented interactive validation.
|
||||
|
||||
### 10.2 Shell
|
||||
|
||||
Changed shell scripts must pass ShellCheck. POSIX shell scripts should also
|
||||
pass `checkbashisms`.
|
||||
|
||||
Scripts should be tested without performing unintended system changes. Use
|
||||
syntax/static checks, controlled containers or virtual machines, mocked
|
||||
commands, and representative supported distributions as appropriate.
|
||||
|
||||
### 10.3 Catalog
|
||||
|
||||
Catalog changes must prove that:
|
||||
|
||||
- TOML parses successfully.
|
||||
- Every referenced script exists.
|
||||
- Required interpreters are valid under normal validation.
|
||||
- Preconditions retain intended entries and remove unsupported entries.
|
||||
- Generated documentation is current.
|
||||
|
||||
The core test suite is the minimum automated validation for catalog changes.
|
||||
|
||||
## 11. Acceptance criteria for a new utility
|
||||
|
||||
A utility is complete when:
|
||||
|
||||
1. It has a focused script or appropriately short raw command.
|
||||
2. It reuses shared environment and service helpers where applicable.
|
||||
3. It supports the intended distributions and rejects unsupported ones.
|
||||
4. Its metadata includes an accurate name, description, path, task flags,
|
||||
preconditions, and multi-select policy.
|
||||
5. It is previewable and executable from the TUI.
|
||||
6. Privileged and destructive operations are explicit.
|
||||
7. Re-running it does not cause avoidable damage or duplication.
|
||||
8. Relevant Rust, TOML, shell, and generated-documentation checks pass.
|
||||
9. Platform limitations and residual risks are documented.
|
||||
|
||||
## 12. Future compatibility
|
||||
|
||||
Architectural extensions should preserve the data-driven utility model.
|
||||
Potential additions such as richer capability detection, structured command
|
||||
results, dry-run support, per-command privilege declarations, or stronger
|
||||
download verification should extend the catalog and core contracts rather
|
||||
than hard-code individual utilities into the TUI.
|
||||
+1
-1
@@ -3,5 +3,5 @@ extend-exclude = ["tui/cool_tips.txt"]
|
||||
|
||||
[default]
|
||||
extend-ignore-identifiers-re = [
|
||||
"ratatui",
|
||||
"(?i)ratatui",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
installBraveOrigin() {
|
||||
if ! command_exists brave-origin && ! command_exists com.brave.Browser; then
|
||||
printf "%b\n" "${YELLOW}Installing Brave Origin...${RC}"
|
||||
if command_exists rpm-ostree; then
|
||||
"$ESCALATION_TOOL" curl -fsSLo /etc/yum.repos.d/brave-browser.repo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||
"$ESCALATION_TOOL" rpm-ostree install brave-origin
|
||||
else
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
|
||||
"$ESCALATION_TOOL" curl -fsSLo /etc/apt/sources.list.d/brave-browser-release.sources https://brave-browser-apt-release.s3.brave.com/brave-browser.sources
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y brave-origin
|
||||
;;
|
||||
dnf)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y dnf-plugins-core
|
||||
if command_exists dnf5; then
|
||||
"$ESCALATION_TOOL" dnf5 config-manager addrepo --from-repofile=https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||
else
|
||||
"$ESCALATION_TOOL" "$PACKAGER" config-manager --add-repo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||
fi
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y brave-origin
|
||||
;;
|
||||
zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" addrepo https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --gpg-auto-import-keys refresh
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y brave-origin
|
||||
;;
|
||||
pacman)
|
||||
checkAURHelper
|
||||
"$AUR_HELPER" -S --needed --noconfirm brave-origin-bin
|
||||
;;
|
||||
*)
|
||||
curl -fsS https://dl.brave.com/install.sh | FLAVOR=origin sh
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
printf "%b\n" "${GREEN}Brave Origin is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
uninstallBraveOrigin() {
|
||||
if command_exists brave-origin || command_exists com.brave.Browser; then
|
||||
printf "%b\n" "${YELLOW}Uninstalling Brave Origin...${RC}"
|
||||
if command_exists rpm-ostree; then
|
||||
"$ESCALATION_TOOL" rpm-ostree uninstall brave-origin
|
||||
else
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" purge --autoremove -y brave-origin
|
||||
"$ESCALATION_TOOL" rm -f /etc/apt/sources.list.d/brave-browser-release.sources
|
||||
"$ESCALATION_TOOL" rm -f /usr/share/keyrings/brave-browser-archive-keyring.gpg
|
||||
;;
|
||||
dnf)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" remove -y brave-origin
|
||||
"$ESCALATION_TOOL" rm -f /etc/yum.repos.d/brave-browser.repo
|
||||
;;
|
||||
zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive remove brave-origin
|
||||
;;
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -Rns --noconfirm brave-origin-bin
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${YELLOW}Automatic uninstall not supported for your distro.${RC}"
|
||||
printf "%b\n" "${YELLOW}Please use your package manager to remove brave-origin manually.${RC}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
printf "%b\n" "${GREEN}Brave Origin is not installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
printf "%b\n" "${YELLOW}Do you want to Install or Uninstall Brave Origin?${RC}"
|
||||
printf "%b\n" "1. ${YELLOW}Install Brave Origin${RC}"
|
||||
printf "%b\n" "2. ${YELLOW}Uninstall Brave Origin${RC}"
|
||||
printf "%b" "Enter your choice [1-2]: "
|
||||
read -r CHOICE
|
||||
case "$CHOICE" in
|
||||
1) installBraveOrigin ;;
|
||||
2) uninstallBraveOrigin ;;
|
||||
*) printf "%b\n" "${RED}Invalid choice.${RC}" && exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkEnv
|
||||
main
|
||||
@@ -273,6 +273,12 @@ description = "Brave is a free and open-source web browser developed by Brave So
|
||||
script = "browsers/brave.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Brave Origin"
|
||||
description = "Brave Origin is a minimalist version of Brave that strips out optional features like VPN, crypto wallet, Rewards, and Leo AI, keeping only core privacy protections and ad blocking."
|
||||
script = "browsers/brave-origin.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Chromium"
|
||||
description = "Chromium is an open-source web browser project started by Google, to provide the source code for the proprietary Google Chrome browser."
|
||||
|
||||
@@ -72,8 +72,15 @@ checkAURHelper() {
|
||||
|
||||
printf "%b\n" "${YELLOW}Installing yay as AUR helper...${RC}"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm base-devel git
|
||||
cd /opt && "$ESCALATION_TOOL" git clone https://aur.archlinux.org/yay-bin.git && "$ESCALATION_TOOL" chown -R "$USER":"$USER" ./yay-bin
|
||||
cd yay-bin && makepkg --noconfirm -si
|
||||
TMP_BUILD_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_BUILD_DIR"' 0
|
||||
git clone https://aur.archlinux.org/yay-bin.git "$TMP_BUILD_DIR/yay-bin"
|
||||
(
|
||||
cd "$TMP_BUILD_DIR/yay-bin"
|
||||
makepkg --noconfirm -si
|
||||
)
|
||||
rm -rf "$TMP_BUILD_DIR"
|
||||
trap - 0
|
||||
|
||||
if command_exists yay; then
|
||||
AUR_HELPER="yay"
|
||||
|
||||
Executable
+282
@@ -0,0 +1,282 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
# shellcheck source=core/tabs/common-script.sh
|
||||
. "$SCRIPT_DIR/../common-script.sh"
|
||||
|
||||
set_launcher() {
|
||||
case "$1" in
|
||||
steam)
|
||||
LAUNCHER_NAME="Steam"
|
||||
PKG_NAME="steam"
|
||||
FLATPAK_ID="com.valvesoftware.Steam"
|
||||
NIX_CONFIG='programs.steam.enable = true;'
|
||||
;;
|
||||
lutris)
|
||||
LAUNCHER_NAME="Lutris"
|
||||
PKG_NAME="lutris"
|
||||
FLATPAK_ID="net.lutris.Lutris"
|
||||
NIX_CONFIG='environment.systemPackages = with pkgs; [ lutris ];'
|
||||
;;
|
||||
retroarch)
|
||||
LAUNCHER_NAME="RetroArch"
|
||||
PKG_NAME="retroarch"
|
||||
FLATPAK_ID="org.libretro.RetroArch"
|
||||
NIX_CONFIG='environment.systemPackages = with pkgs; [ retroarch ];'
|
||||
;;
|
||||
heroic)
|
||||
LAUNCHER_NAME="Heroic"
|
||||
PKG_NAME="heroic-games-launcher-bin"
|
||||
FLATPAK_ID="com.heroicgameslauncher.hgl"
|
||||
NIX_CONFIG='environment.systemPackages = with pkgs; [ heroic ];'
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported launcher preset: $1${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
print_nixos_guidance() {
|
||||
printf "%b\n" "${YELLOW}NixOS is declarative. Linutil will not install or uninstall ${LAUNCHER_NAME} imperatively.${RC}"
|
||||
printf "%b\n" "${CYAN}Add this to /etc/nixos/configuration.nix:${RC}"
|
||||
printf "%s\n" "$NIX_CONFIG"
|
||||
printf "%b\n" "${CYAN}Then apply it with:${RC} sudo nixos-rebuild switch"
|
||||
printf "%b\n" "${CYAN}To uninstall, remove that option/package from configuration.nix and rebuild.${RC}"
|
||||
}
|
||||
|
||||
is_flatpak_installed() {
|
||||
command_exists flatpak && flatpak list --app --columns=application 2>/dev/null | grep -qx "$1"
|
||||
}
|
||||
|
||||
install_flatpak_app() {
|
||||
checkFlatpak
|
||||
"$ESCALATION_TOOL" flatpak install --noninteractive flathub "$FLATPAK_ID"
|
||||
}
|
||||
|
||||
uninstall_flatpak_app() {
|
||||
if is_flatpak_installed "$FLATPAK_ID"; then
|
||||
"$ESCALATION_TOOL" flatpak uninstall --noninteractive "$FLATPAK_ID"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
is_native_pkg_installed() {
|
||||
pkg="$1"
|
||||
case "$PACKAGER" in
|
||||
pacman) "$PACKAGER" -Qq "$pkg" >/dev/null 2>&1 ;;
|
||||
apt-get | nala) dpkg -s "$pkg" >/dev/null 2>&1 ;;
|
||||
dnf | zypper) rpm -q "$pkg" >/dev/null 2>&1 ;;
|
||||
eopkg) "$PACKAGER" info "$pkg" >/dev/null 2>&1 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
get_pacman_pkg_name() {
|
||||
pkg="$1"
|
||||
"$PACKAGER" -Qq "$pkg" 2>/dev/null | sed -n '1p'
|
||||
}
|
||||
|
||||
install_native_pkg() {
|
||||
case "$PACKAGER" in
|
||||
pacman) "$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm "$@" ;;
|
||||
apt-get | nala) "$ESCALATION_TOOL" "$PACKAGER" install -y "$@" ;;
|
||||
dnf) "$ESCALATION_TOOL" "$PACKAGER" install -y "$@" ;;
|
||||
zypper) "$ESCALATION_TOOL" "$PACKAGER" -n install "$@" ;;
|
||||
eopkg) "$ESCALATION_TOOL" "$PACKAGER" install -y "$@" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_aur_pkg_direct() {
|
||||
pkg="$1"
|
||||
|
||||
if ! command_exists git makepkg; then
|
||||
install_native_pkg base-devel git
|
||||
fi
|
||||
|
||||
temp_dir=$(mktemp -d)
|
||||
if git clone "https://aur.archlinux.org/${pkg}.git" "$temp_dir/$pkg"; then
|
||||
if (cd "$temp_dir/$pkg" && makepkg --noconfirm -si); then
|
||||
rm -rf "$temp_dir"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "$temp_dir"
|
||||
return 1
|
||||
}
|
||||
|
||||
uninstall_native_pkg() {
|
||||
case "$PACKAGER" in
|
||||
pacman) "$ESCALATION_TOOL" "$PACKAGER" -Rns --noconfirm "$@" ;;
|
||||
apt-get | nala) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$@" ;;
|
||||
dnf) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$@" ;;
|
||||
zypper) "$ESCALATION_TOOL" "$PACKAGER" -n remove "$@" ;;
|
||||
eopkg) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$@" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_arch_launcher() {
|
||||
case "$LAUNCHER_NAME" in
|
||||
Heroic)
|
||||
install_aur_pkg_direct "$PKG_NAME"
|
||||
;;
|
||||
RetroArch)
|
||||
install_native_pkg retroarch retroarch-assets-xmb retroarch-assets-ozone retroarch-assets-glui libretro-core-info
|
||||
;;
|
||||
*)
|
||||
install_native_pkg "$PKG_NAME"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_launcher() {
|
||||
if [ "$DTYPE" = "nixos" ]; then
|
||||
print_nixos_guidance
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "%b\n" "${YELLOW}Installing ${LAUNCHER_NAME}...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
install_arch_launcher
|
||||
;;
|
||||
apt-get | nala | dnf | zypper | eopkg)
|
||||
if [ "$LAUNCHER_NAME" = "Steam" ] || [ "$LAUNCHER_NAME" = "Heroic" ]; then
|
||||
install_flatpak_app
|
||||
elif [ "$PACKAGER" = "eopkg" ] && [ "$LAUNCHER_NAME" = "RetroArch" ]; then
|
||||
install_flatpak_app
|
||||
else
|
||||
install_native_pkg "$PKG_NAME"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
install_flatpak_app
|
||||
;;
|
||||
esac
|
||||
printf "%b\n" "${GREEN}${LAUNCHER_NAME} installation completed.${RC}"
|
||||
}
|
||||
|
||||
uninstall_arch_launcher() {
|
||||
installed_pkgs=""
|
||||
|
||||
case "$LAUNCHER_NAME" in
|
||||
Heroic)
|
||||
for pkg in heroic-games-launcher heroic-games-launcher-bin; do
|
||||
installed_pkg=$(get_pacman_pkg_name "$pkg")
|
||||
if [ -n "$installed_pkg" ] && ! printf '%s\n' "$installed_pkgs" | grep -qx "$installed_pkg"; then
|
||||
installed_pkgs="${installed_pkgs}${installed_pkgs:+
|
||||
}$installed_pkg"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
RetroArch)
|
||||
for pkg in retroarch retroarch-assets-xmb retroarch-assets-ozone retroarch-assets-glui libretro-core-info; do
|
||||
installed_pkg=$(get_pacman_pkg_name "$pkg")
|
||||
if [ -n "$installed_pkg" ] && ! printf '%s\n' "$installed_pkgs" | grep -qx "$installed_pkg"; then
|
||||
installed_pkgs="${installed_pkgs}${installed_pkgs:+
|
||||
}$installed_pkg"
|
||||
fi
|
||||
done
|
||||
;;
|
||||
*)
|
||||
installed_pkg=$(get_pacman_pkg_name "$PKG_NAME")
|
||||
if [ -n "$installed_pkg" ]; then
|
||||
installed_pkgs="$installed_pkg"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -n "$installed_pkgs" ]; then
|
||||
# Remove related pacman packages in one transaction to satisfy dependencies.
|
||||
# shellcheck disable=SC2086
|
||||
uninstall_native_pkg $installed_pkgs
|
||||
return 0
|
||||
fi
|
||||
|
||||
if uninstall_flatpak_app; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
uninstall_pkg_if_installed() {
|
||||
pkg="$1"
|
||||
if is_native_pkg_installed "$pkg"; then
|
||||
uninstall_native_pkg "$pkg"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
uninstall_launcher() {
|
||||
if [ "$DTYPE" = "nixos" ]; then
|
||||
print_nixos_guidance
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "%b\n" "${YELLOW}Uninstalling ${LAUNCHER_NAME}...${RC}"
|
||||
removed_any=false
|
||||
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
if uninstall_arch_launcher; then
|
||||
removed_any=true
|
||||
fi
|
||||
;;
|
||||
apt-get | nala | dnf | zypper | eopkg)
|
||||
if uninstall_pkg_if_installed "$PKG_NAME"; then
|
||||
removed_any=true
|
||||
fi
|
||||
if uninstall_flatpak_app; then
|
||||
removed_any=true
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
if uninstall_flatpak_app; then
|
||||
removed_any=true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$removed_any" = true ]; then
|
||||
printf "%b\n" "${GREEN}${LAUNCHER_NAME} uninstall completed.${RC}"
|
||||
else
|
||||
printf "%b\n" "${CYAN}${LAUNCHER_NAME} is not installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
preset="${1:-${LAUNCHER_PRESET:-}}"
|
||||
if [ -z "$preset" ]; then
|
||||
printf "%b\n" "${RED}No launcher specified. Please run this script through Gaming > Game Launchers.${RC}"
|
||||
exit 1
|
||||
fi
|
||||
set_launcher "$preset"
|
||||
printf "%b\n" "${YELLOW}Choose action for ${LAUNCHER_NAME}:${RC}"
|
||||
printf "%b\n" "1. ${YELLOW}Install${RC}"
|
||||
printf "%b\n" "2. ${YELLOW}Uninstall${RC}"
|
||||
printf "%b\n" "3. ${YELLOW}Abort${RC}"
|
||||
printf "%b" "Enter your choice [1-3]: "
|
||||
read -r action_choice
|
||||
|
||||
case "$action_choice" in
|
||||
1) install_launcher ;;
|
||||
2) uninstall_launcher ;;
|
||||
3) printf "%b\n" "${CYAN}Aborted.${RC}" ; exit 0 ;;
|
||||
*) printf "%b\n" "${RED}Invalid action choice.${RC}" ; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkDistro
|
||||
if [ "$DTYPE" = "nixos" ]; then
|
||||
checkArch
|
||||
else
|
||||
checkEnv
|
||||
fi
|
||||
main "$@"
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
LAUNCHER_PRESET=heroic sh "$SCRIPT_DIR/game-launchers.sh" heroic
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
LAUNCHER_PRESET=lutris sh "$SCRIPT_DIR/game-launchers.sh" lutris
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
# shellcheck source=core/tabs/common-script.sh
|
||||
. "$SCRIPT_DIR/../common-script.sh"
|
||||
|
||||
set_tool() {
|
||||
case "$1" in
|
||||
protonplus)
|
||||
TOOL_NAME="ProtonPlus"
|
||||
NATIVE_PKG_NAMES="protonplus protonplus-bin"
|
||||
FLATPAK_ID="com.vysp3r.ProtonPlus"
|
||||
;;
|
||||
protonup-qt)
|
||||
TOOL_NAME="ProtonUp-Qt"
|
||||
NATIVE_PKG_NAMES="protonup-qt"
|
||||
FLATPAK_ID="net.davidotek.pupgui2"
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported Proton tool preset: $1${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
is_flatpak_installed() {
|
||||
command_exists flatpak && flatpak list --app --columns=application 2>/dev/null | grep -qx "$FLATPAK_ID"
|
||||
}
|
||||
|
||||
is_native_pkg_installed() {
|
||||
pkg="$1"
|
||||
case "$PACKAGER" in
|
||||
pacman) "$PACKAGER" -Qq "$pkg" >/dev/null 2>&1 ;;
|
||||
apt-get | nala) dpkg -s "$pkg" >/dev/null 2>&1 ;;
|
||||
dnf | zypper) rpm -q "$pkg" >/dev/null 2>&1 ;;
|
||||
apk) "$PACKAGER" info -e "$pkg" >/dev/null 2>&1 ;;
|
||||
xbps-install) xbps-query "$pkg" >/dev/null 2>&1 ;;
|
||||
eopkg) "$PACKAGER" info "$pkg" >/dev/null 2>&1 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_native_pkg() {
|
||||
pkg="$1"
|
||||
case "$PACKAGER" in
|
||||
pacman) "$AUR_HELPER" -S --needed --noconfirm "$pkg" ;;
|
||||
apt-get | nala) "$ESCALATION_TOOL" "$PACKAGER" install -y "$pkg" ;;
|
||||
dnf) "$ESCALATION_TOOL" "$PACKAGER" install -y "$pkg" ;;
|
||||
zypper) "$ESCALATION_TOOL" "$PACKAGER" -n install "$pkg" ;;
|
||||
apk) "$ESCALATION_TOOL" "$PACKAGER" add "$pkg" ;;
|
||||
xbps-install) "$ESCALATION_TOOL" "$PACKAGER" -Sy "$pkg" ;;
|
||||
eopkg) "$ESCALATION_TOOL" "$PACKAGER" install -y "$pkg" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_native_tool() {
|
||||
for pkg in $NATIVE_PKG_NAMES; do
|
||||
if is_native_pkg_installed "$pkg"; then
|
||||
printf "%b\n" "${GREEN}${TOOL_NAME} is already installed as ${pkg}.${RC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "%b\n" "${YELLOW}Trying native package ${pkg} for ${TOOL_NAME}...${RC}"
|
||||
if install_native_pkg "$pkg"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
uninstall_native_pkg() {
|
||||
pkg="$1"
|
||||
case "$PACKAGER" in
|
||||
pacman) "$ESCALATION_TOOL" "$PACKAGER" -Rns --noconfirm "$pkg" ;;
|
||||
apt-get | nala) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$pkg" ;;
|
||||
dnf) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$pkg" ;;
|
||||
zypper) "$ESCALATION_TOOL" "$PACKAGER" -n remove "$pkg" ;;
|
||||
apk) "$ESCALATION_TOOL" "$PACKAGER" del "$pkg" ;;
|
||||
xbps-install) "$ESCALATION_TOOL" xbps-remove -R "$pkg" ;;
|
||||
eopkg) "$ESCALATION_TOOL" "$PACKAGER" remove -y "$pkg" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
uninstall_native_tool() {
|
||||
removed_any=false
|
||||
|
||||
for pkg in $NATIVE_PKG_NAMES; do
|
||||
if is_native_pkg_installed "$pkg"; then
|
||||
uninstall_native_pkg "$pkg"
|
||||
removed_any=true
|
||||
fi
|
||||
done
|
||||
|
||||
[ "$removed_any" = true ]
|
||||
}
|
||||
|
||||
install_tool() {
|
||||
if is_flatpak_installed; then
|
||||
printf "%b\n" "${GREEN}${TOOL_NAME} is already installed.${RC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if install_native_tool; then
|
||||
printf "%b\n" "${GREEN}${TOOL_NAME} installation completed.${RC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
checkFlatpak
|
||||
printf "%b\n" "${YELLOW}Native package unavailable. Installing ${TOOL_NAME} with Flatpak...${RC}"
|
||||
"$ESCALATION_TOOL" flatpak install --noninteractive flathub "$FLATPAK_ID"
|
||||
printf "%b\n" "${GREEN}${TOOL_NAME} installation completed.${RC}"
|
||||
}
|
||||
|
||||
uninstall_tool() {
|
||||
removed_any=false
|
||||
|
||||
if uninstall_native_tool; then
|
||||
removed_any=true
|
||||
fi
|
||||
|
||||
if is_flatpak_installed; then
|
||||
printf "%b\n" "${YELLOW}Uninstalling ${TOOL_NAME} with Flatpak...${RC}"
|
||||
"$ESCALATION_TOOL" flatpak uninstall --noninteractive "$FLATPAK_ID"
|
||||
removed_any=true
|
||||
fi
|
||||
|
||||
if [ "$removed_any" = false ]; then
|
||||
printf "%b\n" "${CYAN}${TOOL_NAME} is not installed.${RC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "%b\n" "${GREEN}${TOOL_NAME} uninstall completed.${RC}"
|
||||
}
|
||||
|
||||
main() {
|
||||
preset="${1:-${PROTON_TOOL_PRESET:-}}"
|
||||
if [ -z "$preset" ]; then
|
||||
printf "%b\n" "${RED}No Proton tool specified. Please run this script through Gaming > Tools and Setups.${RC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set_tool "$preset"
|
||||
printf "%b\n" "${YELLOW}Choose action for ${TOOL_NAME}:${RC}"
|
||||
printf "%b\n" "1. ${YELLOW}Install${RC}"
|
||||
printf "%b\n" "2. ${YELLOW}Uninstall${RC}"
|
||||
printf "%b\n" "3. ${YELLOW}Abort${RC}"
|
||||
printf "%b" "Enter your choice [1-3]: "
|
||||
read -r action_choice
|
||||
|
||||
case "$action_choice" in
|
||||
1) install_tool ;;
|
||||
2) uninstall_tool ;;
|
||||
3) printf "%b\n" "${CYAN}Aborted.${RC}" ; exit 0 ;;
|
||||
*) printf "%b\n" "${RED}Invalid action choice.${RC}" ; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkDistro
|
||||
checkEnv
|
||||
main "$@"
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
PROTON_TOOL_PRESET=protonplus sh "$SCRIPT_DIR/proton-tools.sh" protonplus
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
PROTON_TOOL_PRESET=protonup-qt sh "$SCRIPT_DIR/proton-tools.sh" protonup-qt
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
LAUNCHER_PRESET=retroarch sh "$SCRIPT_DIR/game-launchers.sh" retroarch
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
SCRIPT_DIR=$(dirname -- "$0")
|
||||
SCRIPT_DIR=$(cd -- "$SCRIPT_DIR" && pwd)
|
||||
LAUNCHER_PRESET=steam sh "$SCRIPT_DIR/game-launchers.sh" steam
|
||||
@@ -156,10 +156,22 @@ task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Gaming Dependencies"
|
||||
description = "This script is designed to handle the installation of gaming dependencies across different Linux distributions."
|
||||
description = "Installs gaming runtime dependencies across distributions. Steam and Lutris are managed separately from Game Launchers."
|
||||
script = "../system-setup/gaming-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "ProtonPlus"
|
||||
description = "Manage ProtonPlus installation with native packages first and Flatpak fallback."
|
||||
script = "protonplus.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "ProtonUp-Qt"
|
||||
description = "Manage ProtonUp-Qt installation with native packages first and Flatpak fallback."
|
||||
script = "protonup-qt.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "General GPU Drivers"
|
||||
description = "Auto-detects your GPU and installs a recommended driver stack for your distro, with NixOS guidance."
|
||||
@@ -182,6 +194,34 @@ task_list = "I SS"
|
||||
matches = true
|
||||
data = { environment = "XDG_SESSION_TYPE" }
|
||||
values = ["wayland", "Wayland"]
|
||||
|
||||
[[data]]
|
||||
name = "Game Launchers"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Steam"
|
||||
description = "Manage Steam launcher installation with Install, Uninstall, or Abort actions."
|
||||
script = "steam-launcher.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Lutris"
|
||||
description = "Manage Lutris launcher installation with Install, Uninstall, or Abort actions."
|
||||
script = "lutris-launcher.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "RetroArch"
|
||||
description = "Manage RetroArch launcher installation with Install, Uninstall, or Abort actions."
|
||||
script = "retroarch-launcher.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Heroic"
|
||||
description = "Manage Heroic launcher installation with Install, Uninstall, or Abort actions."
|
||||
script = "heroic-launcher.sh"
|
||||
task_list = "FI"
|
||||
|
||||
[[data]]
|
||||
name = "Arc Raiders Titus Mods"
|
||||
description = "Applies optimized game configuration files from ChrisTitusTech/arc-raiders. Sets Engine.ini to read-only to prevent the game from overwriting the settings, disables motion blur, and enables VRR optimizations."
|
||||
|
||||
@@ -10,8 +10,15 @@ installDepend() {
|
||||
if ! command_exists paru; then
|
||||
printf "%b\n" "${YELLOW}Installing paru as AUR helper...${RC}"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm base-devel git
|
||||
cd /opt && "$ESCALATION_TOOL" git clone https://aur.archlinux.org/paru-bin.git && "$ESCALATION_TOOL" chown -R "$USER": ./paru-bin
|
||||
cd paru-bin && makepkg --noconfirm -si
|
||||
TMP_BUILD_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_BUILD_DIR"' 0
|
||||
git clone https://aur.archlinux.org/paru-bin.git "$TMP_BUILD_DIR/paru-bin"
|
||||
(
|
||||
cd "$TMP_BUILD_DIR/paru-bin"
|
||||
makepkg --noconfirm -si
|
||||
)
|
||||
rm -rf "$TMP_BUILD_DIR"
|
||||
trap - 0
|
||||
printf "%b\n" "${GREEN}Paru installed${RC}"
|
||||
else
|
||||
printf "%b\n" "${GREEN}Paru already installed${RC}"
|
||||
|
||||
@@ -536,6 +536,21 @@ fi
|
||||
|
||||
gpu_type=$(lspci | grep -E "VGA|3D|Display")
|
||||
|
||||
select_nvidia_driver() {
|
||||
if echo "${gpu_type}" | grep -qE "NVIDIA|GeForce"; then
|
||||
echo ""
|
||||
echo "NVIDIA GPU detected. Select driver:"
|
||||
options=("nvidia-lts (proprietary)" "nouveau (open-source, skip nvidia-lts)")
|
||||
select_option "${options[@]}"
|
||||
case $? in
|
||||
0) NVIDIA_DRIVER="nvidia-lts" ;;
|
||||
1) NVIDIA_DRIVER="" ;;
|
||||
esac
|
||||
export NVIDIA_DRIVER
|
||||
fi
|
||||
}
|
||||
select_nvidia_driver
|
||||
|
||||
arch-chroot /mnt /bin/bash -c "KEYMAP='${KEYMAP}' /bin/bash" <<EOF
|
||||
|
||||
echo -ne "
|
||||
@@ -608,8 +623,12 @@ echo -ne "
|
||||
"
|
||||
# Graphics Drivers find and install
|
||||
if echo "${gpu_type}" | grep -E "NVIDIA|GeForce"; then
|
||||
echo "Installing NVIDIA drivers: nvidia-lts"
|
||||
pacman -S --noconfirm --needed nvidia-lts
|
||||
if [ -n "${NVIDIA_DRIVER}" ]; then
|
||||
echo "Installing NVIDIA drivers: ${NVIDIA_DRIVER}"
|
||||
pacman -S --noconfirm --needed "${NVIDIA_DRIVER}"
|
||||
else
|
||||
echo "Skipping proprietary NVIDIA driver. Using kernel nouveau + modesetting."
|
||||
fi
|
||||
elif echo "${gpu_type}" | grep 'VGA' | grep -E "Radeon|AMD"; then
|
||||
echo "Installing AMD drivers: xf86-video-amdgpu"
|
||||
pacman -S --noconfirm --needed xf86-video-amdgpu
|
||||
|
||||
@@ -10,8 +10,15 @@ installDepend() {
|
||||
if ! command_exists yay; then
|
||||
printf "%b\n" "${YELLOW}Installing yay as AUR helper...${RC}"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm base-devel git
|
||||
cd /opt && "$ESCALATION_TOOL" git clone https://aur.archlinux.org/yay-bin.git && "$ESCALATION_TOOL" chown -R "$USER": ./yay-bin
|
||||
cd yay-bin && makepkg --noconfirm -si
|
||||
TMP_BUILD_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP_BUILD_DIR"' 0
|
||||
git clone https://aur.archlinux.org/yay-bin.git "$TMP_BUILD_DIR/yay-bin"
|
||||
(
|
||||
cd "$TMP_BUILD_DIR/yay-bin"
|
||||
makepkg --noconfirm -si
|
||||
)
|
||||
rm -rf "$TMP_BUILD_DIR"
|
||||
trap - 0
|
||||
printf "%b\n" "${GREEN}Yay installed${RC}"
|
||||
else
|
||||
printf "%b\n" "${GREEN}Aur helper already installed${RC}"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installFstrim() {
|
||||
# fstrim ships with util-linux
|
||||
if ! command_exists fstrim; then
|
||||
printf "%b\n" "${YELLOW}Installing fstrim (util-linux)...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm util-linux
|
||||
;;
|
||||
apk)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" add util-linux
|
||||
;;
|
||||
xbps-install)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -Sy util-linux
|
||||
;;
|
||||
*)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y util-linux
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}fstrim is already installed${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
enableFstrimTimer() {
|
||||
if ! systemctl cat fstrim.timer >/dev/null 2>&1; then
|
||||
printf "%b\n" "${RED}fstrim.timer is not available on this system; cannot enable periodic TRIM.${RC}"
|
||||
exit 1
|
||||
fi
|
||||
printf "%b\n" "${YELLOW}Enabling weekly fstrim.timer...${RC}"
|
||||
"$ESCALATION_TOOL" systemctl enable --now fstrim.timer
|
||||
}
|
||||
|
||||
runInitialTrim() {
|
||||
printf "%b\n" "${YELLOW}Running an initial trim on all supported mounted filesystems...${RC}"
|
||||
"$ESCALATION_TOOL" fstrim -av || printf "%b\n" "${YELLOW}Some filesystems do not support trim and were skipped.${RC}"
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installFstrim
|
||||
enableFstrimTimer
|
||||
runInitialTrim
|
||||
|
||||
if systemctl is-active --quiet fstrim.timer; then
|
||||
printf "%b\n" "${GREEN}Periodic SSD TRIM is active (weekly via fstrim.timer).${RC}"
|
||||
else
|
||||
printf "%b\n" "${RED}fstrim.timer could not be activated. Check 'systemctl status fstrim.timer'.${RC}"
|
||||
fi
|
||||
@@ -40,12 +40,25 @@ run_install_step() {
|
||||
step_name="$1"
|
||||
shift
|
||||
step_output=$(mktemp)
|
||||
step_dir=$(mktemp -d)
|
||||
step_pipe="$step_dir/output.pipe"
|
||||
mkfifo "$step_pipe"
|
||||
|
||||
if "$@" > "$step_output" 2>&1; then
|
||||
cat "$step_output"
|
||||
printf "%b\n" "${CYAN}[RUNNING]${RC} ${step_name}"
|
||||
tee "$step_output" < "$step_pipe" &
|
||||
tee_pid=$!
|
||||
|
||||
set +e
|
||||
"$@" > "$step_pipe" 2>&1
|
||||
step_status=$?
|
||||
wait "$tee_pid"
|
||||
set -e
|
||||
|
||||
rm -rf "$step_dir"
|
||||
|
||||
if [ "$step_status" -eq 0 ]; then
|
||||
printf "%b\n" "${GREEN}[OK]${RC} ${step_name}"
|
||||
else
|
||||
cat "$step_output"
|
||||
printf "%b\n" "${YELLOW}[FAILED]${RC} ${step_name}"
|
||||
record_step_failure "$step_name" "$step_output"
|
||||
fi
|
||||
@@ -81,7 +94,7 @@ installDepend() {
|
||||
if ! grep -q "^\s*\[lib32\]" /etc/pacman.conf; then
|
||||
echo "[lib32]" | "$ESCALATION_TOOL" tee -a /etc/pacman.conf
|
||||
echo "Include = /etc/pacman.d/mirrorlist" | "$ESCALATION_TOOL" tee -a /etc/pacman.conf
|
||||
run_install_step "Refresh packages after enabling lib32" "$ESCALATION_TOOL" "$PACKAGER" -Syu
|
||||
run_install_step "Refresh packages after enabling lib32" "$ESCALATION_TOOL" "$PACKAGER" -Sy --noconfirm
|
||||
else
|
||||
printf "%b\n" "${GREEN}lib32 is already enabled.${RC}"
|
||||
fi
|
||||
@@ -90,7 +103,7 @@ installDepend() {
|
||||
if ! grep -q "^\s*\[multilib\]" /etc/pacman.conf; then
|
||||
echo "[multilib]" | "$ESCALATION_TOOL" tee -a /etc/pacman.conf
|
||||
echo "Include = /etc/pacman.d/mirrorlist" | "$ESCALATION_TOOL" tee -a /etc/pacman.conf
|
||||
run_install_step "Refresh packages after enabling multilib" "$ESCALATION_TOOL" "$PACKAGER" -Syu
|
||||
run_install_step "Refresh packages after enabling multilib" "$ESCALATION_TOOL" "$PACKAGER" -Sy --noconfirm
|
||||
else
|
||||
printf "%b\n" "${GREEN}Multilib is already enabled.${RC}"
|
||||
fi
|
||||
@@ -124,8 +137,7 @@ installDepend() {
|
||||
run_install_step "Install base dependencies" "$ESCALATION_TOOL" "$PACKAGER" install -y $DEPENDENCIES
|
||||
|
||||
DISTRO_DEPS="libasound2-plugins:i386 libsdl2-2.0-0:i386 libdbus-1-3:i386 libsqlite3-0:i386 wine32:i386"
|
||||
apt-cache show software-properties-common >/dev/null 2>&1 && DISTRO_DEPS="$DISTRO_DEPS software-properties-common"
|
||||
|
||||
apt-cache show software-properties-common >/dev/null 2>&1 && DISTRO_DEPS="$DISTRO_DEPS software-properties-common"
|
||||
run_install_step "Install distro-specific dependencies" "$ESCALATION_TOOL" "$PACKAGER" install -y $DISTRO_DEPS
|
||||
;;
|
||||
dnf)
|
||||
@@ -144,7 +156,6 @@ installDepend() {
|
||||
;;
|
||||
eopkg)
|
||||
DISTRO_DEPS="libgnutls libgtk-2 libgtk-3 pulseaudio alsa-lib alsa-plugins giflib libpng openal-soft libxcomposite libxinerama ncurses vulkan ocl-icd libva gst-plugins-base sdl2 v4l-utils sqlite3"
|
||||
|
||||
run_install_step "Install base and distro-specific dependencies" \
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y $DEPENDENCIES $DISTRO_DEPS
|
||||
;;
|
||||
@@ -158,38 +169,11 @@ installDepend() {
|
||||
installAdditionalDepend() {
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
DISTRO_DEPS='steam lutris goverlay'
|
||||
run_install_step "Install additional gaming apps" \
|
||||
DISTRO_DEPS='goverlay'
|
||||
run_install_step "Install additional gaming utilities" \
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm $DISTRO_DEPS
|
||||
;;
|
||||
apt-get | nala)
|
||||
printf "%b\n" "${YELLOW}Installing Lutris...${RC}"
|
||||
lutris_url=$(curl -s https://api.github.com/repos/lutris/lutris/releases/latest | grep "browser_download_url.*\.deb" | cut -d '"' -f 4)
|
||||
|
||||
if [ -n "$lutris_url" ]; then
|
||||
printf "%b\n" "${YELLOW}Downloading latest Lutris from GitHub...${RC}"
|
||||
run_install_step "Download latest Lutris package" curl -sSLo lutris.deb "$lutris_url"
|
||||
run_install_step "Install downloaded Lutris package" "$ESCALATION_TOOL" "$PACKAGER" install -y ./lutris.deb
|
||||
rm lutris.deb
|
||||
run_install_step "Refresh package indexes" "$ESCALATION_TOOL" "$PACKAGER" update
|
||||
run_install_step "Install Lutris from repositories" "$ESCALATION_TOOL" "$PACKAGER" install -y lutris
|
||||
fi
|
||||
|
||||
printf "%b\n" "${GREEN}Lutris Installation complete.${RC}"
|
||||
printf "%b\n" "${YELLOW}Installing steam...${RC}"
|
||||
run_install_step "Install Steam" "$ESCALATION_TOOL" "$PACKAGER" install -y steam
|
||||
;;
|
||||
dnf)
|
||||
DISTRO_DEPS='steam lutris'
|
||||
run_install_step "Install additional gaming apps" "$ESCALATION_TOOL" "$PACKAGER" install -y $DISTRO_DEPS
|
||||
;;
|
||||
zypper)
|
||||
DISTRO_DEPS='lutris'
|
||||
run_install_step "Install additional gaming apps" "$ESCALATION_TOOL" "$PACKAGER" -n install $DISTRO_DEPS
|
||||
;;
|
||||
eopkg)
|
||||
DISTRO_DEPS='steam lutris'
|
||||
run_install_step "Install additional gaming apps" "$ESCALATION_TOOL" "$PACKAGER" install -y $DISTRO_DEPS
|
||||
apt-get | nala | dnf | zypper | eopkg)
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager ${PACKAGER}${RC}"
|
||||
|
||||
@@ -212,6 +212,18 @@ description = "This script is designed to handle the installation of various sof
|
||||
script = "compile-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
name = "Enable SSD TRIM"
|
||||
description = "Enable weekly SSD TRIM through systemd's fstrim.timer and run an initial trim. This is the recommended alternative to mounting with the continuous discard option. For more information visit: https://wiki.archlinux.org/title/Solid_state_drive#TRIM"
|
||||
script = "fstrim-setup.sh"
|
||||
task_list = "D I SS"
|
||||
multi_select = false
|
||||
|
||||
[[data.preconditions]]
|
||||
matches = true
|
||||
data = "command_exists"
|
||||
values = [ "systemctl" ]
|
||||
|
||||
[[data]]
|
||||
name = "Full System Cleanup"
|
||||
description = "This script is designed to remove unnecessary packages, clean old cache files, remove temporary files, and to empty the trash."
|
||||
|
||||
@@ -13,7 +13,7 @@ Linutil is a distro-agnostic toolbox designed to simplify everyday Linux tasks.
|
||||
- **System Setup**: Configure your distro with optimized settings and tools
|
||||
- **Security**: Apply firewall baselines and harden your system
|
||||
- **Utilities**: Manage monitors, printers, Bluetooth, WiFi, and more
|
||||
- **Gaming**: Set up gaming dependencies and emulators
|
||||
- **Gaming**: Set up gaming dependencies, game launchers, emulators, and game-specific optimizations
|
||||
|
||||
## Who Should Use Linutil?
|
||||
|
||||
@@ -77,7 +77,7 @@ Tools for monitor management, printer setup, Bluetooth, WiFi, service management
|
||||
|
||||
### Gaming
|
||||
|
||||
Install gaming dependencies, emulators, and game-specific optimizations.
|
||||
Install gaming dependencies, manage game launchers, add emulators, and apply game-specific optimizations.
|
||||
|
||||
**[Read the Features Guide →](features/)**
|
||||
|
||||
|
||||
@@ -30,7 +30,29 @@ An alternative to UFW, FirewallD is the default firewall manager on Fedora and R
|
||||
|
||||
### Gaming Dependencies
|
||||
|
||||
Installs the libraries and tools needed to run games on Linux across different distributions (Steam, Wine, DXVK, Vulkan drivers, etc.).
|
||||
Installs the libraries and tools needed to run games on Linux across different distributions, such as Wine, Vulkan support, MangoHud, GameMode, and related runtime dependencies. Steam and Lutris are managed separately from the **Game Launchers** section.
|
||||
|
||||
### Proton Compatibility Tools
|
||||
|
||||
The Gaming tab includes **ProtonPlus** and **ProtonUp-Qt** under **Tools and Setups**. Both entries use an interactive Install, Uninstall, or Abort prompt, try native packages first, and fall back to Flathub Flatpak packages:
|
||||
|
||||
| Tool | Flatpak ID |
|
||||
|------|------------|
|
||||
| ProtonPlus | `com.vysp3r.ProtonPlus` |
|
||||
| ProtonUp-Qt | `net.davidotek.pupgui2` |
|
||||
|
||||
### Game Launchers
|
||||
|
||||
The Gaming tab includes a **Game Launchers** section for managing common launchers with an interactive Install, Uninstall, or Abort prompt.
|
||||
|
||||
| Launcher | Behavior |
|
||||
|----------|----------|
|
||||
| Steam | Uses native packages on Arch-based systems; uses Flatpak on several other distros where native availability is less consistent |
|
||||
| Lutris | Uses the native package manager on supported distros |
|
||||
| RetroArch | Uses native packages where available, with Flatpak fallback for selected distros |
|
||||
| Heroic | Uses Flatpak on non-Arch systems; on Arch-based systems builds `heroic-games-launcher-bin` directly from AUR |
|
||||
|
||||
On NixOS, these entries print declarative configuration guidance instead of modifying the system imperatively.
|
||||
|
||||
### Emulators
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ The **System Setup** section contains distro-specific and general configuration
|
||||
| Hyprland (JaKooLit) | Install JaKooLit's Hyprland configuration |
|
||||
| Full System Cleanup | Remove unused packages, clear cache, empty trash |
|
||||
| Full System Update | Update all packages to the latest available |
|
||||
| Gaming Dependencies | Install gaming dependencies across distros |
|
||||
| Gaming Dependencies | Install gaming runtime dependencies across distros |
|
||||
| Global Theme | Install and configure a global desktop theme |
|
||||
| Remove Snaps | Remove Snap and prevent it from reinstalling |
|
||||
| Build Prerequisites | Install software build dependencies |
|
||||
@@ -83,7 +83,7 @@ These scripts work across all distributions:
|
||||
|--------|-------------|
|
||||
| Full System Update | Update all packages using your distro's package manager |
|
||||
| Full System Cleanup | Clear package caches, temp files, and trash |
|
||||
| Gaming Dependencies | Install dependencies needed for gaming on Linux |
|
||||
| Gaming Dependencies | Install runtime dependencies needed for gaming on Linux |
|
||||
| Build Prerequisites | Install common software build dependencies |
|
||||
|
||||
> [!TIP]
|
||||
|
||||
@@ -74,12 +74,6 @@ https://github.com/ChrisTitusTech/neovim
|
||||
- **Android Debloater**: Universal Android Debloater (UAD) is a tool designed to help users remove bloatware and unnecessary pre-installed applications from Android devices, enhancing performance and user experience.
|
||||
- **Bash Prompt**: The .bashrc file is a script that runs every time a new terminal session is started in Unix-like operating systems. It is used to configure the shell session, set up aliases, define functions, and more, making the terminal easier to use and more powerful. This command configures the key sections and functionalities defined in the .bashrc file from CTT's mybash repository. https://github.com/ChrisTitusTech/mybash
|
||||
- **Docker**: Docker is an open platform that uses OS-level virtualization to deliver software in packages called containers.
|
||||
- **DWM-Titus**: DWM is a dynamic window manager for X.
|
||||
It manages windows in tiled, monocle and floating layouts.
|
||||
All of the layouts can be applied dynamically, optimising the environment for the application in use and the task performed.
|
||||
This command installs and configures DWM and a desktop manager.
|
||||
The list of patches applied can be found in CTT's DWM repository
|
||||
https://github.com/ChrisTitusTech/dwm-titus
|
||||
- **Fastfetch**: Fastfetch is a neofetch-like tool for fetching system information and displaying it prettily. It is written mainly in C, with performance and customizability in mind. This command installs fastfetch and configures from CTT's mybash repository. https://github.com/ChrisTitusTech/mybash
|
||||
- **Flatpak / Flathub**: Flatpak is a universal application sandbox for Linux that uses isolated packages from Flathub to prevent conflicts and system alterations, while alleviating dependency concerns. This command installs Flatpak and adds the Flathub repository
|
||||
- **Ghostty**: Ghostty is a terminal emulator that has embedded web technologies, allowing for a highly customizable and visually appealing terminal experience.
|
||||
@@ -98,6 +92,10 @@ https://github.com/ChrisTitusTech/dwm-titus
|
||||
### Emulators
|
||||
|
||||
|
||||
### Multi-System Emulators
|
||||
|
||||
- **RetroArch Game Emulator**: Frontend for emulators, game engines and media players. NO Games or Bios' are included
|
||||
|
||||
### Nintendo Emulators
|
||||
|
||||
- **bsnes**: Super Nintendo Emulator. NO Games are included
|
||||
@@ -121,10 +119,6 @@ https://github.com/ChrisTitusTech/dwm-titus
|
||||
- **Flycast**: A Dreamcase emulator. NO Games are included
|
||||
- **Kronos**: A Sega Saturn emulator. NO Games are included
|
||||
|
||||
### Multi-System Emulators
|
||||
|
||||
- **RetroArch Game Emulator**: Frontend for emulators, game engines and media players. NO Games or Bios' are included
|
||||
|
||||
### Xbox Emulators
|
||||
|
||||
- **XEMU**: An Original Xbox emulator. NO Games or Bios' are included
|
||||
@@ -136,13 +130,23 @@ https://github.com/ChrisTitusTech/dwm-titus
|
||||
https://github.com/AdnanHodzic/auto-cpufreq
|
||||
- **Auto Mount Drive**: This utility is designed to help with automating the process of mounting a drive on to your system.
|
||||
- **Bottles**: Bottles allows Windows software, like applications and games, to run on Linux. Bottles also provides tools to categorize, organize and optimize your applications.
|
||||
- **Gaming Dependencies**: This script is designed to handle the installation of gaming dependencies across different Linux distributions.
|
||||
- **Gaming Dependencies**: Installs gaming runtime dependencies across distributions. Steam and Lutris are managed separately from Game Launchers.
|
||||
- **ProtonPlus**: Manage ProtonPlus installation with native packages first and Flatpak fallback.
|
||||
- **ProtonUp-Qt**: Manage ProtonUp-Qt installation with native packages first and Flatpak fallback.
|
||||
- **General GPU Drivers**: Auto-detects your GPU and installs a recommended driver stack for your distro, with NixOS guidance.
|
||||
- **Nvidia Drivers & Hardware Acceleration**: Opens the Arch-specific NVIDIA installer (kept under System Setup / Arch).
|
||||
- **Waydroid**: Waydroid is an emulator that allows you to run Android apps and games on Linux.
|
||||
|
||||
### Game Launchers
|
||||
|
||||
- **Steam**: Manage Steam launcher installation with Install, Uninstall, or Abort actions.
|
||||
- **Lutris**: Manage Lutris launcher installation with Install, Uninstall, or Abort actions.
|
||||
- **RetroArch**: Manage RetroArch launcher installation with Install, Uninstall, or Abort actions.
|
||||
- **Heroic**: Manage Heroic launcher installation with Install, Uninstall, or Abort actions.
|
||||
- **Arc Raiders Titus Mods**: Applies optimized game configuration files from ChrisTitusTech/arc-raiders. Sets Engine.ini to read-only to prevent the game from overwriting the settings, disables motion blur, and enables VRR optimizations.
|
||||
- **Diablo II Resurrected Loot Filter**: Installs a loot filter for Diablo II Resurrected from ChrisTitusTech/d2r-loot-filter. Highlights high runes and other valuable items. Works on Battle.net and single player. After install, add launch option: -mod lootfilter -txt
|
||||
- **Fallout 76 INI and Mods**: Installs a custom Fallout76Custom.ini and mods from ChrisTitusTech/fallout76-configs via Steam. Improves performance and stability with quality of life tweaks.
|
||||
- **Starfield Titus INI and Mods**: Installs custom Starfield mods from ChrisTitusTech/starfield-config via steam.
|
||||
|
||||
## Security
|
||||
|
||||
@@ -159,7 +163,14 @@ https://github.com/AdnanHodzic/auto-cpufreq
|
||||
### Arch
|
||||
|
||||
- **Arch Server Setup**: This command installs a minimal arch server setup under 5 minutes.
|
||||
- **DWM-Titus**: DWM is a dynamic window manager for X.
|
||||
It manages windows in tiled, monocle and floating layouts.
|
||||
All of the layouts can be applied dynamically, optimising the environment for the application in use and the task performed.
|
||||
This command installs and configures DWM and a desktop manager.
|
||||
The list of patches applied can be found in CTT's DWM repository
|
||||
https://github.com/ChrisTitusTech/dwm-titus
|
||||
- **Hyprland JaKooLit**: Install JaKooLit's Hyprland configuration
|
||||
- **Install CachyOS Repository and Kernel**: To deliver a performance-optimized distribution, CachyOS recompiles Arch Linux packages specifically for the x86-64-v3, x86-64-v4, and Zen4+ architectures.
|
||||
- **Install Chaotic-AUR Repository**: Chaotic-AUR provides prebuilt binaries for popular AUR packages, saving compilation time. To know more visit: https://aur.chaotic.cx/
|
||||
- **Linux Neptune for SteamDeck**: Valve's fork of Linux Kernel for the SteamDeck
|
||||
- **Nvidia Drivers & Hardware Acceleration**: This script installs and configures nvidia drivers with Hardware Acceleration.
|
||||
@@ -192,8 +203,10 @@ https://github.com/AdnanHodzic/auto-cpufreq
|
||||
|
||||
- **Hyprland JaKooLit**: Install JaKooLit's Hyprland configuration
|
||||
- **Build Prerequisites**: This script is designed to handle the installation of various software dependencies across different Linux distributions
|
||||
- **Enable SSD TRIM**: Enable weekly SSD TRIM through systemd's fstrim.timer and run an initial trim. This is the recommended alternative to mounting with the continuous discard option. For more information visit: https://wiki.archlinux.org/title/Solid_state_drive#TRIM
|
||||
- **Full System Cleanup**: This script is designed to remove unnecessary packages, clean old cache files, remove temporary files, and to empty the trash.
|
||||
- **Full System Update**: This command updates your system to the latest packages available for your distro
|
||||
- **Full System Update (Topgrade)**: This command uses topgrade to update your system packages, configs, and more from various sources
|
||||
- **Global Theme**: This script is designed to handle the installation and configuration of global theming
|
||||
- **Remove Snaps**: This script is designed to remove snap
|
||||
- **TTY Fonts**: This Script will set the default TTY font to Terminus size 32 Bold
|
||||
@@ -227,6 +240,7 @@ https://github.com/AdnanHodzic/auto-cpufreq
|
||||
- **Bluetooth Manager**: This utility is designed to manage bluetooth in your system
|
||||
- **Numlock on Startup**: This utility is designed to enable Num Lock at boot, rather than within desktop environments like KDE or GNOME
|
||||
- **Ollama**: This utility is designed to manage ollama in your system
|
||||
- **Ranalama**: This utility is designed to manage ramalama in your system
|
||||
- **Service Manager**: This utility is designed to manage services in your system
|
||||
- **US Locale Setup**: This fixes US UTF-8 Locale and Folder listings
|
||||
- **WiFi Manager**: This utility is designed to manage wifi in your system
|
||||
|
||||
Generated
+3
-3
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1777268161,
|
||||
"narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=",
|
||||
"lastModified": 1779560665,
|
||||
"narHash": "sha256-tpyBcxPpcQb8ukyNF7DoCwfSY3VPsxHoYwj00Cayv5o=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76",
|
||||
"rev": "64c08a7ca051951c8eae34e3e3cb1e202fe36786",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
+2
-2
@@ -32,10 +32,10 @@ oneshot = { version = "0.2.1", features = ["std"], default-features = false }
|
||||
portable-pty = "0.9.0"
|
||||
rand = { version = "0.10.1", optional = true }
|
||||
ratatui = { version = "0.30.0", features = ["crossterm"], default-features = false }
|
||||
ratatui-image = { version = "11.0.2", default-features = false, features = ["crossterm", "image-defaults"] }
|
||||
ratatui-image = { version = "11.0.5", default-features = false, features = ["crossterm", "image-defaults"] }
|
||||
time = { version = "0.3.47", features = ["formatting", "local-offset", "macros"], default-features = false }
|
||||
tree-sitter-bash = "0.25.1"
|
||||
tree-sitter-highlight = "0.26.8"
|
||||
tree-sitter-highlight = "0.26.9"
|
||||
tui-term = { version = "0.3.4", default-features = false }
|
||||
unicode-width = { version = "0.2.0", default-features = false }
|
||||
vt100-ctt = "0.17.1"
|
||||
|
||||
+24
-1
@@ -176,7 +176,7 @@ impl AppState {
|
||||
}
|
||||
|
||||
fn spawn_confirmprompt(&mut self) {
|
||||
if self.skip_confirmation {
|
||||
if self.skip_confirmation || self.should_skip_confirmation_for_selection() {
|
||||
self.handle_confirm_command();
|
||||
} else {
|
||||
let cmd_names: Vec<_> = self
|
||||
@@ -194,6 +194,29 @@ impl AppState {
|
||||
}
|
||||
}
|
||||
|
||||
fn should_skip_confirmation_for_selection(&self) -> bool {
|
||||
!self.selected_commands.is_empty()
|
||||
&& self
|
||||
.selected_commands
|
||||
.iter()
|
||||
.all(|node| self.should_skip_confirmation_for_command(&node.command))
|
||||
}
|
||||
|
||||
fn should_skip_confirmation_for_command(&self, command: &Command) -> bool {
|
||||
match command {
|
||||
Command::LocalFile { file, .. } => {
|
||||
let path = file.to_string_lossy();
|
||||
path.ends_with("/gaming/steam-launcher.sh")
|
||||
|| path.ends_with("/gaming/lutris-launcher.sh")
|
||||
|| path.ends_with("/gaming/retroarch-launcher.sh")
|
||||
|| path.ends_with("/gaming/heroic-launcher.sh")
|
||||
|| path.ends_with("/gaming/protonplus.sh")
|
||||
|| path.ends_with("/gaming/protonup-qt.sh")
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_list_item_shortcut(&self) -> Box<[Shortcut]> {
|
||||
if self.selected_item_is_dir() {
|
||||
shortcuts!(("Go to selected dir", ["l", "Right", "Enter"]))
|
||||
|
||||
Reference in New Issue
Block a user