From a2929417cd3e49d2737f5ac73085556283d1cd06 Mon Sep 17 00:00:00 2001 From: servius Date: Tue, 16 Jun 2026 22:36:32 +0000 Subject: [PATCH] Merge branch 'goose-migrate' --- darwin/shiro/configuration.nix | 16 ++++++++++++++++ darwin/shiro/services/sunshine.nix | 4 ++-- home/programs/goose.nix | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- secrets/secrets.yaml | 9 ++++++--- 4 file(s) changed, 121 insertion(s)(+), 10 deletion(s)(-) diff --git a/darwin/shiro/configuration.nix b/darwin/shiro/configuration.nix --- a/darwin/shiro/configuration.nix +++ b/darwin/shiro/configuration.nix @@ -88,6 +88,22 @@ eval "$(/opt/homebrew/bin/brew shellenv)" ''; programs.fish.enable = true; + launchd.user.envVariables = { + SHELL = "${pkgs.bash}/bin/bash"; + PATH = [ + "${device.home}/.nix-profile/bin" + "/etc/profiles/per-user/${device.user}/bin" + "/run/current-system/sw/bin" + "/nix/var/nix/profiles/default/bin" + "/opt/homebrew/bin" + "/usr/local/bin" + "/usr/bin" + "/bin" + "/usr/sbin" + "/sbin" + ]; + }; + # services.nix-daemon.enable = true; system.primaryUser = "servius"; system.stateVersion = 5; diff --git a/darwin/shiro/services/sunshine.nix b/darwin/shiro/services/sunshine.nix --- a/darwin/shiro/services/sunshine.nix +++ b/darwin/shiro/services/sunshine.nix @@ -1,10 +1,10 @@ {...}: { homebrew = { taps = [ - "lizardbyte/homebrew" + # "lizardbyte/homebrew" ]; brews = [ - "lizardbyte/homebrew/sunshine-beta" + # "lizardbyte/homebrew/sunshine-beta" ]; }; } diff --git a/home/programs/goose.nix b/home/programs/goose.nix --- a/home/programs/goose.nix +++ b/home/programs/goose.nix @@ -5,8 +5,37 @@ config, device, ... }: let + secretsFile = builtins.readFile ../../secrets/secrets.yaml; + hasSlackMcpXoxpToken = lib.hasInfix "mcp-xoxp-token:" secretsFile; + hasSlackMcpXoxcToken = lib.hasInfix "mcp-xoxc-token:" secretsFile; + hasSlackMcpXoxdToken = lib.hasInfix "mcp-xoxd-token:" secretsFile; homeAssistantUrl = "https://home.darksailor.dev"; homeAssistantTokenFile = config.sops.secrets."homeassistant/cli-token".path; + slackXoxpTokenFile = + if hasSlackMcpXoxpToken + then config.sops.secrets."slack/mcp-xoxp-token".path + else "${device.home}/.config/goose/slack-mcp/xoxp-token"; + slackXoxcTokenFile = + if hasSlackMcpXoxcToken + then config.sops.secrets."slack/mcp-xoxc-token".path + else "${device.home}/.config/goose/slack-mcp/xoxc-token"; + slackXoxdTokenFile = + if hasSlackMcpXoxdToken + then config.sops.secrets."slack/mcp-xoxd-token".path + else "${device.home}/.config/goose/slack-mcp/xoxd-token"; + gooseShell = "${pkgs.bash}/bin/bash"; + goosePath = lib.concatStringsSep ":" [ + "${device.home}/.nix-profile/bin" + "/etc/profiles/per-user/${device.user}/bin" + "/run/current-system/sw/bin" + "/nix/var/nix/profiles/default/bin" + "/opt/homebrew/bin" + "/usr/local/bin" + "/usr/bin" + "/bin" + "/usr/sbin" + "/sbin" + ]; homeAssistantMcp = pkgs.writeShellScriptBin "goose-ha-mcp" '' set -euo pipefail @@ -31,6 +60,39 @@ export NPM_CONFIG_AUDIT=false exec ${pkgs.nodejs}/bin/npx --yes --loglevel=silent ha-mcp "$@" ''; + slackMcp = pkgs.writeShellScriptBin "goose-slack-mcp" '' + set -euo pipefail + + cache_root="''${XDG_CACHE_HOME:-${device.home}/.cache}/goose/slack-mcp" + xoxp_token_file=${lib.escapeShellArg (toString slackXoxpTokenFile)} + xoxc_token_file=${lib.escapeShellArg (toString slackXoxcTokenFile)} + xoxd_token_file=${lib.escapeShellArg (toString slackXoxdTokenFile)} + mkdir -p "$cache_root" + + if [ -s "$xoxc_token_file" ] && [ -s "$xoxd_token_file" ]; then + export SLACK_MCP_XOXC_TOKEN="$(cat "$xoxc_token_file")" + export SLACK_MCP_XOXD_TOKEN="$(cat "$xoxd_token_file")" + elif [ -s "$xoxp_token_file" ]; then + export SLACK_MCP_XOXP_TOKEN="$(cat "$xoxp_token_file")" + else + echo "Slack MCP token missing: add SOPS secrets slack/mcp-xoxc-token and slack/mcp-xoxd-token, or slack/mcp-xoxp-token." >&2 + exit 1 + fi + + export SLACK_MCP_USERS_CACHE="$cache_root/users.json" + export SLACK_MCP_CHANNELS_CACHE="$cache_root/channels.json" + export SLACK_MCP_ENABLED_TOOLS=conversations_history,conversations_replies,conversations_search_messages,conversations_unreads,channels_list,channels_me,users_search,usergroups_list,saved_list + export SLACK_MCP_LOG_LEVEL=error + + # Keep the stdio server startup free of npm chatter before JSON-RPC begins. + export PATH=${lib.escapeShellArg (lib.makeBinPath [pkgs.nodejs pkgs.bash pkgs.coreutils])} + export NPM_CONFIG_LOGLEVEL=silent + export NPM_CONFIG_UPDATE_NOTIFIER=false + export NPM_CONFIG_FUND=false + export NPM_CONFIG_AUDIT=false + + exec ${pkgs.nodejs}/bin/npx --yes --loglevel=silent slack-mcp-server@latest --transport stdio "$@" + ''; gooseHomeAssistantExtension = { enabled = true; type = "stdio"; @@ -43,8 +105,23 @@ timeout = 300; bundled = false; available_tools = []; }; - gooseHomeAssistantExtensionFile = (pkgs.formats.yaml {}).generate "goose-homeassistant-extension.yaml" { - extensions.homeassistant = gooseHomeAssistantExtension; + gooseSlackExtension = { + enabled = true; + type = "stdio"; + name = "slack"; + display_name = "Slack"; + description = "Read Slack channels, threads, DMs, users, and unread messages via slack-mcp-server."; + cmd = "${slackMcp}/bin/goose-slack-mcp"; + args = []; + timeout = 300; + bundled = false; + available_tools = []; + }; + gooseExtensionFile = (pkgs.formats.yaml {}).generate "goose-extensions.yaml" { + extensions = { + homeassistant = gooseHomeAssistantExtension; + slack = gooseSlackExtension; + }; }; gooseDesktopExternalBackendConfigFile = config.sops.templates."goose-desktop-external-goosed.json".path; goosedMacosScript = pkgs.writeShellScriptBin "goosed-shiro" '' @@ -63,6 +140,8 @@ export GOOSE_HOST=127.0.0.1 export GOOSE_PORT=3000 export GOOSE_TLS=false + export SHELL=${lib.escapeShellArg gooseShell} + export PATH=${lib.escapeShellArg goosePath} exec /Applications/Goose.app/Contents/Resources/bin/goosed agent ''; @@ -77,14 +156,27 @@ home.packages = [ pkgs.goose-ai homeAssistantMcp + slackMcp ] ++ lib.optionals (pkgs.stdenv.hostPlatform.system == "x86_64-linux") [pkgs.goose-desktop]; - sops.secrets."homeassistant/cli-token" = {}; + sops.secrets = + { + "homeassistant/cli-token" = {}; + } + // lib.optionalAttrs hasSlackMcpXoxpToken { + "slack/mcp-xoxp-token" = {}; + } + // lib.optionalAttrs hasSlackMcpXoxcToken { + "slack/mcp-xoxc-token" = {}; + } + // lib.optionalAttrs hasSlackMcpXoxdToken { + "slack/mcp-xoxd-token" = {}; + }; - home.activation.configureGooseHomeAssistant = lib.hm.dag.entryAfter ["writeBoundary"] '' + home.activation.configureGooseExtensions = lib.hm.dag.entryAfter ["writeBoundary"] '' config_file="${config.xdg.configHome}/goose/config.yaml" - extension_file="${gooseHomeAssistantExtensionFile}" + extension_file="${gooseExtensionFile}" mkdir -p "$(dirname "$config_file")" if [ ! -e "$config_file" ]; then diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -155,6 +155,9 @@ jwt_secret_b64: ENC[AES256_GCM,data:t/sgw98CjVeTy/cxyO4HMA8K94qwfvdY5zRGbUV9kf0ghXULIeomg50gl8U=,iv:Y7baR0ZY+z6eA9Y1R+gHqpGEQp+z6B7Z536Kf8Whd7Q=,tag:Y0jKJQxjkGI19mS7m8laGg==,type:str] sloe_upload_token: ENC[AES256_GCM,data:fGoWQoD8bUlP7Phe/3OJzVcMLgSny5j5WzCXBxWGfOM+KGfZAswKiqWTe3bKZydkdkZcBMGLKFl4M17xD/oH2kd2Jnm4RHCQVy6epvYFK2JTr1B0vdTojQNgIsCnroeyDsHPJY64Rsvb+xszSGyEbTf+1npCkuPze6Hyu32dkSfAbOFjbiooQhE3ZJz0Dfdbupx0C0emNdqT49h+n/WD6UyyMY000tlHk4DvqAh2oHYGX+HLlaCoUAWLWBhAyRZXxl1H2n8Z+L8E+NUtoie4F7Ad3eqQhYvbrKWlmTiKvXrQE0suY5FQusZSEFnhjbvDdexuPbuhzInlIRgjBUQNU37lNdxziG1wOgW9zJAhKgJs9ldLjCV7+1Fo4D5Ril5jazngpx8rAWj6L8GT6lblkYoIrw/g3mNRcBpSsbLNx8e3KCaGXIbE2qhkdEn53Kz0NXWyDYLs8FxjQ+LwgcXVyA==,iv:MAoISxK1Ozv4OnXpRG8n689Ga35aLlMMm+hhILoevKk=,tag:DhF5i1zUICPjShRZK6fBKg==,type:str] goose: server_secret: ENC[AES256_GCM,data:VPqdv1poAXaLeRHG/IPE24ivA3/M8lpyLI+eyevsJDAt0mgJCM8Hs9hvuoEU1XK3SW4Sk1oTL23qKeZwUSjcvQ==,iv:cOt/IqfSZJwCGcyqnbpUp4MVZkViHcg62bgsRyrT53s=,tag:+HinnSyI7utC0BzN4FhG8w==,type:str] +slack: + mcp-xoxc-token: ENC[AES256_GCM,data:gvD8hyrDDDZh1p4aSvaQrHsH2ahyEkDkxN6Zx6+gBXk1DcTCnMmWLF09Q/I+Q2TyqBHsf32zeAQt5NypV8QbOif/eY5npkypga028l9lknG77qs2hXcYdRh1rjV5AmaeZM6lRgqUZE0yPKMQnqAvUQ==,iv:Hir6GFMMDGMKJ6hdTtLZKOZrKepRLtGMu9npQcZf3HY=,tag:EI3Ezv4B3AmjY1+Z1dbr9Q==,type:str] + mcp-xoxd-token: ENC[AES256_GCM,data:XT+YFs8O+xVso3ZskSWmIvyrdzfjSMjEiuLY128745m8rCF1F3KP7TdnmrRGsthZ5kKcprR/mItXTCnokirYCY2PJQ+dJcn0WQ4850R/kjJ2VLiiiEItEtpc0REvJpZUyTDpFi5ukuBv8pHucnQiGSZI+XU879adOn7vB+pC4htAOoVU0CNAEj+UdDV7AJmI9jQ2bIpA+MTvMVxNFsG82DGT2v6Bw7P9T9ifMH0NrRZMICKJzIuytw/zh+7ZBWvomUP1l5Aov+GxtlzVf3mgMm2O/gD66F1ong==,iv:2X1qTSafUgLNXlqwumKPNwcTgyJhvBAEebjIHtQzp68=,tag:Elt1enJ47fafpUR5TeEGYA==,type:str] sops: age: - enc: | @@ -166,7 +169,7 @@ VGZKdHpVeFRpQUxtSEkyaEhLMlBJcGsKLb0DvPNZosPBUuiX6qz1s5IO5INQh8CK ZtXTVClwMSmaUYhdSB2gKFrKVZHXTJZ4oAL5t/BpC0pOHyr+o96T3Q== -----END AGE ENCRYPTED FILE----- recipient: age1pw7kluxp7872c63ne4jecq75glj060jkmqwzkk6esatuyck9egfswufdpk - lastmodified: "2026-06-11T14:19:15Z" - mac: ENC[AES256_GCM,data:eC5TEJUvzF6r3vyqswimY7okOOwxXiJLvVVymRWQmW3uAy1+/MyTD6TCHKmX20q/JscRJJAMtDsuafgKuoMz/Le+WmWtr0qqFApKcY7PDvPXXTrdSRLpVPIZaUW+2hXuQdRTsPFr1wYQo4mcCmeXlIPhnVZJrztvcEGt44wqdwU=,iv:jkBxL1Q8a4tRiO72oqdxwbm+zd67zbj58aNEySYb5MY=,tag:svsW1PTVtgerDCCe1B87qA==,type:str] + lastmodified: "2026-06-16T22:13:02Z" + mac: ENC[AES256_GCM,data:JqHLDn8mUihasOIX24iErCon3CkCF0Tt9fwOySIfaVKNcM6f9i+AyIXCtp4yxiF7I/ScgyfMWPrSMZVfMKZe15iAi+vyYXgrC+3wa78S+wnJqwXDnrcYjMiIvay+J9fwYYY9aO4zno5LksZXy6w8mvRpatNTB9CRnHYNFnaFRzE=,iv:9qAvZNZp2E56+xXjOx8F8p+3kf85Z4Yxg6XjXPo4m4E=,tag:bguaImSsZrY9ZewWFqeeCg==,type:str] unencrypted_suffix: _unencrypted - version: 3.12.2 + version: 3.13.1 -- tangled.sh