diff --git a/system_files/shared/usr/share/ublue-os/goose/config.yaml b/system_files/shared/usr/share/ublue-os/goose/config.yaml new file mode 100644 index 00000000..518d9085 --- /dev/null +++ b/system_files/shared/usr/share/ublue-os/goose/config.yaml @@ -0,0 +1,11 @@ +# Bluefin default Goose configuration. +extensions: + linux-mcp-server: + args: [] + bundled: false + cmd: linux-mcp-server + enabled: true + envs: {} + name: linux-mcp-server + timeout: 300 + type: stdio diff --git a/system_files/shared/usr/share/ublue-os/just/apps.just b/system_files/shared/usr/share/ublue-os/just/apps.just index 7ca0cb8e..2866f03e 100644 --- a/system_files/shared/usr/share/ublue-os/just/apps.just +++ b/system_files/shared/usr/share/ublue-os/just/apps.just @@ -54,6 +54,27 @@ cncf: brew bundle --file=/usr/share/ublue-os/homebrew/cncf.Brewfile [[ -t 0 ]] && ujust --choose || true +# Install Goose and configure the read-only Linux diagnostics MCP server. +[group('Apps')] +install-ai-tools: + #!/usr/bin/env bash + set -euo pipefail + brew bundle --file=/usr/share/ublue-os/homebrew/ai-tools.Brewfile + + CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/goose" + CONFIG_FILE="${CONFIG_DIR}/config.yaml" + TEMPLATE="${GOOSE_TEMPLATE:-/usr/share/ublue-os/goose/config.yaml}" + mkdir -p "${CONFIG_DIR}" + + if [[ -e "${CONFIG_FILE}" ]]; then + echo "Goose config already exists: ${CONFIG_FILE}" + echo "Review ${TEMPLATE} and merge its linux-mcp-server extension if needed." + exit 0 + fi + + install -m0644 "${TEMPLATE}" "${CONFIG_FILE}" + echo "Goose configured with read-only Linux diagnostics." + # Install ASUS laptop tools (asusctl daemon + ROG Control Center) | https://gitlab.com/asus-linux/asusctl [group('Apps')] install-asus: diff --git a/tests/test_ujust.bats b/tests/test_ujust.bats index 82c5afee..053a9d6a 100644 --- a/tests/test_ujust.bats +++ b/tests/test_ujust.bats @@ -127,3 +127,120 @@ EOF [ "${status}" -ne 0 ] [ "$(grep -cF "just" "${WORKDIR}/calls.log" || true)" -eq 0 ] } + +# --------------------------------------------------------------------------- +# apps.just: install-ai-tools recipe tests +# --------------------------------------------------------------------------- + +APPS_JUST="$BATS_TEST_DIRNAME/../system_files/shared/usr/share/ublue-os/just/apps.just" + +_extract_apps_recipe() { + local recipe="$1" out_file="$2" + awk -v recipe="$recipe" ' + $0 ~ ("^" recipe "([[:space:]].*)?:$") { in_recipe=1; next } + in_recipe && /^[[:space:]]+#!\/usr\/bin\/env bash/ { found=1; next } + found && /^[^[:space:]]/ { exit } + found { sub(/^[[:space:]]{4}/, ""); print } + ' "${APPS_JUST}" > "${out_file}" +} + +@test "apps.just: install-ai-tools installs brew bundle and creates goose config on fresh setup" { + local script="${WORKDIR}/install-ai-tools.sh" + _extract_apps_recipe "install-ai-tools" "${script}" + + local mock_template="${WORKDIR}/mock-goose-config.yaml" + echo "mock-template-data" > "${mock_template}" + + local test_home="${WORKDIR}/test-user-home" + mkdir -p "${test_home}" + + run env \ + PATH="${WORKDIR}/bin:${PATH}" \ + CALLS="${WORKDIR}/calls.log" \ + HOME="${test_home}" \ + GOOSE_TEMPLATE="${mock_template}" \ + bash "${script}" + + [ "${status}" -eq 0 ] + grep -qF "brew bundle --file=/usr/share/ublue-os/homebrew/ai-tools.Brewfile" "${WORKDIR}/calls.log" + [ -f "${test_home}/.config/goose/config.yaml" ] + [ "$(< "${test_home}/.config/goose/config.yaml")" = "mock-template-data" ] + [[ "${output}" == *"Goose configured with read-only Linux diagnostics."* ]] +} + +@test "apps.just: install-ai-tools respects XDG_CONFIG_HOME on fresh setup" { + local script="${WORKDIR}/install-ai-tools.sh" + _extract_apps_recipe "install-ai-tools" "${script}" + + local mock_template="${WORKDIR}/mock-goose-config.yaml" + echo "mock-template-data" > "${mock_template}" + + local test_home="${WORKDIR}/test-user-home" + local custom_xdg="${WORKDIR}/custom-xdg" + mkdir -p "${test_home}" "${custom_xdg}" + + run env \ + PATH="${WORKDIR}/bin:${PATH}" \ + CALLS="${WORKDIR}/calls.log" \ + HOME="${test_home}" \ + XDG_CONFIG_HOME="${custom_xdg}" \ + GOOSE_TEMPLATE="${mock_template}" \ + bash "${script}" + + [ "${status}" -eq 0 ] + [ -f "${custom_xdg}/goose/config.yaml" ] + [ ! -e "${test_home}/.config/goose/config.yaml" ] + [ "$(< "${custom_xdg}/goose/config.yaml")" = "mock-template-data" ] +} + +@test "apps.just: install-ai-tools preserves existing goose config and does not overwrite" { + local script="${WORKDIR}/install-ai-tools.sh" + _extract_apps_recipe "install-ai-tools" "${script}" + + local mock_template="${WORKDIR}/mock-goose-config.yaml" + echo "mock-template-data" > "${mock_template}" + + local test_home="${WORKDIR}/test-user-home" + mkdir -p "${test_home}/.config/goose" + echo "existing-custom-config" > "${test_home}/.config/goose/config.yaml" + + run env \ + PATH="${WORKDIR}/bin:${PATH}" \ + CALLS="${WORKDIR}/calls.log" \ + HOME="${test_home}" \ + GOOSE_TEMPLATE="${mock_template}" \ + bash "${script}" + + [ "${status}" -eq 0 ] + grep -qF "brew bundle --file=/usr/share/ublue-os/homebrew/ai-tools.Brewfile" "${WORKDIR}/calls.log" + [ -f "${test_home}/.config/goose/config.yaml" ] + [ "$(< "${test_home}/.config/goose/config.yaml")" = "existing-custom-config" ] + [[ "${output}" == *"Goose config already exists: ${test_home}/.config/goose/config.yaml"* ]] + [[ "${output}" == *"Review "* ]] + [[ "${output}" == *"and merge its linux-mcp-server extension if needed."* ]] + [[ "${output}" != *"Goose configured with read-only Linux diagnostics."* ]] +} + +@test "apps.just: install-ai-tools preserves existing config under XDG_CONFIG_HOME" { + local script="${WORKDIR}/install-ai-tools.sh" + _extract_apps_recipe "install-ai-tools" "${script}" + + local mock_template="${WORKDIR}/mock-goose-config.yaml" + echo "mock-template-data" > "${mock_template}" + + local custom_xdg="${WORKDIR}/custom-xdg" + mkdir -p "${custom_xdg}/goose" + echo "existing-xdg-config" > "${custom_xdg}/goose/config.yaml" + + run env \ + PATH="${WORKDIR}/bin:${PATH}" \ + CALLS="${WORKDIR}/calls.log" \ + XDG_CONFIG_HOME="${custom_xdg}" \ + GOOSE_TEMPLATE="${mock_template}" \ + bash "${script}" + + [ "${status}" -eq 0 ] + [ -f "${custom_xdg}/goose/config.yaml" ] + [ "$(< "${custom_xdg}/goose/config.yaml")" = "existing-xdg-config" ] + [[ "${output}" == *"Goose config already exists: ${custom_xdg}/goose/config.yaml"* ]] +}