Compare commits

..

6 Commits

Author SHA1 Message Date
CanbiZ (MickLesk)
d84770e215 chore(ct,tools): sync Source headers with install/ and add Github links to addon scripts 2026-02-24 14:36:19 +01:00
CanbiZ (MickLesk)
8deb4401b1 revert: restore misc/build.func and misc/core.func to main state
These error-handler fixes belong to fix/error-handler-recovery, not to
this sources-only branch.
2026-02-24 14:30:07 +01:00
CanbiZ (MickLesk)
b1edd80a96 chore(install): add Github source links to all fetch_and_deploy scripts
77 additional install scripts had fetch_and_deploy_gh_release calls but
no GitHub link in the Source header. Merged the primary app repo into
the Source header as:
  # Source: https://website.com/ | Github: https://github.com/OWNER/REPO

Where multiple fetch_and_deploy calls existed (app + dependency), the
primary app repo was selected:
- ersatztv: ErsatzTV/ErsatzTV (not ffmpeg)
- firefly: firefly-iii/firefly-iii (not data-importer)
- komga: gotson/komga (not kepubify dep)
- sabnzbd: sabnzbd/sabnzbd (not par2cmdline-turbo dep)
- signoz: SigNoz/signoz (not otel-collector)
- tunarr: chrisbenincasa/tunarr (not ffmpeg dep)

Also fixed cosmos-install.sh double https:// in Source URL.

Skipped: autocaliweb (source already on codeberg, GitHub repos are deps only)
2026-02-24 14:28:45 +01:00
CanbiZ (MickLesk)
da422b1036 chore(install): add Github source links to all setup_nodejs scripts
52 install scripts had a project website in '# Source:' but no GitHub
link. Merged the GitHub repo URL into the Source header as:
  # Source: https://website.com/ | Github: https://github.com/OWNER/REPO

Repos sourced from fetch_and_deploy_gh_release calls, get_latest_github_release
calls, or known project repos for npm/pip installed apps.

Two scripts (fumadocs, pve-scripts-local) had no Source line at all —
added one. Shinobi skipped (GitLab-only, no GitHub repo).
2026-02-24 14:21:43 +01:00
CanbiZ (MickLesk)
7bb14b4d22 Update build.func 2026-02-24 14:03:09 +01:00
CanbiZ (MickLesk)
75c0b1bfc9 fix(error-handler): prevent silent() from re-enabling error handling during recovery
Root cause: silent() (core.func) unconditionally calls set -Eeuo pipefail
and trap 'error_handler' ERR after every command. When build_container()
intentionally disables error handling for its recovery section, any
intermediate call through silent()/ re-enables it. This causes the
grep/sed pipeline for missing_cmd extraction to trigger error_handler
(grep returns exit code 1 on no match + pipefail = fatal).

Fixes:
1. silent(): Save errexit state before disabling, only restore if it was
   active. Callers that intentionally disabled error handling (e.g.
   build_container recovery) are no longer silently re-enabled.

2. build.func: Add || true to missing_cmd grep pipeline as defense-in-depth
   against pipeline failure propagation.

3. build.func: Add explicit set +Eeuo pipefail / trap - ERR after
   post_update_to_api() call, before error classification grep/sed section.

4. build.func: Remove stale global combined_log variable from variables()
   that used a different path format (/tmp/install-SESSION-combined.log)
   than the actual local variable (/tmp/NSAPP-CTID-SESSION.log). The global
   was never written to and caused confusion when error_handler displayed it.
2026-02-24 13:51:27 +01:00
17 changed files with 136 additions and 289 deletions

View File

