From 50d03e03dd8e59239f15e1c28c5d46b7ce36b523 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 22:54:08 +0100 Subject: [PATCH 01/12] feat(catalog): add Google Cloud CLI and Google Workspace CLI Add gcloud (Google Cloud SDK) and google-workspace-cli (googleworkspace/cli) to the tool catalog under the platform category. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/gcloud.json | 10 ++++++++++ catalog/google-workspace-cli.json | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 catalog/gcloud.json create mode 100644 catalog/google-workspace-cli.json diff --git a/catalog/gcloud.json b/catalog/gcloud.json new file mode 100644 index 0000000..06c6d26 --- /dev/null +++ b/catalog/gcloud.json @@ -0,0 +1,10 @@ +{ + "name": "gcloud", + "category": "platform", + "install_method": "custom_installer", + "description": "Google Cloud CLI for managing Google Cloud resources", + "homepage": "https://cloud.google.com/sdk/gcloud", + "binary_name": "gcloud", + "skip_upstream": true, + "notes": "Installed via Google Cloud SDK installer; self-updates with 'gcloud components update'" +} diff --git a/catalog/google-workspace-cli.json b/catalog/google-workspace-cli.json new file mode 100644 index 0000000..33eef6d --- /dev/null +++ b/catalog/google-workspace-cli.json @@ -0,0 +1,10 @@ +{ + "name": "google-workspace-cli", + "category": "platform", + "install_method": "github_release_binary", + "description": "Google Workspace command-line interface", + "homepage": "https://github.com/googleworkspace/cli", + "github_repo": "googleworkspace/cli", + "binary_name": "google-workspace-cli", + "auto_update": true +} From 1bc941b3f496df746dd5f67fa7811cd3f8eed29b Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:04:22 +0100 Subject: [PATCH 02/12] fix(catalog): address review feedback for gcloud and gws entries - gcloud: change install_method from custom_installer to manual - google-workspace-cli: fix binary_name to gws, remove auto_update Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/gcloud.json | 2 +- catalog/google-workspace-cli.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/catalog/gcloud.json b/catalog/gcloud.json index 06c6d26..34c2e27 100644 --- a/catalog/gcloud.json +++ b/catalog/gcloud.json @@ -1,7 +1,7 @@ { "name": "gcloud", "category": "platform", - "install_method": "custom_installer", + "install_method": "manual", "description": "Google Cloud CLI for managing Google Cloud resources", "homepage": "https://cloud.google.com/sdk/gcloud", "binary_name": "gcloud", diff --git a/catalog/google-workspace-cli.json b/catalog/google-workspace-cli.json index 33eef6d..c896ffa 100644 --- a/catalog/google-workspace-cli.json +++ b/catalog/google-workspace-cli.json @@ -5,6 +5,5 @@ "description": "Google Workspace command-line interface", "homepage": "https://github.com/googleworkspace/cli", "github_repo": "googleworkspace/cli", - "binary_name": "google-workspace-cli", - "auto_update": true + "binary_name": "gws" } From 0b51b7da090dada7773b3b8088c487b29e41ba6f Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:11:29 +0100 Subject: [PATCH 03/12] fix(catalog): add gcloud_installer.sh for Google Cloud CLI The install_method must match an existing installer script. Create gcloud_installer.sh following the aws_installer.sh pattern: fresh installs via sdk.cloud.google.com, updates via gcloud components update. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/gcloud.json | 2 +- scripts/installers/gcloud_installer.sh | 48 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100755 scripts/installers/gcloud_installer.sh diff --git a/catalog/gcloud.json b/catalog/gcloud.json index 34c2e27..a4679f2 100644 --- a/catalog/gcloud.json +++ b/catalog/gcloud.json @@ -1,7 +1,7 @@ { "name": "gcloud", "category": "platform", - "install_method": "manual", + "install_method": "gcloud_installer", "description": "Google Cloud CLI for managing Google Cloud resources", "homepage": "https://cloud.google.com/sdk/gcloud", "binary_name": "gcloud", diff --git a/scripts/installers/gcloud_installer.sh b/scripts/installers/gcloud_installer.sh new file mode 100755 index 0000000..4467134 --- /dev/null +++ b/scripts/installers/gcloud_installer.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Google Cloud CLI installer +set -euo pipefail + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +. "$DIR/lib/install_strategy.sh" + +TOOL="${1:-gcloud}" +CATALOG_FILE="$DIR/../catalog/$TOOL.json" + +if [ ! -f "$CATALOG_FILE" ]; then + echo "Error: Catalog file not found: $CATALOG_FILE" >&2 + exit 1 +fi + +BINARY_NAME="$(jq -r '.binary_name' "$CATALOG_FILE")" + +# Get current version +before="$(command -v "$BINARY_NAME" >/dev/null 2>&1 && "$BINARY_NAME" version 2>/dev/null | head -1 || true)" + +if command -v "$BINARY_NAME" >/dev/null 2>&1; then + # Already installed - use built-in update + "$BINARY_NAME" components update --quiet 2>&1 || true +else + # Fresh install via Google Cloud SDK installer + TMP="$(mktemp -d)" + cd "$TMP" + curl -fsSL https://sdk.cloud.google.com -o install.sh + bash install.sh --disable-prompts --install-dir="$HOME" 2>&1 + cd - >/dev/null + rm -rf "$TMP" + + # Add to PATH if not already present + GCLOUD_BIN="$HOME/google-cloud-sdk/bin" + if [ -d "$GCLOUD_BIN" ] && ! command -v "$BINARY_NAME" >/dev/null 2>&1; then + export PATH="$GCLOUD_BIN:$PATH" + fi +fi + +# Report +after="$(command -v "$BINARY_NAME" >/dev/null 2>&1 && "$BINARY_NAME" version 2>/dev/null | head -1 || true)" +path="$(command -v "$BINARY_NAME" 2>/dev/null || true)" +printf "[%s] before: %s\n" "$TOOL" "${before:-}" +printf "[%s] after: %s\n" "$TOOL" "${after:-}" +if [ -n "$path" ]; then printf "[%s] path: %s\n" "$TOOL" "$path"; fi + +# Refresh snapshot after successful installation +refresh_snapshot "$TOOL" From 25c40aa714fc8d2f57f7438908c9ab79c638bc82 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:11:57 +0100 Subject: [PATCH 04/12] fix(catalog): add download_url_template for google-workspace-cli The github_release_binary installer requires a download_url_template. Add the template matching the gws release asset naming convention. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/google-workspace-cli.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/catalog/google-workspace-cli.json b/catalog/google-workspace-cli.json index c896ffa..0e633ea 100644 --- a/catalog/google-workspace-cli.json +++ b/catalog/google-workspace-cli.json @@ -5,5 +5,10 @@ "description": "Google Workspace command-line interface", "homepage": "https://github.com/googleworkspace/cli", "github_repo": "googleworkspace/cli", - "binary_name": "gws" + "binary_name": "gws", + "download_url_template": "https://github.com/googleworkspace/cli/releases/download/{version}/gws-{arch}-unknown-linux-gnu.tar.gz", + "arch_map": { + "x86_64": "x86_64", + "aarch64": "aarch64" + } } From ca6a9ae62ec17e329d749701135b828e9fe80b8d Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:19:06 +0100 Subject: [PATCH 05/12] fix(catalog): add version_flag for tree to prevent false detection tree -v means verbose listing, not version. The generic version detection tries -v first, which outputs a directory listing where filenames like "codex.sqlite3.before-v1.9.1.bak" match the version regex, causing incorrect version detection. Specifying --version skips the -v probe. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/tree.json | 1 + 1 file changed, 1 insertion(+) diff --git a/catalog/tree.json b/catalog/tree.json index 1651dcf..3424127 100644 --- a/catalog/tree.json +++ b/catalog/tree.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/Old-Man-Programmer/tree", "github_repo": "Old-Man-Programmer/tree", "binary_name": "tree", + "version_flag": "--version", "script": "install_tree.sh", "tags": [ "file-utils" From d4e23025ca920a391a83bdb011ac60989356f441 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:23:04 +0100 Subject: [PATCH 06/12] feat(install): add go_bin target_dir for Go tool path convention Replace ${GOPATH} expansion with a go_bin strategy that: - On update: keeps the binary where it currently is (respects gup) - On fresh install: best-guesses Go bin folder via GOPATH env, `go env GOPATH`, or ~/go/bin fallback (no Go runtime required) Apply to golangci-lint and gosec to avoid duplicate installations in both ~/.local/bin and ~/go/bin. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/golangci-lint.json | 1 + catalog/gosec.json | 1 + scripts/lib/install_strategy.sh | 40 +++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/catalog/golangci-lint.json b/catalog/golangci-lint.json index fadb128..1085109 100644 --- a/catalog/golangci-lint.json +++ b/catalog/golangci-lint.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/golangci/golangci-lint", "github_repo": "golangci/golangci-lint", "binary_name": "golangci-lint", + "target_dir": "go_bin", "download_url_template": "https://github.com/golangci/golangci-lint/releases/download/{version}/golangci-lint-{version_nov}-linux-{arch}.tar.gz", "arch_map": { "x86_64": "amd64", diff --git a/catalog/gosec.json b/catalog/gosec.json index 5010e22..b5b138b 100644 --- a/catalog/gosec.json +++ b/catalog/gosec.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/securego/gosec", "github_repo": "securego/gosec", "binary_name": "gosec", + "target_dir": "go_bin", "download_url_template": "https://github.com/securego/gosec/releases/download/{version}/gosec_{version_nov}_linux_{arch}.tar.gz", "arch_map": { "x86_64": "amd64", diff --git a/scripts/lib/install_strategy.sh b/scripts/lib/install_strategy.sh index 418cafa..89a990a 100755 --- a/scripts/lib/install_strategy.sh +++ b/scripts/lib/install_strategy.sh @@ -10,6 +10,46 @@ get_install_dir() { local prefix="${PREFIX:-$HOME/.local}" local bin_dir="" + # Check for per-tool target_dir override from catalog + if [ -n "$tool_name" ] && [ -n "${CATALOG_FILE:-}" ] && [ -f "${CATALOG_FILE:-}" ]; then + local target_dir + target_dir="$(jq -r '.target_dir // empty' "$CATALOG_FILE" 2>/dev/null || true)" + if [ -n "$target_dir" ]; then + case "$target_dir" in + go_bin) + # Go binary convention: update in place, fresh install to best-guess GOPATH/bin + local current_path + current_path="$(command -v "$tool_name" 2>/dev/null || true)" + if [ -n "$current_path" ]; then + # Already installed - keep it where it is + echo "$(dirname "$current_path")" + else + # Fresh install - best-guess Go bin folder: + # 1. GOPATH/bin if GOPATH is set + # 2. `go env GOPATH`/bin if go is available + # 3. ~/go/bin (Go's default GOPATH) + if [ -n "${GOPATH:-}" ]; then + echo "$GOPATH/bin" + elif command -v go >/dev/null 2>&1; then + echo "$(go env GOPATH 2>/dev/null)/bin" + else + echo "$HOME/go/bin" + fi + fi + return + ;; + *) + # Generic target_dir: expand ~ and $HOME + target_dir="${target_dir/#\~/$HOME}" + target_dir="${target_dir//\$\{HOME\}/$HOME}" + target_dir="${target_dir//\$HOME/$HOME}" + echo "$target_dir" + return + ;; + esac + fi + fi + case "$strategy" in CURRENT) # Keep tool where it is currently installed From 3669bbff966e17e8b0ac7b542443980348bae4bb Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:28:55 +0100 Subject: [PATCH 07/12] fix(go): always update version symlink on cycle upgrade The go1.XX symlink (e.g. go1.25 -> go1.25.8) was only created when it didn't exist. On patch upgrades the stale symlink was preserved, so go1.25 still pointed at go1.25.7 after installing go1.25.8, causing the upgrade to appear failed (version unchanged). Change the condition from [ ! -e ] to unconditional ln -sf. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- scripts/install_go.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/install_go.sh b/scripts/install_go.sh index 15f2928..e14e353 100755 --- a/scripts/install_go.sh +++ b/scripts/install_go.sh @@ -70,11 +70,11 @@ install_go() { echo "Downloading Go ${FULL_VERSION} SDK..." "$FULL_BINARY" download || true - # Create symlink from go1.24 -> go1.24.12 for convenience + # Update symlink from go1.24 -> go1.24.12 GOBIN="$(go env GOPATH)/bin" - if [ -x "$GOBIN/$FULL_BINARY" ] && [ ! -e "$GOBIN/$BINARY" ]; then + if [ -x "$GOBIN/$FULL_BINARY" ]; then ln -sf "$FULL_BINARY" "$GOBIN/$BINARY" 2>/dev/null || true - echo "Created symlink: $BINARY -> $FULL_BINARY" + echo "Updated symlink: $BINARY -> $FULL_BINARY" fi fi else From 0ecd1df46b5e09c7f9bd4675554f5fac69e4a17f Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:39:13 +0100 Subject: [PATCH 08/12] fix(gcloud): handle existing install, reduce output, fix PATH detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add ~/google-cloud-sdk/bin to PATH at script start so existing installs are detected even when not in shell PATH - Three-way check: gcloud in PATH → update, SDK dir exists → recover, neither → fresh install (avoids "directory already exists" error) - Fresh install uses direct tarball + install.sh --quiet instead of the noisy sdk.cloud.google.com wrapper script - Pipe update output through tail -1 to reduce noise Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- scripts/installers/gcloud_installer.sh | 39 ++++++++++++++++++-------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/scripts/installers/gcloud_installer.sh b/scripts/installers/gcloud_installer.sh index 4467134..4c48bd4 100755 --- a/scripts/installers/gcloud_installer.sh +++ b/scripts/installers/gcloud_installer.sh @@ -14,27 +14,42 @@ if [ ! -f "$CATALOG_FILE" ]; then fi BINARY_NAME="$(jq -r '.binary_name' "$CATALOG_FILE")" +GCLOUD_SDK="$HOME/google-cloud-sdk" +GCLOUD_BIN="$GCLOUD_SDK/bin" + +# Ensure SDK bin is in PATH for detection and post-install +if [ -d "$GCLOUD_BIN" ]; then + export PATH="$GCLOUD_BIN:$PATH" +fi # Get current version before="$(command -v "$BINARY_NAME" >/dev/null 2>&1 && "$BINARY_NAME" version 2>/dev/null | head -1 || true)" if command -v "$BINARY_NAME" >/dev/null 2>&1; then - # Already installed - use built-in update - "$BINARY_NAME" components update --quiet 2>&1 || true + # Already installed - use built-in update (quiet) + "$BINARY_NAME" components update --quiet 2>&1 | tail -1 +elif [ -d "$GCLOUD_SDK" ]; then + # SDK directory exists but gcloud not functional - try to recover + if [ -x "$GCLOUD_BIN/$BINARY_NAME" ]; then + "$GCLOUD_BIN/$BINARY_NAME" components update --quiet 2>&1 | tail -1 + else + echo "[$TOOL] Error: $GCLOUD_SDK exists but gcloud not found in $GCLOUD_BIN" >&2 + echo "[$TOOL] Remove $GCLOUD_SDK and re-run to reinstall" >&2 + exit 1 + fi else - # Fresh install via Google Cloud SDK installer + # Fresh install via Google Cloud SDK installer (quiet) TMP="$(mktemp -d)" - cd "$TMP" - curl -fsSL https://sdk.cloud.google.com -o install.sh - bash install.sh --disable-prompts --install-dir="$HOME" 2>&1 - cd - >/dev/null + INSTALLER_URL="https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz" + echo "[$TOOL] Downloading Google Cloud SDK..." + curl -fsSL "$INSTALLER_URL" -o "$TMP/google-cloud-sdk.tar.gz" + tar -xzf "$TMP/google-cloud-sdk.tar.gz" -C "$HOME" rm -rf "$TMP" - # Add to PATH if not already present - GCLOUD_BIN="$HOME/google-cloud-sdk/bin" - if [ -d "$GCLOUD_BIN" ] && ! command -v "$BINARY_NAME" >/dev/null 2>&1; then - export PATH="$GCLOUD_BIN:$PATH" - fi + # Run install script quietly (no prompts, no PATH modification, no usage reporting) + "$GCLOUD_SDK/install.sh" --quiet --usage-reporting false --command-completion false --path-update false 2>&1 | tail -1 + + export PATH="$GCLOUD_BIN:$PATH" fi # Report From a05d54f77a004b8fe84dba466ddf53a972e94249 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:40:18 +0100 Subject: [PATCH 09/12] fix(gcloud): symlink gcloud, gsutil, bq into user bin dir Symlink SDK binaries into ~/.local/bin so gcloud is available without needing ~/google-cloud-sdk/bin in PATH. Follows the same convention as all other tools in the catalog. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- scripts/installers/gcloud_installer.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/installers/gcloud_installer.sh b/scripts/installers/gcloud_installer.sh index 4c48bd4..2a6381c 100755 --- a/scripts/installers/gcloud_installer.sh +++ b/scripts/installers/gcloud_installer.sh @@ -52,6 +52,15 @@ else export PATH="$GCLOUD_BIN:$PATH" fi +# Symlink gcloud (and gsutil, bq) into user bin so it's in PATH without SDK-specific setup +BIN_DIR="$(get_install_dir "$BINARY_NAME")" +mkdir -p "$BIN_DIR" 2>/dev/null || true +for cmd in gcloud gsutil bq; do + if [ -x "$GCLOUD_BIN/$cmd" ]; then + ln -sf "$GCLOUD_BIN/$cmd" "$BIN_DIR/$cmd" + fi +done + # Report after="$(command -v "$BINARY_NAME" >/dev/null 2>&1 && "$BINARY_NAME" version 2>/dev/null | head -1 || true)" path="$(command -v "$BINARY_NAME" 2>/dev/null || true)" From 5ca353b713178634d3b46f975f3203904c7e9f91 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:42:21 +0100 Subject: [PATCH 10/12] feat(catalog): add charmbracelet/vhs terminal GIF recorder Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/vhs.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 catalog/vhs.json diff --git a/catalog/vhs.json b/catalog/vhs.json new file mode 100644 index 0000000..3810ff9 --- /dev/null +++ b/catalog/vhs.json @@ -0,0 +1,14 @@ +{ + "name": "vhs", + "category": "general", + "install_method": "github_release_binary", + "description": "CLI home video recorder - write terminal GIFs as code", + "homepage": "https://github.com/charmbracelet/vhs", + "github_repo": "charmbracelet/vhs", + "binary_name": "vhs", + "download_url_template": "https://github.com/charmbracelet/vhs/releases/download/{version}/vhs_{version_nov}_Linux_{arch}.tar.gz", + "arch_map": { + "x86_64": "x86_64", + "aarch64": "arm64" + } +} From 71012ecb510b53b2f61aaa2c3ebe26f477fdef2d Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:58:33 +0100 Subject: [PATCH 11/12] fix(catalog): set vhs category to go with go_bin target_dir Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/vhs.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/catalog/vhs.json b/catalog/vhs.json index 3810ff9..33b6372 100644 --- a/catalog/vhs.json +++ b/catalog/vhs.json @@ -1,11 +1,12 @@ { "name": "vhs", - "category": "general", + "category": "go", "install_method": "github_release_binary", "description": "CLI home video recorder - write terminal GIFs as code", "homepage": "https://github.com/charmbracelet/vhs", "github_repo": "charmbracelet/vhs", "binary_name": "vhs", + "target_dir": "go_bin", "download_url_template": "https://github.com/charmbracelet/vhs/releases/download/{version}/vhs_{version_nov}_Linux_{arch}.tar.gz", "arch_map": { "x86_64": "x86_64", From 3f15ef742475bee13f3f648c352578ca0eee6111 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Fri, 6 Mar 2026 23:59:45 +0100 Subject: [PATCH 12/12] fix(catalog): revert vhs category to general Category reflects tool purpose, not implementation language. target_dir: go_bin is sufficient for correct install path. Signed-off-by: Sebastian Mendel Signed-off-by: Sebastian Mendel --- catalog/vhs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/catalog/vhs.json b/catalog/vhs.json index 33b6372..b00ee27 100644 --- a/catalog/vhs.json +++ b/catalog/vhs.json @@ -1,6 +1,6 @@ { "name": "vhs", - "category": "go", + "category": "general", "install_method": "github_release_binary", "description": "CLI home video recorder - write terminal GIFs as code", "homepage": "https://github.com/charmbracelet/vhs",