From 7416734f68f255eea7464f434248be669fa53806 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 13:34:00 -0500
Subject: [PATCH 01/21] chore: fix release workflow to merge docs branch
---
.github/workflows/release.yml | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a3940b86..e160d085 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -483,11 +483,16 @@ jobs:
PR_NUMBER=$(gh pr list --repo Termix-SSH/Docs --head "$BRANCH" --base main --state open --json number -q '.[0].number' || true)
if [ -z "$PR_NUMBER" ]; then
- PR_NUMBER=$(gh pr create --repo Termix-SSH/Docs \
+ PR_URL=$(gh pr create --repo Termix-SSH/Docs \
--base main --head "$BRANCH" \
--title "release-${{ needs.prep.outputs.version }}" \
- --body "API docs for ${{ needs.prep.outputs.version }}" \
- | grep -oE '[0-9]+$')
+ --body "API docs for ${{ needs.prep.outputs.version }}")
+ PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
+ fi
+
+ if [ -z "$PR_NUMBER" ]; then
+ echo "Failed to find or create a PR for $BRANCH."
+ exit 1
fi
gh pr merge "$PR_NUMBER" --repo Termix-SSH/Docs --squash --admin
From 30acbed1a7d2f337150345c3e52b3e3fc8ac1a1a Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 14:05:47 -0500
Subject: [PATCH 02/21] fix: svg donation generator push fail
---
.github/workflows/donation-goal.yml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index e495594f..a8017798 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -117,10 +117,11 @@ jobs:
fi
# Amend the previous bot commit if it exists, otherwise create a new one
LAST_AUTHOR=$(git log -1 --format='%ae')
+ REMOTE="https://x-access-token:${{ secrets.GHCR_TOKEN }}@github.com/${{ github.repository }}.git"
if [ "$LAST_AUTHOR" = "github-actions[bot]@users.noreply.github.com" ]; then
git commit --amend --no-edit
- git push --force-with-lease
+ git push --force-with-lease "$REMOTE" HEAD:main
else
git commit -m "chore: update donation goal badge"
- git push
+ git push "$REMOTE" HEAD:main
fi
From fe96e688723752028815baebc51642f57eaef508 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 14:26:30 -0500
Subject: [PATCH 03/21] fix: svg donation generator push fail
---
.github/workflows/donation-goal.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index a8017798..95fe52dd 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -117,7 +117,7 @@ jobs:
fi
# Amend the previous bot commit if it exists, otherwise create a new one
LAST_AUTHOR=$(git log -1 --format='%ae')
- REMOTE="https://x-access-token:${{ secrets.GHCR_TOKEN }}@github.com/${{ github.repository }}.git"
+ REMOTE="https://x-access-token:${{ secrets.PUSH_TOKEN }}@github.com/${{ github.repository }}.git"
if [ "$LAST_AUTHOR" = "github-actions[bot]@users.noreply.github.com" ]; then
git commit --amend --no-edit
git push --force-with-lease "$REMOTE" HEAD:main
From 253be0077e9c22181823025b22e07c72254c1e11 Mon Sep 17 00:00:00 2001
From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Date: Mon, 29 Jun 2026 14:45:46 -0500
Subject: [PATCH 04/21] Update termix.rb
---
Casks/termix.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Casks/termix.rb b/Casks/termix.rb
index f3a6b804..71de8222 100644
--- a/Casks/termix.rb
+++ b/Casks/termix.rb
@@ -1,6 +1,6 @@
cask "termix" do
- version "2.4.1"
- sha256 "c71209bf0bde9eefa5aeefbfc2b1db3af4ca3546e5f2ef09d233a6d3d1719150"
+ version "2.5.0"
+ sha256 "0662380b3cc986e5ddab263122e87b03a581bc18dbff1ad13e11dc973c84984b"
url "https://github.com/Termix-SSH/Termix/releases/download/release-#{version}-tag/termix_macos_universal_dmg.dmg"
name "Termix"
From 97124bc3b6a3adccc4fa2d8de0db219ad74061d9 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 14:52:14 -0500
Subject: [PATCH 05/21] fix: svg donation generator push fail
---
.github/workflows/donation-goal.yml | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index 95fe52dd..54fde243 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -12,6 +12,8 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
+ with:
+ token: ${{ secrets.PUSH_TOKEN }}
- name: Generate donation goal SVG
run: |
@@ -109,19 +111,18 @@ jobs:
PYEOF
- name: Commit SVG
run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
+ git config user.name "LukeGus"
+ git config user.email "bugattiguy527@gmail.com"
git add repo-images/donation-goal.svg
if git diff --cached --quiet; then
exit 0
fi
# Amend the previous bot commit if it exists, otherwise create a new one
LAST_AUTHOR=$(git log -1 --format='%ae')
- REMOTE="https://x-access-token:${{ secrets.PUSH_TOKEN }}@github.com/${{ github.repository }}.git"
- if [ "$LAST_AUTHOR" = "github-actions[bot]@users.noreply.github.com" ]; then
+ if [ "$LAST_AUTHOR" = "bugattiguy527@gmail.com" ]; then
git commit --amend --no-edit
- git push --force-with-lease "$REMOTE" HEAD:main
+ git push --force-with-lease origin HEAD:main
else
git commit -m "chore: update donation goal badge"
- git push "$REMOTE" HEAD:main
+ git push origin HEAD:main
fi
From 3a3b51d1aef68fc31c42c8b8821e15c353b77f56 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 14:59:29 -0500
Subject: [PATCH 06/21] chore: move donation badge to badges branch to avoid
ruleset conflicts
---
.github/workflows/donation-goal.yml | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index 54fde243..a42f36fd 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -13,6 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
+ ref: badges
token: ${{ secrets.PUSH_TOKEN }}
- name: Generate donation goal SVG
@@ -86,7 +87,6 @@ jobs:
goal_display = f'${int(goal):,}'
- # SVG dimensions
W = 400
BAR_W = 360
BAR_X = 20
@@ -105,24 +105,18 @@ jobs:
{pct_label}
'''
- with open('repo-images/donation-goal.svg', 'w') as f:
+ with open('donation-goal.svg', 'w') as f:
f.write(svg)
print(f'SVG written: {display} / {goal_display} ({round(pct)}%)')
PYEOF
+
- name: Commit SVG
run: |
git config user.name "LukeGus"
git config user.email "bugattiguy527@gmail.com"
- git add repo-images/donation-goal.svg
+ git add donation-goal.svg
if git diff --cached --quiet; then
exit 0
fi
- # Amend the previous bot commit if it exists, otherwise create a new one
- LAST_AUTHOR=$(git log -1 --format='%ae')
- if [ "$LAST_AUTHOR" = "bugattiguy527@gmail.com" ]; then
- git commit --amend --no-edit
- git push --force-with-lease origin HEAD:main
- else
- git commit -m "chore: update donation goal badge"
- git push origin HEAD:main
- fi
+ git commit -m "chore: update donation goal badge"
+ git push origin HEAD:badges
From 63cfdfda9e9a62c2f151ee1bf2b911183a38a43c Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 15:01:06 -0500
Subject: [PATCH 07/21] chore: remove unneeded token from donation badge
workflow
---
.github/workflows/donation-goal.yml | 1 -
1 file changed, 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index a42f36fd..57928143 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -14,7 +14,6 @@ jobs:
- uses: actions/checkout@v4
with:
ref: badges
- token: ${{ secrets.PUSH_TOKEN }}
- name: Generate donation goal SVG
run: |
From 72e5ff5a64ff586dddbc2954c278c88d1c1373b9 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 15:07:34 -0500
Subject: [PATCH 08/21] chore: debug donation badge commit step
---
.github/workflows/donation-goal.yml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index 57928143..3cf74409 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -113,8 +113,10 @@ jobs:
run: |
git config user.name "LukeGus"
git config user.email "bugattiguy527@gmail.com"
- git add donation-goal.svg
+ git add -f donation-goal.svg
+ git diff --cached --stat
if git diff --cached --quiet; then
+ echo "No changes to commit"
exit 0
fi
git commit -m "chore: update donation goal badge"
From a46f2f134373fa1b6db4e695e157a3aacb8a0dbe Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 15:11:29 -0500
Subject: [PATCH 09/21] fix: escape < character in donation SVG
---
.github/workflows/donation-goal.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index 3cf74409..d750c580 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -80,7 +80,7 @@ jobs:
pct = min(total / goal * 100, 100) if goal > 0 else 0
if total < 1:
- display = '< $1'
+ display = '< $1'
else:
display = f'${math.floor(total):,}'
From 4ec4cfcdb7f4a4638daccad8882faf6c2d7acccb Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 15:14:29 -0500
Subject: [PATCH 10/21] fix: point donation badge to badges branch
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e1ac7b30..99d0fc6b 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@
Termix is free and open source. If you find it useful, consider [donating](https://donate.termix.site/) to help cover server costs and development time.
-
+
From 4fbaf50e085b99015e438143ee0b04cad36a8a15 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 29 Jun 2026 15:16:16 -0500
Subject: [PATCH 11/21] chore: remove unused donation badge svg from main
---
repo-images/donation-goal.svg | 8 --------
1 file changed, 8 deletions(-)
delete mode 100644 repo-images/donation-goal.svg
diff --git a/repo-images/donation-goal.svg b/repo-images/donation-goal.svg
deleted file mode 100644
index e63bc49f..00000000
--- a/repo-images/donation-goal.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
- Monthly donation goal
-
- Monthly Donation Goal ... / $750
-
-
- Loading...
-
From 794714368aa403d38b8864ba29feb435844ea846 Mon Sep 17 00:00:00 2001
From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Date: Tue, 30 Jun 2026 13:32:22 -0500
Subject: [PATCH 12/21] Add Rack Genius logo to README
Added Rack Genius logo to the README.
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 99d0fc6b..d21216ee 100644
--- a/README.md
+++ b/README.md
@@ -392,6 +392,10 @@ See [Projects](https://github.com/orgs/Termix-SSH/projects/5) for all planned fe
+
+
+
+
From 078e6d5de0358a4686f0caf91b78880cd37c2be5 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Tue, 30 Jun 2026 22:41:32 -0500
Subject: [PATCH 13/21] chore: improve donation goal svg generator to include
stablecoins
---
.github/workflows/donation-goal.yml | 77 ++++++++++++++++++++++++++++-
1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index d750c580..1eda2392 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -25,6 +25,16 @@ jobs:
DOCS_SNAPSHOT_URL="https://raw.githubusercontent.com/Termix-SSH/Termix-Docs/main/static/donation-snapshot.json"
MONTHLY_GOAL=750
+ # Ethereum mainnet stablecoin contracts
+ ETH_USDC="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
+ ETH_USDT="0xdAC17F958D2ee523a2206206994597C13D831ec7"
+ ETH_DAI="0x6B175474E89094C44Da98b954EedeAC495271d0F"
+
+ # Base stablecoin contracts
+ BASE_USDC="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
+ BASE_USDT="0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"
+ BASE_DAI="0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
+
# Fetch crypto prices
PRICES=$(curl -sf "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,bitcoin,solana&vs_currencies=usd" || echo '{}')
ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethereum',{}).get('usd',0))" 2>/dev/null || echo 0)
@@ -46,14 +56,54 @@ jobs:
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getBalance\",\"params\":[\"${SOL_ADDRESS}\"]}" || echo '{"result":{"value":0}}')
SOL_BAL=$(echo "$SOL_RAW" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('result',{}).get('value',0)/1e9)" 2>/dev/null || echo 0)
+ # Helper: fetch an ERC-20 token balance from Blockscout token-balances endpoint
+ fetch_token_balance() {
+ local base_url="$1"
+ local contract="$2"
+ curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" \
+ | python3 -c "
+import sys, json
+contract = '$contract'.lower()
+try:
+ d = json.load(sys.stdin)
+except Exception:
+ print(0)
+ sys.exit()
+for item in d.get('items', []):
+ token = item.get('token', {})
+ if token.get('address', '').lower() == contract:
+ decimals = int(token.get('decimals') or 18)
+ value = int(item.get('value') or 0)
+ print(value / (10 ** decimals))
+ sys.exit()
+print(0)
+" 2>/dev/null || echo 0
+ }
+
+ ETH_USDC_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDC")
+ ETH_USDT_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDT")
+ ETH_DAI_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_DAI")
+
+ BASE_USDC_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_USDC")
+ BASE_USDT_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_USDT")
+ BASE_DAI_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_DAI")
+
# Fetch snapshot baseline from docs repo
SNAPSHOT=$(curl -sf "$DOCS_SNAPSHOT_URL" || echo '{"ethBal":0,"baseBal":0,"btcBal":0,"solBal":0}')
SNAP_ETH=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethBal',0))" 2>/dev/null || echo 0)
SNAP_BASE=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseBal',0))" 2>/dev/null || echo 0)
SNAP_BTC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('btcBal',0))" 2>/dev/null || echo 0)
SNAP_SOL=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('solBal',0))" 2>/dev/null || echo 0)
+ SNAP_ETH_USDC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethUsdcBal',0))" 2>/dev/null || echo 0)
+ SNAP_ETH_USDT=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethUsdtBal',0))" 2>/dev/null || echo 0)
+ SNAP_ETH_DAI=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethDaiBal',0))" 2>/dev/null || echo 0)
+ SNAP_BASE_USDC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseUsdcBal',0))" 2>/dev/null || echo 0)
+ SNAP_BASE_USDT=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseUsdtBal',0))" 2>/dev/null || echo 0)
+ SNAP_BASE_DAI=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseDaiBal',0))" 2>/dev/null || echo 0)
export ETH_BAL BASE_BAL BTC_BAL SOL_BAL SNAP_ETH SNAP_BASE SNAP_BTC SNAP_SOL ETH_PRICE BTC_PRICE SOL_PRICE MONTHLY_GOAL
+ export ETH_USDC_BAL ETH_USDT_BAL ETH_DAI_BAL BASE_USDC_BAL BASE_USDT_BAL BASE_DAI_BAL
+ export SNAP_ETH_USDC SNAP_ETH_USDT SNAP_ETH_DAI SNAP_BASE_USDC SNAP_BASE_USDT SNAP_BASE_DAI
python3 - <<'PYEOF'
import os, math
@@ -71,12 +121,37 @@ jobs:
sol_price = float(os.environ.get('SOL_PRICE', 0))
goal = float(os.environ.get('MONTHLY_GOAL', 750))
+ eth_usdc_bal = float(os.environ.get('ETH_USDC_BAL', 0))
+ eth_usdt_bal = float(os.environ.get('ETH_USDT_BAL', 0))
+ eth_dai_bal = float(os.environ.get('ETH_DAI_BAL', 0))
+ base_usdc_bal = float(os.environ.get('BASE_USDC_BAL', 0))
+ base_usdt_bal = float(os.environ.get('BASE_USDT_BAL', 0))
+ base_dai_bal = float(os.environ.get('BASE_DAI_BAL', 0))
+ snap_eth_usdc = float(os.environ.get('SNAP_ETH_USDC', 0))
+ snap_eth_usdt = float(os.environ.get('SNAP_ETH_USDT', 0))
+ snap_eth_dai = float(os.environ.get('SNAP_ETH_DAI', 0))
+ snap_base_usdc = float(os.environ.get('SNAP_BASE_USDC', 0))
+ snap_base_usdt = float(os.environ.get('SNAP_BASE_USDT', 0))
+ snap_base_dai = float(os.environ.get('SNAP_BASE_DAI', 0))
+
delta_eth = max(0, eth_bal - snap_eth)
delta_base = max(0, base_bal - snap_base)
delta_btc = max(0, btc_bal - snap_btc)
delta_sol = max(0, sol_bal - snap_sol)
- total = delta_eth * eth_price + delta_base * eth_price + delta_btc * btc_price + delta_sol * sol_price
+ delta_eth_usdc = max(0, eth_usdc_bal - snap_eth_usdc)
+ delta_eth_usdt = max(0, eth_usdt_bal - snap_eth_usdt)
+ delta_eth_dai = max(0, eth_dai_bal - snap_eth_dai)
+ delta_base_usdc = max(0, base_usdc_bal - snap_base_usdc)
+ delta_base_usdt = max(0, base_usdt_bal - snap_base_usdt)
+ delta_base_dai = max(0, base_dai_bal - snap_base_dai)
+
+ total = (
+ delta_eth * eth_price + delta_base * eth_price +
+ delta_btc * btc_price + delta_sol * sol_price +
+ delta_eth_usdc + delta_eth_usdt + delta_eth_dai +
+ delta_base_usdc + delta_base_usdt + delta_base_dai
+ )
pct = min(total / goal * 100, 100) if goal > 0 else 0
if total < 1:
From 19a2cb8eedcb3e72242f45ba4eacfb4c06a24143 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Wed, 1 Jul 2026 00:36:45 -0500
Subject: [PATCH 14/21] chore: donation goal generator syntax error
---
.github/workflows/donation-goal.yml | 19 +------------------
1 file changed, 1 insertion(+), 18 deletions(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index 1eda2392..d7569ff9 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -60,24 +60,7 @@ jobs:
fetch_token_balance() {
local base_url="$1"
local contract="$2"
- curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" \
- | python3 -c "
-import sys, json
-contract = '$contract'.lower()
-try:
- d = json.load(sys.stdin)
-except Exception:
- print(0)
- sys.exit()
-for item in d.get('items', []):
- token = item.get('token', {})
- if token.get('address', '').lower() == contract:
- decimals = int(token.get('decimals') or 18)
- value = int(item.get('value') or 0)
- print(value / (10 ** decimals))
- sys.exit()
-print(0)
-" 2>/dev/null || echo 0
+ curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" | CONTRACT="$contract" python3 -c "import sys, json, os; contract = os.environ['CONTRACT'].lower(); d = json.load(sys.stdin); match = next((i for i in d.get('items', []) if i.get('token', {}).get('address', '').lower() == contract), None); decimals = int((match or {}).get('token', {}).get('decimals') or 18); value = int((match or {}).get('value') or 0); print(value / (10 ** decimals) if match else 0)" 2>/dev/null || echo 0
}
ETH_USDC_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDC")
From b2ff35e106e9eb6f46759cbdbe5ab9c3d1dd9f07 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Wed, 1 Jul 2026 00:41:45 -0500
Subject: [PATCH 15/21] chore: donation goal generator incorrect docs url usage
---
.github/workflows/donation-goal.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index d7569ff9..c0b98797 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -22,7 +22,7 @@ jobs:
EVM_ADDRESS="0x83eA1Db55cc6E34fCD11Da2b7849621af67b6E34"
BTC_ADDRESS="bc1qrxc3vpnl6qhh9p8akjmjukcgmgmq852ua64h05"
SOL_ADDRESS="T4BF5ioySVUjwaPNw4Sdu7oK8SXLxgQRcMaTQ6YJ2UJ"
- DOCS_SNAPSHOT_URL="https://raw.githubusercontent.com/Termix-SSH/Termix-Docs/main/static/donation-snapshot.json"
+ DOCS_SNAPSHOT_URL="https://raw.githubusercontent.com/Termix-SSH/Docs/main/static/donation-snapshot.json"
MONTHLY_GOAL=750
# Ethereum mainnet stablecoin contracts
From bb5559c696b6b476a508c0bcc0b6dfbbec847c36 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Mon, 6 Jul 2026 15:22:13 -0500
Subject: [PATCH 16/21] chore: donation bar reporting wrong result
---
.github/workflows/donation-goal.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
index c0b98797..77a223de 100644
--- a/.github/workflows/donation-goal.yml
+++ b/.github/workflows/donation-goal.yml
@@ -36,7 +36,7 @@ jobs:
BASE_DAI="0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
# Fetch crypto prices
- PRICES=$(curl -sf "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,bitcoin,solana&vs_currencies=usd" || echo '{}')
+ PRICES=$(curl -sf -A "TermixDonationBar/1.0" "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,bitcoin,solana&vs_currencies=usd" || echo '{}')
ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethereum',{}).get('usd',0))" 2>/dev/null || echo 0)
BTC_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('bitcoin',{}).get('usd',0))" 2>/dev/null || echo 0)
SOL_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('solana',{}).get('usd',0))" 2>/dev/null || echo 0)
@@ -60,7 +60,7 @@ jobs:
fetch_token_balance() {
local base_url="$1"
local contract="$2"
- curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" | CONTRACT="$contract" python3 -c "import sys, json, os; contract = os.environ['CONTRACT'].lower(); d = json.load(sys.stdin); match = next((i for i in d.get('items', []) if i.get('token', {}).get('address', '').lower() == contract), None); decimals = int((match or {}).get('token', {}).get('decimals') or 18); value = int((match or {}).get('value') or 0); print(value / (10 ** decimals) if match else 0)" 2>/dev/null || echo 0
+ curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" | CONTRACT="$contract" python3 -c "import sys, json, os; contract = os.environ['CONTRACT'].lower(); d = json.load(sys.stdin); match = next((i for i in d.get('items', []) if (i.get('token', {}).get('address_hash') or i.get('token', {}).get('address') or '').lower() == contract), None); decimals = int((match or {}).get('token', {}).get('decimals') or 18); value = int((match or {}).get('value') or 0); print(value / (10 ** decimals) if match else 0)" 2>/dev/null || echo 0
}
ETH_USDC_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDC")
From 0712fdd731a9991e2d8b6cbd0de4e3d4891419f7 Mon Sep 17 00:00:00 2001
From: Sankeerth Nara
Date: Mon, 13 Jul 2026 22:46:11 +0530
Subject: [PATCH 17/21] feat: add Open File Manager to tab right-click menu
(#1046)
---
src/ui/AppShell.tsx | 4 ++++
src/ui/shell/TabBar.tsx | 17 +++++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/src/ui/AppShell.tsx b/src/ui/AppShell.tsx
index 0d0e6379..e978f4da 100644
--- a/src/ui/AppShell.tsx
+++ b/src/ui/AppShell.tsx
@@ -1713,6 +1713,10 @@ export function AppShell({
onAddToSplit={addTabToSplit}
onRemoveFromSplit={removeTabFromSplit}
onRenameTab={renameTab}
+ onOpenFileManager={(tabId) => {
+ const targetTab = tabs.find((t) => t.id === tabId);
+ if (targetTab?.host) openTab(targetTab.host, "files");
+ }}
isAppFullscreen={isAppFullscreen}
onToggleAppFullscreen={toggleAppFullscreen}
/>
diff --git a/src/ui/shell/TabBar.tsx b/src/ui/shell/TabBar.tsx
index df1dee24..f9553dc1 100644
--- a/src/ui/shell/TabBar.tsx
+++ b/src/ui/shell/TabBar.tsx
@@ -18,6 +18,7 @@ import {
Pencil,
Maximize2,
Minimize2,
+ FolderOpen,
} from "lucide-react";
import { tabIcon } from "@/shell/tabUtils";
import { isElectron } from "@/lib/electron";
@@ -40,6 +41,7 @@ export function TabBar({
onAddToSplit,
onRemoveFromSplit,
onRenameTab,
+ onOpenFileManager,
isAppFullscreen,
onToggleAppFullscreen,
}: {
@@ -56,6 +58,7 @@ export function TabBar({
onAddToSplit: (tabId: string) => void;
onRemoveFromSplit: (tabId: string) => void;
onRenameTab?: (tabId: string, newLabel: string) => void;
+ onOpenFileManager?: (tabId: string) => void;
isAppFullscreen: boolean;
onToggleAppFullscreen: () => void;
}) {
@@ -527,6 +530,20 @@ export function TabBar({
{t("nav.refreshTab")}
)}
+ {ctxTab.type === "terminal" &&
+ ctxTab.host &&
+ onOpenFileManager && (
+ {
+ onOpenFileManager(contextTabId);
+ setContextTabId(null);
+ }}
+ >
+
+ {t("nav.openFileManager")}
+
+ )}
{
From 38e128bd166cd973d873d428c85187ddc751f972 Mon Sep 17 00:00:00 2001
From: ZacharyZcR
Date: Tue, 14 Jul 2026 01:36:12 +0800
Subject: [PATCH 18/21] Revert "feat: add Open File Manager to tab right-click
menu (#1046)" (#1050)
This reverts commit 0712fdd731a9991e2d8b6cbd0de4e3d4891419f7.
---
src/ui/AppShell.tsx | 4 ----
src/ui/shell/TabBar.tsx | 17 -----------------
2 files changed, 21 deletions(-)
diff --git a/src/ui/AppShell.tsx b/src/ui/AppShell.tsx
index e978f4da..0d0e6379 100644
--- a/src/ui/AppShell.tsx
+++ b/src/ui/AppShell.tsx
@@ -1713,10 +1713,6 @@ export function AppShell({
onAddToSplit={addTabToSplit}
onRemoveFromSplit={removeTabFromSplit}
onRenameTab={renameTab}
- onOpenFileManager={(tabId) => {
- const targetTab = tabs.find((t) => t.id === tabId);
- if (targetTab?.host) openTab(targetTab.host, "files");
- }}
isAppFullscreen={isAppFullscreen}
onToggleAppFullscreen={toggleAppFullscreen}
/>
diff --git a/src/ui/shell/TabBar.tsx b/src/ui/shell/TabBar.tsx
index f9553dc1..df1dee24 100644
--- a/src/ui/shell/TabBar.tsx
+++ b/src/ui/shell/TabBar.tsx
@@ -18,7 +18,6 @@ import {
Pencil,
Maximize2,
Minimize2,
- FolderOpen,
} from "lucide-react";
import { tabIcon } from "@/shell/tabUtils";
import { isElectron } from "@/lib/electron";
@@ -41,7 +40,6 @@ export function TabBar({
onAddToSplit,
onRemoveFromSplit,
onRenameTab,
- onOpenFileManager,
isAppFullscreen,
onToggleAppFullscreen,
}: {
@@ -58,7 +56,6 @@ export function TabBar({
onAddToSplit: (tabId: string) => void;
onRemoveFromSplit: (tabId: string) => void;
onRenameTab?: (tabId: string, newLabel: string) => void;
- onOpenFileManager?: (tabId: string) => void;
isAppFullscreen: boolean;
onToggleAppFullscreen: () => void;
}) {
@@ -530,20 +527,6 @@ export function TabBar({
{t("nav.refreshTab")}
)}
- {ctxTab.type === "terminal" &&
- ctxTab.host &&
- onOpenFileManager && (
- {
- onOpenFileManager(contextTabId);
- setContextTabId(null);
- }}
- >
-
- {t("nav.openFileManager")}
-
- )}
{
From 972e27eb643023a55edc1dc9df5bef916ee0c371 Mon Sep 17 00:00:00 2001
From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Date: Mon, 13 Jul 2026 20:03:42 -0500
Subject: [PATCH 19/21] Remove donation badge from README
Removed donation badge from README.
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index d21216ee..1bff5ab4 100644
--- a/README.md
+++ b/README.md
@@ -35,8 +35,6 @@
Termix is free and open source. If you find it useful, consider [donating](https://donate.termix.site/) to help cover server costs and development time.
-
-
From 1aea3603a772c60406690ffe485b40efde176bc5 Mon Sep 17 00:00:00 2001
From: Luke Gustafson <88517757+LukeGus@users.noreply.github.com>
Date: Mon, 13 Jul 2026 20:04:16 -0500
Subject: [PATCH 20/21] Delete .github/workflows/donation-goal.yml
---
.github/workflows/donation-goal.yml | 181 ----------------------------
1 file changed, 181 deletions(-)
delete mode 100644 .github/workflows/donation-goal.yml
diff --git a/.github/workflows/donation-goal.yml b/.github/workflows/donation-goal.yml
deleted file mode 100644
index 77a223de..00000000
--- a/.github/workflows/donation-goal.yml
+++ /dev/null
@@ -1,181 +0,0 @@
-name: Donation Goal Badge
-
-on:
- schedule:
- - cron: "0 */6 * * *"
- workflow_dispatch:
-
-jobs:
- update:
- runs-on: ubuntu-latest
- permissions:
- contents: write
- steps:
- - uses: actions/checkout@v4
- with:
- ref: badges
-
- - name: Generate donation goal SVG
- run: |
- set -e
-
- EVM_ADDRESS="0x83eA1Db55cc6E34fCD11Da2b7849621af67b6E34"
- BTC_ADDRESS="bc1qrxc3vpnl6qhh9p8akjmjukcgmgmq852ua64h05"
- SOL_ADDRESS="T4BF5ioySVUjwaPNw4Sdu7oK8SXLxgQRcMaTQ6YJ2UJ"
- DOCS_SNAPSHOT_URL="https://raw.githubusercontent.com/Termix-SSH/Docs/main/static/donation-snapshot.json"
- MONTHLY_GOAL=750
-
- # Ethereum mainnet stablecoin contracts
- ETH_USDC="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
- ETH_USDT="0xdAC17F958D2ee523a2206206994597C13D831ec7"
- ETH_DAI="0x6B175474E89094C44Da98b954EedeAC495271d0F"
-
- # Base stablecoin contracts
- BASE_USDC="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
- BASE_USDT="0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"
- BASE_DAI="0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb"
-
- # Fetch crypto prices
- PRICES=$(curl -sf -A "TermixDonationBar/1.0" "https://api.coingecko.com/api/v3/simple/price?ids=ethereum,bitcoin,solana&vs_currencies=usd" || echo '{}')
- ETH_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethereum',{}).get('usd',0))" 2>/dev/null || echo 0)
- BTC_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('bitcoin',{}).get('usd',0))" 2>/dev/null || echo 0)
- SOL_PRICE=$(echo "$PRICES" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('solana',{}).get('usd',0))" 2>/dev/null || echo 0)
-
- # Fetch live balances
- ETH_RAW=$(curl -sf "https://eth.blockscout.com/api/v2/addresses/${EVM_ADDRESS}" || echo '{"coin_balance":"0"}')
- ETH_BAL=$(echo "$ETH_RAW" | python3 -c "import sys,json; d=json.load(sys.stdin); print(int(d.get('coin_balance','0')) / 1e18)" 2>/dev/null || echo 0)
-
- BASE_RAW=$(curl -sf "https://base.blockscout.com/api/v2/addresses/${EVM_ADDRESS}" || echo '{"coin_balance":"0"}')
- BASE_BAL=$(echo "$BASE_RAW" | python3 -c "import sys,json; d=json.load(sys.stdin); print(int(d.get('coin_balance','0')) / 1e18)" 2>/dev/null || echo 0)
-
- BTC_RAW=$(curl -sf "https://blockstream.info/api/address/${BTC_ADDRESS}" || echo '{"chain_stats":{"funded_txo_sum":0,"spent_txo_sum":0}}')
- BTC_BAL=$(echo "$BTC_RAW" | python3 -c "import sys,json; d=json.load(sys.stdin); s=d.get('chain_stats',{}); print((s.get('funded_txo_sum',0)-s.get('spent_txo_sum',0))/1e8)" 2>/dev/null || echo 0)
-
- SOL_RAW=$(curl -sf -X POST "https://api.mainnet-beta.solana.com" \
- -H "Content-Type: application/json" \
- -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getBalance\",\"params\":[\"${SOL_ADDRESS}\"]}" || echo '{"result":{"value":0}}')
- SOL_BAL=$(echo "$SOL_RAW" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('result',{}).get('value',0)/1e9)" 2>/dev/null || echo 0)
-
- # Helper: fetch an ERC-20 token balance from Blockscout token-balances endpoint
- fetch_token_balance() {
- local base_url="$1"
- local contract="$2"
- curl -sf "${base_url}/api/v2/addresses/${EVM_ADDRESS}/tokens?type=ERC-20" | CONTRACT="$contract" python3 -c "import sys, json, os; contract = os.environ['CONTRACT'].lower(); d = json.load(sys.stdin); match = next((i for i in d.get('items', []) if (i.get('token', {}).get('address_hash') or i.get('token', {}).get('address') or '').lower() == contract), None); decimals = int((match or {}).get('token', {}).get('decimals') or 18); value = int((match or {}).get('value') or 0); print(value / (10 ** decimals) if match else 0)" 2>/dev/null || echo 0
- }
-
- ETH_USDC_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDC")
- ETH_USDT_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_USDT")
- ETH_DAI_BAL=$(fetch_token_balance "https://eth.blockscout.com" "$ETH_DAI")
-
- BASE_USDC_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_USDC")
- BASE_USDT_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_USDT")
- BASE_DAI_BAL=$(fetch_token_balance "https://base.blockscout.com" "$BASE_DAI")
-
- # Fetch snapshot baseline from docs repo
- SNAPSHOT=$(curl -sf "$DOCS_SNAPSHOT_URL" || echo '{"ethBal":0,"baseBal":0,"btcBal":0,"solBal":0}')
- SNAP_ETH=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethBal',0))" 2>/dev/null || echo 0)
- SNAP_BASE=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseBal',0))" 2>/dev/null || echo 0)
- SNAP_BTC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('btcBal',0))" 2>/dev/null || echo 0)
- SNAP_SOL=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('solBal',0))" 2>/dev/null || echo 0)
- SNAP_ETH_USDC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethUsdcBal',0))" 2>/dev/null || echo 0)
- SNAP_ETH_USDT=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethUsdtBal',0))" 2>/dev/null || echo 0)
- SNAP_ETH_DAI=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ethDaiBal',0))" 2>/dev/null || echo 0)
- SNAP_BASE_USDC=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseUsdcBal',0))" 2>/dev/null || echo 0)
- SNAP_BASE_USDT=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseUsdtBal',0))" 2>/dev/null || echo 0)
- SNAP_BASE_DAI=$(echo "$SNAPSHOT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('baseDaiBal',0))" 2>/dev/null || echo 0)
-
- export ETH_BAL BASE_BAL BTC_BAL SOL_BAL SNAP_ETH SNAP_BASE SNAP_BTC SNAP_SOL ETH_PRICE BTC_PRICE SOL_PRICE MONTHLY_GOAL
- export ETH_USDC_BAL ETH_USDT_BAL ETH_DAI_BAL BASE_USDC_BAL BASE_USDT_BAL BASE_DAI_BAL
- export SNAP_ETH_USDC SNAP_ETH_USDT SNAP_ETH_DAI SNAP_BASE_USDC SNAP_BASE_USDT SNAP_BASE_DAI
-
- python3 - <<'PYEOF'
- import os, math
-
- eth_bal = float(os.environ.get('ETH_BAL', 0))
- base_bal = float(os.environ.get('BASE_BAL', 0))
- btc_bal = float(os.environ.get('BTC_BAL', 0))
- sol_bal = float(os.environ.get('SOL_BAL', 0))
- snap_eth = float(os.environ.get('SNAP_ETH', 0))
- snap_base = float(os.environ.get('SNAP_BASE', 0))
- snap_btc = float(os.environ.get('SNAP_BTC', 0))
- snap_sol = float(os.environ.get('SNAP_SOL', 0))
- eth_price = float(os.environ.get('ETH_PRICE', 0))
- btc_price = float(os.environ.get('BTC_PRICE', 0))
- sol_price = float(os.environ.get('SOL_PRICE', 0))
- goal = float(os.environ.get('MONTHLY_GOAL', 750))
-
- eth_usdc_bal = float(os.environ.get('ETH_USDC_BAL', 0))
- eth_usdt_bal = float(os.environ.get('ETH_USDT_BAL', 0))
- eth_dai_bal = float(os.environ.get('ETH_DAI_BAL', 0))
- base_usdc_bal = float(os.environ.get('BASE_USDC_BAL', 0))
- base_usdt_bal = float(os.environ.get('BASE_USDT_BAL', 0))
- base_dai_bal = float(os.environ.get('BASE_DAI_BAL', 0))
- snap_eth_usdc = float(os.environ.get('SNAP_ETH_USDC', 0))
- snap_eth_usdt = float(os.environ.get('SNAP_ETH_USDT', 0))
- snap_eth_dai = float(os.environ.get('SNAP_ETH_DAI', 0))
- snap_base_usdc = float(os.environ.get('SNAP_BASE_USDC', 0))
- snap_base_usdt = float(os.environ.get('SNAP_BASE_USDT', 0))
- snap_base_dai = float(os.environ.get('SNAP_BASE_DAI', 0))
-
- delta_eth = max(0, eth_bal - snap_eth)
- delta_base = max(0, base_bal - snap_base)
- delta_btc = max(0, btc_bal - snap_btc)
- delta_sol = max(0, sol_bal - snap_sol)
-
- delta_eth_usdc = max(0, eth_usdc_bal - snap_eth_usdc)
- delta_eth_usdt = max(0, eth_usdt_bal - snap_eth_usdt)
- delta_eth_dai = max(0, eth_dai_bal - snap_eth_dai)
- delta_base_usdc = max(0, base_usdc_bal - snap_base_usdc)
- delta_base_usdt = max(0, base_usdt_bal - snap_base_usdt)
- delta_base_dai = max(0, base_dai_bal - snap_base_dai)
-
- total = (
- delta_eth * eth_price + delta_base * eth_price +
- delta_btc * btc_price + delta_sol * sol_price +
- delta_eth_usdc + delta_eth_usdt + delta_eth_dai +
- delta_base_usdc + delta_base_usdt + delta_base_dai
- )
- pct = min(total / goal * 100, 100) if goal > 0 else 0
-
- if total < 1:
- display = '< $1'
- else:
- display = f'${math.floor(total):,}'
-
- goal_display = f'${int(goal):,}'
-
- W = 400
- BAR_W = 360
- BAR_X = 20
- BAR_H = 8
- FILL_W = round(BAR_W * pct / 100)
-
- label = f'Monthly Donation Goal {display} / {goal_display}'
- pct_label = f'{round(pct)}% of monthly goal' if pct < 100 else 'Goal reached this month. Thank you!'
-
- svg = f'''
- Monthly donation goal
-
- {label}
-
-
- {pct_label}
- '''
-
- with open('donation-goal.svg', 'w') as f:
- f.write(svg)
- print(f'SVG written: {display} / {goal_display} ({round(pct)}%)')
- PYEOF
-
- - name: Commit SVG
- run: |
- git config user.name "LukeGus"
- git config user.email "bugattiguy527@gmail.com"
- git add -f donation-goal.svg
- git diff --cached --stat
- if git diff --cached --quiet; then
- echo "No changes to commit"
- exit 0
- fi
- git commit -m "chore: update donation goal badge"
- git push origin HEAD:badges
From a6d0658e41656a67566572bcf48efa3968872f05 Mon Sep 17 00:00:00 2001
From: LukeGus
Date: Wed, 15 Jul 2026 15:41:29 -0500
Subject: [PATCH 21/21] chore: display donations in readme
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index 1bff5ab4..4e75ff40 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,10 @@
+
+
+
+
Termix is free and open source. If you find it useful, consider [donating](https://donate.termix.site/) to help cover server costs and development time.