Compare commits

...

20 Commits

Author SHA1 Message Date
dependabot[bot] 3625cb455d chore(deps): bump actions/cache from 5 to 6
Check for typos / check-typos (push) Has been cancelled
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-29 19:52:53 +00:00
titus 9be14fe058 fix security alert for rand
Deploy Hugo site to Pages / build (push) Has been cancelled
nix / checks (push) Has been cancelled
nix / update (push) Has been cancelled
Check for typos / check-typos (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
2026-06-23 20:27:14 -05:00
Pinak Dhabu 50e6e33c91 Add nouveau option for old NVIDIA GPUs in Arch Server install (#1293)
Co-authored-by: Pinak Dhabu <thepinak503@users.noreply.github.com>
2026-06-23 20:24:50 -05:00
Daniel 28ab9a8ca5 Use temporary directory for AUR helper installation (#1305)
* Use temporary directory for AUR helper installation

Switch from using /opt to a temporary directory for building yay to
improve
security, auto clean-up and prevent permission issues.

* apply the fix in the yay-setup and paru-setup scripts

* fix(arch): clean temporary AUR build directories

---------

Co-authored-by: titus <contact@christitus.com>
2026-06-23 20:23:01 -05:00
emylfy 29ac0ef394 Add SSD TRIM (fstrim.timer) setup script (#1318)
* Add SSD TRIM (fstrim.timer) setup script

* fix(system): mark fstrim as non-queueable

---------

Co-authored-by: titus <contact@christitus.com>
2026-06-23 20:21:43 -05:00
Pinak Dhabu dbadadff86 feat: add Brave Origin browser install script (#1311)
* feat: add Brave Origin browser install script

* fix: address PR #1311 review - fix rpm-ostree detection and add uninstaller

---------

Co-authored-by: Pinak Dhabu <thepinak503@users.noreply.github.com>
2026-06-23 20:09:34 -05:00
github-actions[bot] da55a2e47a chore(nix): update flake inputs (#1298)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-23 20:09:02 -05:00
dependabot[bot] d6d0f11beb chore(deps): bump which from 8.0.2 to 8.0.3 (#1317)
Bumps [which](https://github.com/harryfei/which-rs) from 8.0.2 to 8.0.3.
- [Release notes](https://github.com/harryfei/which-rs/releases)
- [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/harryfei/which-rs/compare/8.0.2...8.0.3)

---
updated-dependencies:
- dependency-name: which
  dependency-version: 8.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 20:03:32 -05:00
dependabot[bot] 3038c24820 chore(deps): bump time from 0.3.47 to 0.3.51 (#1316)
Bumps [time](https://github.com/time-rs/time) from 0.3.47 to 0.3.51.
- [Release notes](https://github.com/time-rs/time/releases)
- [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md)
- [Commits](https://github.com/time-rs/time/compare/v0.3.47...v0.3.51)

---
updated-dependencies:
- dependency-name: time
  dependency-version: 0.3.49
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 20:02:45 -05:00
titus 1316e9a953 bump ratatui-image to 11.0.5 to fix render 2026-06-23 20:02:22 -05:00
dependabot[bot] e6b4d0b724 chore(deps): bump ratatui from 0.30.0 to 0.30.2 (#1315)
Bumps [ratatui](https://github.com/ratatui/ratatui) from 0.30.0 to 0.30.2.
- [Release notes](https://github.com/ratatui/ratatui/releases)
- [Changelog](https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ratatui/ratatui/compare/ratatui-v0.30.0...ratatui-v0.30.2)

---
updated-dependencies:
- dependency-name: ratatui
  dependency-version: 0.30.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:57:43 -05:00
dependabot[bot] 4eeb01a308 chore(deps): bump actions/cache from 4 to 5 (#1304)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:57:15 -05:00
dependabot[bot] 7fadb7b3e3 chore(deps): bump actions/github-script from 7 to 9 (#1303)
Bumps [actions/github-script](https://github.com/actions/github-script) from 7 to 9.
- [Release notes](https://github.com/actions/github-script/releases)
- [Commits](https://github.com/actions/github-script/compare/v7...v9)

---
updated-dependencies:
- dependency-name: actions/github-script
  dependency-version: '9'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:57:05 -05:00
dependabot[bot] e07b62d2ad chore(deps): bump ratatui-image from 11.0.2 to 11.0.3 (#1302)
Bumps [ratatui-image](https://github.com/ratatui/ratatui-image) from 11.0.2 to 11.0.3.
- [Release notes](https://github.com/ratatui/ratatui-image/releases)
- [Changelog](https://github.com/ratatui/ratatui-image/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ratatui/ratatui-image/compare/v11.0.2...v11.0.3)

---
updated-dependencies:
- dependency-name: ratatui-image
  dependency-version: 11.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:56:29 -05:00
dependabot[bot] 2682c35cd1 chore(deps): bump actions/upload-pages-artifact from 4 to 5 (#1301)
Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-pages-artifact/releases)
- [Commits](https://github.com/actions/upload-pages-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-pages-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:56:04 -05:00
dependabot[bot] 3da4fb76e4 chore(deps): bump actions/deploy-pages from 4 to 5 (#1300)
Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 4 to 5.
- [Release notes](https://github.com/actions/deploy-pages/releases)
- [Commits](https://github.com/actions/deploy-pages/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/deploy-pages
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:55:54 -05:00
dependabot[bot] 6fef076083 chore(deps): bump softprops/action-gh-release from 2 to 3 (#1299)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 19:55:07 -05:00
dependabot[bot] dabddd5692 chore(deps): bump tree-sitter-highlight from 0.26.8 to 0.26.9 (#1295)
* chore(deps): bump tree-sitter-highlight from 0.26.8 to 0.26.9

Bumps [tree-sitter-highlight](https://github.com/tree-sitter/tree-sitter) from 0.26.8 to 0.26.9.
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/compare/v0.26.8...v0.26.9)

---
updated-dependencies:
- dependency-name: tree-sitter-highlight
  dependency-version: 0.26.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* docs: refresh generated walkthrough

* ci: allow Ratatui product name

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: titus <contact@christitus.com>
2026-06-23 19:54:15 -05:00
titus f3946bf4a4 add agent and spec sheets 2026-06-23 19:22:15 -05:00
Abs c770e88764 add Game Launchers and Proton tool entries (#1290)
Deploy Hugo site to Pages / build (push) Has been cancelled
nix / checks (push) Has been cancelled
nix / update (push) Has been cancelled
Check for typos / check-typos (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
* add Game Launchers

* Add Proton tools to gaming tab

* cleanup gaming-setup

* install proton tools using native pkg manager

* fix(gaming): show live progress for long dependency installs

* fix(gaming): avoid pacman prompt when enabling multilib

---------

Co-authored-by: Chris Titus <contact@christitus.com>
2026-06-10 14:37:24 -05:00
34 changed files with 1509 additions and 145 deletions
+4 -4
View File
@@ -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
+1 -1
View File
@@ -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"];
+3 -3
View File
@@ -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 }}
+1 -1
View File
@@ -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 || '';
+2 -2
View File
@@ -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') }}
+197
View File
@@ -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
View File
@@ -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",
+384
View File
@@ -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
View File
@@ -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."
+9 -2
View File
@@ -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"
+282
View File
@@ -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 "$@"
+5
View File
@@ -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
+5
View File
@@ -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
+164
View File
@@ -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 "$@"
+5
View File
@@ -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
+5
View File
@@ -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
+5
View File
@@ -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
+5
View File
@@ -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
+41 -1
View File
@@ -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."
+9 -2
View File
@@ -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}"
+21 -2
View File
@@ -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
+9 -2
View File
@@ -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}"
+52
View File
@@ -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
+22 -38
View File
@@ -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}"
+12
View File
@@ -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."
+2 -2
View File
@@ -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/)**
+23 -1
View File
@@ -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
+2 -2
View File
@@ -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]
+25 -11
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"]))