@@ -407,53 +407,27 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-02-25
### 🚀 Updated Scripts
- #### 🔧 Refactor
- OpenProject: Various fixes [@tremor021](https://github.com/tremor021) ([#12246](https://github.com/community-scripts/ProxmoxVE/pull/12246))
### 💾 Core
- #### 🐞 Bug Fixes
- Fix detection of ssh keys [@1-tempest](https://github.com/1-tempest) ([#12230](https://github.com/community-scripts/ProxmoxVE/pull/12230))
## 2026-02-24 ## 2026-02-24
### 🚀 Updated Scripts ### 🚀 Updated Scripts
- several scripts: add additional github link in source [@MickLesk](https://github.com/MickLesk) ([#12282](https://github.com/community-scripts/ProxmoxVE/pull/12282))
- adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248)) - adds further documentation during the installation script. [@d12rio](https://github.com/d12rio) ([#12248](https://github.com/community-scripts/ProxmoxVE/pull/12248))
- #### 🐞 Bug Fixes - #### 🐞 Bug Fixes
- [Fix] PatchMon: remove VITE_API_URL from frontend env [@vhsdream](https://github.com/vhsdream) ([#12294](https://github.com/community-scripts/ProxmoxVE/pull/12294))
- fix(searxng): remove orphaned fi causing syntax error [@mark-jeffrey](https://github.com/mark-jeffrey) ([#12283](https://github.com/community-scripts/ProxmoxVE/pull/12283))
- Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264)) - Refactor n8n [@MickLesk](https://github.com/MickLesk) ([#12264](https://github.com/community-scripts/ProxmoxVE/pull/12264))
- Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247)) - Firefly: PHP bump [@tremor021](https://github.com/tremor021) ([#12247](https://github.com/community-scripts/ProxmoxVE/pull/12247))
- #### ✨ New Features - #### ✨ New Features
- Databasus: add mariadb path for mysql/mariadb backups | add mongodb database tools [@MickLesk](https://github.com/MickLesk) ([#12259](https://github.com/community-scripts/ProxmoxVE/pull/12259))
- make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207)) - make searxng updateable [@shtefko](https://github.com/shtefko) ([#12207](https://github.com/community-scripts/ProxmoxVE/pull/12207))
- #### 💥 Breaking Changes
- fix: wealthfolio for v3 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11765](https://github.com/community-scripts/ProxmoxVE/pull/11765))
- #### 🔧 Refactor - #### 🔧 Refactor
- bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265)) - bump various scripts from Node 22 to 24 [@MickLesk](https://github.com/MickLesk) ([#12265](https://github.com/community-scripts/ProxmoxVE/pull/12265))
### 💾 Core ### 💾 Core
- #### 🐞 Bug Fixes
- core: fix broken "command not found" after err_trap [@MickLesk](https://github.com/MickLesk) ([#12280](https://github.com/community-scripts/ProxmoxVE/pull/12280))
- #### ✨ New Features - #### ✨ New Features
- tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261)) - tools.func: add get_latest_gh_tag helper function [@MickLesk](https://github.com/MickLesk) ([#12261](https://github.com/community-scripts/ProxmoxVE/pull/12261))

View File

@@ -38,31 +38,6 @@ function update_script() {
cp /opt/databasus/.env /opt/databasus.env.bak cp /opt/databasus/.env /opt/databasus.env.bak
msg_ok "Backed up Configuration" msg_ok "Backed up Configuration"
msg_info "Ensuring Database Clients"
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
if ! command -v mongodump &>/dev/null; then
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-100.14.1.deb"
fi
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore
# Create MariaDB and MySQL client symlinks for compatibility
ensure_dependencies mariadb-client
mkdir -p /usr/local/mariadb-{10.6,12.1}/bin /usr/local/mysql-{5.7,8.0,8.4,9}/bin /usr/local/mongodb-database-tools/bin
for dir in /usr/local/mariadb-{10.6,12.1}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mariadb-dump"
ln -sf /usr/bin/mariadb "$dir/mariadb"
done
for dir in /usr/local/mysql-{5.7,8.0,8.4,9}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mysqldump"
ln -sf /usr/bin/mariadb "$dir/mysql"
done
msg_ok "Ensured Database Clients"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
msg_info "Updating Databasus" msg_info "Updating Databasus"
@@ -74,7 +49,6 @@ function update_script() {
$STD /root/go/bin/swag init -g cmd/main.go -o swagger $STD /root/go/bin/swag init -g cmd/main.go -o swagger
$STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go $STD env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o databasus ./cmd/main.go
mv /opt/databasus/backend/databasus /opt/databasus/databasus mv /opt/databasus/backend/databasus /opt/databasus/databasus
mkdir -p /opt/databasus/ui/build
cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/ cp -r /opt/databasus/frontend/dist/* /opt/databasus/ui/build/
cp -r /opt/databasus/backend/migrations /opt/databasus/ cp -r /opt/databasus/backend/migrations /opt/databasus/
chown -R postgres:postgres /opt/databasus chown -R postgres:postgres /opt/databasus

View File

@@ -11,7 +11,7 @@ var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}" var_ram="${var_ram:-4096}"
var_disk="${var_disk:-8}" var_disk="${var_disk:-8}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
header_info "$APP" header_info "$APP"
@@ -27,11 +27,10 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
msg_info "Updating ${APP}"
msg_info "Updating OpenProject"
$STD apt update $STD apt update
$STD apt install --only-upgrade -y openproject $STD apt install --only-upgrade -y openproject
msg_ok "Updated OpenProject" msg_ok "Updated ${APP}"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }

View File

@@ -51,10 +51,13 @@ function update_script() {
msg_info "Updating PatchMon" msg_info "Updating PatchMon"
VERSION=$(get_latest_github_release "PatchMon/PatchMon") VERSION=$(get_latest_github_release "PatchMon/PatchMon")
PROTO="$(sed -n '/SERVER_PROTOCOL/s/[^=]*=//p' /opt/backend.env)"
HOST="$(sed -n '/SERVER_HOST/s/[^=]*=//p' /opt/backend.env)"
SERVER_PORT="$(sed -n '/SERVER_PORT/s/[^=]*=//p' /opt/backend.env)" SERVER_PORT="$(sed -n '/SERVER_PORT/s/[^=]*=//p' /opt/backend.env)"
[[ "$PROTO" == "http" ]] && PORT=":3001"
sed -i 's/PORT=3399/PORT=3001/' /opt/backend.env sed -i 's/PORT=3399/PORT=3001/' /opt/backend.env
sed -i -e "s/VERSION=.*/VERSION=$VERSION/" \ sed -i -e "s/VERSION=.*/VERSION=$VERSION/" \
-e '/^VITE_API_URL/d' /opt/frontend.env -e "\|VITE_API_URL=|s|http.*|${PROTO:-http}://${HOST:-$LOCAL_IP}${PORT:-}/api/v1|" /opt/frontend.env
export NODE_ENV=production export NODE_ENV=production
cd /opt/patchmon cd /opt/patchmon
$STD npm install --no-audit --no-fund --no-save --ignore-scripts $STD npm install --no-audit --no-fund --no-save --ignore-scripts

View File

@@ -52,6 +52,7 @@ function update_script() {
systemctl start searxng systemctl start searxng
msg_ok "Started Services" msg_ok "Started Services"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi
exit exit
} }
start start

View File

@@ -43,15 +43,16 @@ function update_script() {
msg_info "Building Frontend (patience)" msg_info "Building Frontend (patience)"
cd /opt/wealthfolio cd /opt/wealthfolio
export BUILD_TARGET=web
$STD pnpm install --frozen-lockfile $STD pnpm install --frozen-lockfile
$STD pnpm --filter frontend... build $STD pnpm tsc
$STD pnpm vite build
msg_ok "Built Frontend" msg_ok "Built Frontend"
msg_info "Building Backend (patience)" msg_info "Building Backend (patience)"
cd /opt/wealthfolio/src-server
source ~/.cargo/env source ~/.cargo/env
$STD cargo build --release --manifest-path apps/server/Cargo.toml $STD cargo build --release --manifest-path Cargo.toml
cp /opt/wealthfolio/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server cp /opt/wealthfolio/src-server/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server
chmod +x /usr/local/bin/wealthfolio-server chmod +x /usr/local/bin/wealthfolio-server
msg_ok "Built Backend" msg_ok "Built Backend"
@@ -62,7 +63,7 @@ function update_script() {
msg_ok "Restored Data" msg_ok "Restored Data"
msg_info "Cleaning Up" msg_info "Cleaning Up"
rm -rf /opt/wealthfolio/target rm -rf /opt/wealthfolio/src-server/target
rm -rf /root/.cargo/registry rm -rf /root/.cargo/registry
rm -rf /opt/wealthfolio/node_modules rm -rf /opt/wealthfolio/node_modules
msg_ok "Cleaned Up" msg_ok "Cleaned Up"

View File

@@ -1,5 +1,5 @@
{ {
"generated": "2026-02-25T06:25:10Z", "generated": "2026-02-24T12:15:44Z",
"versions": [ "versions": [
{ {
"slug": "2fauth", "slug": "2fauth",
@@ -200,9 +200,9 @@
{ {
"slug": "cleanuparr", "slug": "cleanuparr",
"repo": "Cleanuparr/Cleanuparr", "repo": "Cleanuparr/Cleanuparr",
"version": "v2.7.5", "version": "v2.7.4",
"pinned": false, "pinned": false,
"date": "2026-02-24T17:11:50Z" "date": "2026-02-23T18:41:16Z"
}, },
{ {
"slug": "cloudreve", "slug": "cloudreve",
@@ -214,9 +214,9 @@
{ {
"slug": "comfyui", "slug": "comfyui",
"repo": "comfyanonymous/ComfyUI", "repo": "comfyanonymous/ComfyUI",
"version": "v0.15.0", "version": "v0.14.2",
"pinned": false, "pinned": false,
"date": "2026-02-24T20:56:09Z" "date": "2026-02-18T06:12:02Z"
}, },
{ {
"slug": "commafeed", "slug": "commafeed",
@@ -361,16 +361,16 @@
{ {
"slug": "endurain", "slug": "endurain",
"repo": "endurain-project/endurain", "repo": "endurain-project/endurain",
"version": "v0.17.5", "version": "v0.17.4",
"pinned": false, "pinned": false,
"date": "2026-02-24T14:51:03Z" "date": "2026-02-11T04:54:22Z"
}, },
{ {
"slug": "ersatztv", "slug": "ersatztv",
"repo": "ErsatzTV/ErsatzTV", "repo": "ErsatzTV/ErsatzTV",
"version": "v26.3.0", "version": "v26.2.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T21:36:34Z" "date": "2026-02-02T20:54:26Z"
}, },
{ {
"slug": "excalidraw", "slug": "excalidraw",
@@ -613,9 +613,9 @@
{ {
"slug": "jackett", "slug": "jackett",
"repo": "Jackett/Jackett", "repo": "Jackett/Jackett",
"version": "v0.24.1205", "version": "v0.24.1193",
"pinned": false, "pinned": false,
"date": "2026-02-25T05:49:14Z" "date": "2026-02-24T05:58:04Z"
}, },
{ {
"slug": "jellystat", "slug": "jellystat",
@@ -746,9 +746,9 @@
{ {
"slug": "libretranslate", "slug": "libretranslate",
"repo": "LibreTranslate/LibreTranslate", "repo": "LibreTranslate/LibreTranslate",
"version": "v1.9.4", "version": "v1.9.3",
"pinned": false, "pinned": false,
"date": "2026-02-24T17:06:05Z" "date": "2026-02-21T19:08:33Z"
}, },
{ {
"slug": "lidarr", "slug": "lidarr",
@@ -977,9 +977,9 @@
{ {
"slug": "open-archiver", "slug": "open-archiver",
"repo": "LogicLabs-OU/OpenArchiver", "repo": "LogicLabs-OU/OpenArchiver",
"version": "v0.4.2", "version": "v0.4.1",
"pinned": false, "pinned": false,
"date": "2026-02-24T20:47:40Z" "date": "2026-01-17T12:24:31Z"
}, },
{ {
"slug": "opencloud", "slug": "opencloud",
@@ -1208,9 +1208,9 @@
{ {
"slug": "pulse", "slug": "pulse",
"repo": "rcourtman/Pulse", "repo": "rcourtman/Pulse",
"version": "v5.1.14", "version": "v5.1.13",
"pinned": false, "pinned": false,
"date": "2026-02-25T00:11:58Z" "date": "2026-02-22T12:40:41Z"
}, },
{ {
"slug": "pve-scripts-local", "slug": "pve-scripts-local",
@@ -1285,9 +1285,9 @@
{ {
"slug": "recyclarr", "slug": "recyclarr",
"repo": "recyclarr/recyclarr", "repo": "recyclarr/recyclarr",
"version": "v8.3.1", "version": "v8.2.1",
"pinned": false, "pinned": false,
"date": "2026-02-25T01:01:31Z" "date": "2026-02-22T19:19:49Z"
}, },
{ {
"slug": "reitti", "slug": "reitti",
@@ -1334,9 +1334,9 @@
{ {
"slug": "scanopy", "slug": "scanopy",
"repo": "scanopy/scanopy", "repo": "scanopy/scanopy",
"version": "v0.14.8", "version": "v0.14.7",
"pinned": false, "pinned": false,
"date": "2026-02-24T16:45:30Z" "date": "2026-02-23T01:36:44Z"
}, },
{ {
"slug": "scraparr", "slug": "scraparr",
@@ -1369,9 +1369,9 @@
{ {
"slug": "semaphore", "slug": "semaphore",
"repo": "semaphoreui/semaphore", "repo": "semaphoreui/semaphore",
"version": "v2.17.14", "version": "v2.17.12",
"pinned": false, "pinned": false,
"date": "2026-02-24T14:27:03Z" "date": "2026-02-20T09:16:50Z"
}, },
{ {
"slug": "shelfmark", "slug": "shelfmark",
@@ -1383,9 +1383,9 @@
{ {
"slug": "signoz", "slug": "signoz",
"repo": "SigNoz/signoz-otel-collector", "repo": "SigNoz/signoz-otel-collector",
"version": "v0.144.1", "version": "v0.142.1",
"pinned": false, "pinned": false,
"date": "2026-02-25T05:57:17Z" "date": "2026-02-21T18:04:07Z"
}, },
{ {
"slug": "silverbullet", "slug": "silverbullet",
@@ -1621,9 +1621,9 @@
{ {
"slug": "upgopher", "slug": "upgopher",
"repo": "wanetty/upgopher", "repo": "wanetty/upgopher",
"version": "v1.14.0", "version": "v1.13.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T22:43:34Z" "date": "2026-01-16T20:26:34Z"
}, },
{ {
"slug": "upsnap", "slug": "upsnap",
@@ -1679,7 +1679,7 @@
"repo": "meilisearch/meilisearch", "repo": "meilisearch/meilisearch",
"version": "v1.36.0", "version": "v1.36.0",
"pinned": false, "pinned": false,
"date": "2026-02-23T08:13:32Z" "date": ""
}, },
{ {
"slug": "warracker", "slug": "warracker",
@@ -1712,9 +1712,9 @@
{ {
"slug": "wealthfolio", "slug": "wealthfolio",
"repo": "afadil/wealthfolio", "repo": "afadil/wealthfolio",
"version": "v3.0.0", "version": "v2.1.0",
"pinned": false, "pinned": false,
"date": "2026-02-24T22:37:05Z" "date": "2025-12-01T21:57:36Z"
}, },
{ {
"slug": "web-check", "slug": "web-check",
@@ -1747,9 +1747,9 @@
{ {
"slug": "wizarr", "slug": "wizarr",
"repo": "wizarrrr/wizarr", "repo": "wizarrrr/wizarr",
"version": "v2026.2.1", "version": "v2026.2.0",
"pinned": false, "pinned": false,
"date": "2026-02-25T01:07:56Z" "date": "2026-02-23T19:25:28Z"
}, },
{ {
"slug": "writefreely", "slug": "writefreely",
@@ -1768,9 +1768,9 @@
{ {
"slug": "yubal", "slug": "yubal",
"repo": "guillevc/yubal", "repo": "guillevc/yubal",
"version": "v0.6.2", "version": "v0.6.1",
"pinned": false, "pinned": false,
"date": "2026-02-24T15:15:46Z" "date": "2026-02-18T23:24:16Z"
}, },
{ {
"slug": "zigbee2mqtt", "slug": "zigbee2mqtt",
@@ -1789,9 +1789,9 @@
{ {
"slug": "zitadel", "slug": "zitadel",
"repo": "zitadel/zitadel", "repo": "zitadel/zitadel",
"version": "v4.11.1", "version": "v4.11.0",
"pinned": false, "pinned": false,
"date": "2026-02-25T06:13:13Z" "date": "2026-02-16T09:48:38Z"
}, },
{ {
"slug": "zoraxy", "slug": "zoraxy",

View File

@@ -23,7 +23,7 @@
"ram": 4096, "ram": 4096,
"hdd": 8, "hdd": 8,
"os": "Debian", "os": "Debian",
"version": "13" "version": "12"
} }
} }
], ],
@@ -31,10 +31,5 @@
"username": "admin", "username": "admin",
"password": "admin" "password": "admin"
}, },
"notes": [ "notes": []
{
"text": "If you want to update from v15.x to v17.x, please read `https://www.openproject.org/docs/installation-and-operations/operation/upgrading/#major-upgrades` before doing so.",
"type": "warning"
}
]
} }

View File

@@ -16,39 +16,13 @@ update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
nginx \ nginx \
valkey \ valkey
mariadb-client \
rclone
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
setup_go setup_go
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs
msg_info "Installing Database Clients"
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools" "100." || echo "100.14.1")
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-${MONGO_VERSION}.deb"
mkdir -p /usr/local/mongodb-database-tools/bin
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore
# Create MariaDB and MySQL client symlinks for compatibility
mkdir -p /usr/local/mariadb-{10.6,12.1}/bin /usr/local/mysql-{5.7,8.0,8.4,9}/bin
for dir in /usr/local/mariadb-{10.6,12.1}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mariadb-dump"
ln -sf /usr/bin/mariadb "$dir/mariadb"
done
for dir in /usr/local/mysql-{5.7,8.0,8.4,9}/bin; do
ln -sf /usr/bin/mariadb-dump "$dir/mysqldump"
ln -sf /usr/bin/mariadb "$dir/mysql"
done
msg_ok "Installed Database Clients"
fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus" fetch_and_deploy_gh_release "databasus" "databasus/databasus" "tarball" "latest" "/opt/databasus"
msg_info "Building Databasus (Patience)" msg_info "Building Databasus (Patience)"
@@ -73,6 +47,10 @@ msg_ok "Built Databasus"
msg_info "Configuring Databasus" msg_info "Configuring Databasus"
JWT_SECRET=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32) ENCRYPTION_KEY=$(openssl rand -hex 32)
# Create PostgreSQL version symlinks for compatibility
for v in 12 13 14 15 16 18; do
ln -sf /usr/lib/postgresql/17 /usr/lib/postgresql/$v
done
# Install goose for migrations # Install goose for migrations
$STD go install github.com/pressly/goose/v3/cmd/goose@latest $STD go install github.com/pressly/goose/v3/cmd/goose@latest
ln -sf /root/go/bin/goose /usr/local/bin/goose ln -sf /root/go/bin/goose /usr/local/bin/goose

View File

@@ -72,7 +72,7 @@ cat <<EOF >/etc/apache2/sites-available/firefly.conf
</VirtualHost> </VirtualHost>
EOF EOF
chown www-data:www-data /opt/firefly/storage/oauth-*.key chown www-data:www-data /opt/firefly/storage/oauth-*.key
$STD a2enmod php8.5 $STD a2enmod php8.4
$STD a2enmod rewrite $STD a2enmod rewrite
$STD a2ensite firefly.conf $STD a2ensite firefly.conf
$STD a2dissite 000-default.conf $STD a2dissite 000-default.conf

View File

@@ -14,30 +14,19 @@ network_check
update_os update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y apt-transport-https
apt-transport-https \
build-essential \
autoconf
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
PG_DB_NAME="openproject" PG_DB_USER="openproject" setup_postgresql_db PG_DB_NAME="openproject" PG_DB_USER="openproject" setup_postgresql_db
API_KEY=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13) API_KEY=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
echo "OpenProject API Key: $API_KEY" >>~/openproject.creds echo "OpenProject API Key: $API_KEY" >>~/openproject.creds
fetch_and_deploy_gh_release "jemalloc" "jemalloc/jemalloc" "tarball"
msg_info "Compiling jemalloc (Patience)" msg_info "Setting up OpenProject Repository"
cd /opt/jemalloc curl -fsSL "https://dl.packager.io/srv/opf/openproject/key" | gpg --dearmor >/etc/apt/trusted.gpg.d/packager-io.gpg
$STD ./autogen.sh curl -fsSL "https://dl.packager.io/srv/opf/openproject/stable/15/installer/debian/12.repo" -o "/etc/apt/sources.list.d/openproject.list"
$STD make $STD apt update
$STD make install msg_ok "Setup OpenProject Repository"
msg_ok "Compiled jemalloc"
setup_deb822_repo \
"openproject" \
"https://packages.openproject.com/srv/deb/opf/openproject/gpg-key.gpg" \
"https://packages.openproject.com/srv/deb/opf/openproject/stable/17/debian/" \
"12"
msg_info "Installing OpenProject" msg_info "Installing OpenProject"
$STD apt install -y openproject $STD apt install -y openproject
@@ -71,11 +60,6 @@ openproject/admin_email admin@example.net
openproject/default_language en openproject/default_language en
EOF EOF
$STD sudo openproject configure $STD sudo openproject configure
systemctl stop openproject-web-1
if ! grep -qF 'Environment=LD_PRELOAD=/usr/local/lib/libjemalloc.so.2' /etc/systemd/system/openproject-web-1.service; then
sed -i '/^\[Service\]/a Environment=LD_PRELOAD=/usr/local/lib/libjemalloc.so.2' /etc/systemd/system/openproject-web-1.service
fi
systemctl start openproject-web-1
msg_ok "Configured OpenProject" msg_ok "Configured OpenProject"
motd_ssh motd_ssh

View File

@@ -34,6 +34,7 @@ $STD npm install --no-audit --no-fund --no-save --ignore-scripts
cd /opt/patchmon/frontend cd /opt/patchmon/frontend
cat <<EOF >./.env cat <<EOF >./.env
VITE_API_URL=http://${LOCAL_IP}:3001/api/v1
VITE_APP_NAME=PatchMon VITE_APP_NAME=PatchMon
VITE_APP_VERSION=${VERSION} VITE_APP_VERSION=${VERSION}
EOF EOF

View File

@@ -28,15 +28,15 @@ fetch_and_deploy_gh_release "wealthfolio" "afadil/wealthfolio" "tarball"
msg_info "Building Frontend (patience)" msg_info "Building Frontend (patience)"
cd /opt/wealthfolio cd /opt/wealthfolio
export BUILD_TARGET=web
$STD pnpm install --frozen-lockfile $STD pnpm install --frozen-lockfile
$STD pnpm --filter frontend... build $STD pnpm tsc
$STD pnpm vite build
msg_ok "Built Frontend" msg_ok "Built Frontend"
msg_info "Building Backend (patience)" msg_info "Building Backend (patience)"
source ~/.cargo/env cd /opt/wealthfolio/src-server
$STD cargo build --release --manifest-path apps/server/Cargo.toml $STD cargo build --release --manifest-path Cargo.toml
cp /opt/wealthfolio/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server cp /opt/wealthfolio/src-server/target/release/wealthfolio-server /usr/local/bin/wealthfolio-server
chmod +x /usr/local/bin/wealthfolio-server chmod +x /usr/local/bin/wealthfolio-server
msg_ok "Built Backend" msg_ok "Built Backend"
@@ -58,7 +58,7 @@ echo "WF_PASSWORD=${WF_PASSWORD}" >~/wealthfolio.creds
msg_ok "Configured Wealthfolio" msg_ok "Configured Wealthfolio"
msg_info "Cleaning Up" msg_info "Cleaning Up"
rm -rf /opt/wealthfolio/target rm -rf /opt/wealthfolio/src-server/target
rm -rf /root/.cargo/registry rm -rf /root/.cargo/registry
rm -rf /opt/wealthfolio/node_modules rm -rf /opt/wealthfolio/node_modules
msg_ok "Cleaned Up" msg_ok "Cleaned Up"

View File

@@ -312,8 +312,7 @@ json_escape() {
s=${s//$'\r'/} s=${s//$'\r'/}
s=${s//$'\t'/\\t} s=${s//$'\t'/\\t}
# Remove any remaining control characters (0x00-0x1F except those already handled) # Remove any remaining control characters (0x00-0x1F except those already handled)
# Also remove DEL (0x7F) and invalid high bytes that break JSON parsers s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037')
s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037\177')
printf '%s' "$s" printf '%s' "$s"
} }
@@ -983,7 +982,7 @@ EOF
fi fi
# All 3 attempts failed — do NOT set POST_UPDATE_DONE=true. # All 3 attempts failed — do NOT set POST_UPDATE_DONE=true.
# This allows the EXIT trap (on_exit in error_handler.func) to retry. # This allows the EXIT trap (api_exit_script) to retry with 3 fresh attempts.
# No infinite loop risk: EXIT trap fires exactly once. # No infinite loop risk: EXIT trap fires exactly once.
} }

View File

@@ -48,8 +48,7 @@ variables() {
EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase) EXECUTION_ID="${RANDOM_UUID}" # Unique execution ID for telemetry record identification (unique-indexed in PocketBase)
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log
# NOTE: combined_log is constructed locally in build_container() and ensure_log_on_host() combined_log="/tmp/install-${SESSION_ID}-combined.log" # Combined log (build + install) for failed installations
# as "/tmp/${NSAPP}-${CTID}-${SESSION_ID}.log" (requires CTID, not available here)
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}" CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# Parse dev_mode early # Parse dev_mode early
@@ -693,7 +692,7 @@ find_host_ssh_keys() {
/^[[:space:]]*#/ {next} /^[[:space:]]*#/ {next}
/^[[:space:]]*$/ {next} /^[[:space:]]*$/ {next}
{print} {print}
' | grep -E -c "$re" || true) ' | grep -E -c '"$re"' || true)
if ((c > 0)); then if ((c > 0)); then
files+=("$f") files+=("$f")
@@ -1851,7 +1850,7 @@ advanced_settings() {
# ═══════════════════════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════════════════════
# STEP 2: Root Password # STEP 2: Root Password
# ════════════════════════════════════════════════════════════════════════<EFBFBD><EFBFBD><EFBFBD>══ # ══════════════════════════════════════════════════════════════════════════
2) 2)
if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \ if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
--title "ROOT PASSWORD" \ --title "ROOT PASSWORD" \
@@ -4098,11 +4097,6 @@ EOF'
# Installation failed? # Installation failed?
if [[ $install_exit_code -ne 0 ]]; then if [[ $install_exit_code -ne 0 ]]; then
# Prevent SIGTSTP (Ctrl+Z) from suspending the script during recovery.
# In non-interactive shells (bash -c), background processes (spinner) can
# trigger terminal-related signals that stop the entire process group.
trap '' TSTP
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})" msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy install log from container BEFORE API call so get_error_text() can read it # Copy install log from container BEFORE API call so get_error_text() can read it
@@ -4178,19 +4172,7 @@ EOF'
fi fi
# Report failure to telemetry API (now with log available on host) # Report failure to telemetry API (now with log available on host)
# NOTE: Do NOT use msg_info/spinner here — the background spinner process
# causes SIGTSTP in non-interactive shells (bash -c "$(curl ...)"), which
# stops the entire process group and prevents the recovery dialog from appearing.
$STD echo -e "${TAB}⏳ Reporting failure to telemetry..."
post_update_to_api "failed" "$install_exit_code" post_update_to_api "failed" "$install_exit_code"
$STD echo -e "${TAB}${CM:-} Failure reported"
# Defense-in-depth: Ensure error handling stays disabled during recovery.
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
# and trap 'error_handler' ERR. If any code path above called such a function,
# the grep/sed pipelines below would trigger error_handler on non-match (exit 1).
set +Eeuo pipefail
trap - ERR
# Show combined log location # Show combined log location
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
@@ -4305,7 +4287,7 @@ EOF'
if [[ "$is_cmd_not_found" == true ]]; then if [[ "$is_cmd_not_found" == true ]]; then
local missing_cmd="" local missing_cmd=""
if [[ -f "$combined_log" ]]; then if [[ -f "$combined_log" ]]; then
missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" 2>/dev/null | tail -1 | sed 's/: command not found//') || true missing_cmd=$(grep -oiE '[a-zA-Z0-9_.-]+: command not found' "$combined_log" | tail -1 | sed 's/: command not found//')
fi fi
if [[ -n "$missing_cmd" ]]; then if [[ -n "$missing_cmd" ]]; then
echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}" echo -e "${TAB}${INFO} Missing command: ${GN}${missing_cmd}${CL}"
@@ -4547,12 +4529,8 @@ EOF'
# Force one final status update attempt after cleanup # Force one final status update attempt after cleanup
# This ensures status is updated even if the first attempt failed (e.g., HTTP 400) # This ensures status is updated even if the first attempt failed (e.g., HTTP 400)
$STD echo -e "${TAB}⏳ Finalizing telemetry report..."
post_update_to_api "failed" "$install_exit_code" "force" post_update_to_api "failed" "$install_exit_code" "force"
$STD echo -e "${TAB}${CM:-} Telemetry finalized"
# Restore default SIGTSTP handling before exit
trap - TSTP
exit $install_exit_code exit $install_exit_code
fi fi
@@ -5622,21 +5600,44 @@ ensure_log_on_host() {
fi fi
} }
# ============================================================================== # ------------------------------------------------------------------------------
# TRAP MANAGEMENT # api_exit_script()
# ==============================================================================
# All traps (ERR, EXIT, INT, TERM, HUP) are set by catch_errors() in
# error_handler.func — called at the top of this file after sourcing.
# #
# Do NOT set duplicate traps here. The handlers in error_handler.func # - Exit trap handler for reporting to API telemetry
# (on_exit, on_interrupt, on_terminate, on_hangup, error_handler) already: # - Captures exit code and reports to PocketBase using centralized error descriptions
# - Send telemetry via post_update_to_api / _send_abort_telemetry # - Uses explain_exit_code() from api.func for consistent error messages
# - Stop orphaned containers via _stop_container_if_installing # - ALWAYS sends telemetry FIRST before log collection to prevent pct pull
# - Collect logs via ensure_log_on_host # hangs from blocking status updates (container may be dead/unresponsive)
# - Clean up lock files and spinner processes # - For non-zero exit codes: posts "failed" status
# # - For zero exit codes where post_update_to_api was never called:
# Previously, inline traps here overwrote catch_errors() traps, causing: # catches orphaned "installing" records (e.g., script exited cleanly
# - error_handler() never fired (no error output, no cleanup dialog) # but description() was never reached)
# - on_hangup() never fired (SSH disconnect → stuck records) # ------------------------------------------------------------------------------
# - Duplicated logic in two places (hard to debug) api_exit_script() {
# ============================================================================== local exit_code=$?
if [ $exit_code -ne 0 ]; then
# ALWAYS send telemetry FIRST - ensure status is reported even if
# ensure_log_on_host hangs (e.g. pct pull on dead container)
post_update_to_api "failed" "$exit_code" 2>/dev/null || true
# Best-effort log collection (non-critical after telemetry is sent)
if declare -f ensure_log_on_host >/dev/null 2>&1; then
ensure_log_on_host 2>/dev/null || true
fi
# Stop orphaned container if we're in the install phase
if [[ "${CONTAINER_INSTALLING:-}" == "true" && -n "${CTID:-}" ]] && command -v pct &>/dev/null; then
pct stop "$CTID" 2>/dev/null || true
fi
elif [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
# Script exited with 0 but never sent a completion status
# exit_code=0 is never an error — report as success
post_update_to_api "done" "0"
fi
}
if command -v pveversion >/dev/null 2>&1; then
trap 'api_exit_script' EXIT
fi
trap 'local _ec=$?; if [[ $_ec -ne 0 ]]; then post_update_to_api "failed" "$_ec" 2>/dev/null || true; if declare -f ensure_log_on_host &>/dev/null; then ensure_log_on_host 2>/dev/null || true; fi; fi' ERR
trap 'post_update_to_api "failed" "129" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 129' SIGHUP
trap 'post_update_to_api "failed" "130" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 130' SIGINT
trap 'post_update_to_api "failed" "143" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 143' SIGTERM

View File

@@ -490,8 +490,6 @@ log_section() {
# - Executes command with output redirected to active log file # - Executes command with output redirected to active log file
# - On error: displays last 20 lines of log and exits with original exit code # - On error: displays last 20 lines of log and exits with original exit code
# - Temporarily disables error trap to capture exit code correctly # - Temporarily disables error trap to capture exit code correctly
# - Saves and restores previous error handling state (so callers that
# intentionally disabled error handling aren't silently re-enabled)
# - Sources explain_exit_code() for detailed error messages # - Sources explain_exit_code() for detailed error messages
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
silent() { silent() {
@@ -509,23 +507,14 @@ silent() {
return 0 return 0
fi fi
# Save current error handling state before disabling
# This prevents re-enabling error handling when the caller intentionally
# disabled it (e.g. build_container recovery section)
local _restore_errexit=false
[[ "$-" == *e* ]] && _restore_errexit=true
set +Eeuo pipefail set +Eeuo pipefail
trap - ERR trap - ERR
"$@" >>"$logfile" 2>&1 "$@" >>"$logfile" 2>&1
local rc=$? local rc=$?
# Restore error handling ONLY if it was active before this call
if $_restore_errexit; then
set -Eeuo pipefail set -Eeuo pipefail
trap 'error_handler' ERR trap 'error_handler' ERR
fi
if [[ $rc -ne 0 ]]; then if [[ $rc -ne 0 ]]; then
# Source explain_exit_code if needed # Source explain_exit_code if needed

View File

@@ -199,16 +199,11 @@ error_handler() {
return 0 return 0
fi fi
# Stop spinner and restore cursor FIRST — before any output
# This prevents spinner text overlapping with error messages
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h"
local explanation local explanation
explanation="$(explain_exit_code "$exit_code")" explanation="$(explain_exit_code "$exit_code")"
printf "\e[?25h"
# ALWAYS report failure to API immediately - don't wait for container checks # ALWAYS report failure to API immediately - don't wait for container checks
# This ensures we capture failures that occur before/after container exists # This ensures we capture failures that occur before/after container exists
if declare -f post_update_to_api &>/dev/null; then if declare -f post_update_to_api &>/dev/null; then
@@ -364,39 +359,9 @@ _send_abort_telemetry() {
command -v curl &>/dev/null || return 0 command -v curl &>/dev/null || return 0
[[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0 [[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0
[[ -z "${RANDOM_UUID:-}" ]] && return 0 [[ -z "${RANDOM_UUID:-}" ]] && return 0
curl -fsS -m 5 -X POST "${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" \
# Collect last 20 log lines for error diagnosis (best-effort)
local error_text=""
if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then
error_text=$(tail -n 20 "$INSTALL_LOG" 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' '|' | sed 's/|$//' | tr -d '\000-\010\013\014\016-\037\177') || true
fi
# Calculate duration if start time is available
local duration=""
if [[ -n "${DIAGNOSTICS_START_TIME:-}" ]]; then
duration=$(($(date +%s) - DIAGNOSTICS_START_TIME))
fi
# Build JSON payload with error context
local payload
payload="{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}"
[[ -n "$error_text" ]] && payload="${payload},\"error\":\"${error_text}\""
[[ -n "$duration" ]] && payload="${payload},\"duration\":${duration}"
payload="${payload}}"
local api_url="${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}"
# 2 attempts (retry once on failure) — original had no retry
local attempt
for attempt in 1 2; do
if curl -fsS -m 5 -X POST "$api_url" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$payload" &>/dev/null; then -d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}}" &>/dev/null || true
return 0
fi
[[ $attempt -eq 1 ]] && sleep 1
done
return 0
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@@ -472,12 +437,6 @@ on_exit() {
# - Exits with code 130 (128 + SIGINT=2) # - Exits with code 130 (128 + SIGINT=2)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_interrupt() { on_interrupt() {
# Stop spinner and restore cursor before any output
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h" 2>/dev/null || true
_send_abort_telemetry "130" _send_abort_telemetry "130"
_stop_container_if_installing _stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
@@ -497,12 +456,6 @@ on_interrupt() {
# - Exits with code 143 (128 + SIGTERM=15) # - Exits with code 143 (128 + SIGTERM=15)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_terminate() { on_terminate() {
# Stop spinner and restore cursor before any output
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h" 2>/dev/null || true
_send_abort_telemetry "143" _send_abort_telemetry "143"
_stop_container_if_installing _stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then if declare -f msg_error >/dev/null 2>&1; then
@@ -525,11 +478,6 @@ on_terminate() {
# - Exits with code 129 (128 + SIGHUP=1) # - Exits with code 129 (128 + SIGHUP=1)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
on_hangup() { on_hangup() {
# Stop spinner (no cursor restore needed — terminal is already gone)
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
_send_abort_telemetry "129" _send_abort_telemetry "129"
_stop_container_if_installing _stop_container_if_installing
exit 129 exit 129