From 63774e86ec3fffb7695722bd5d369c962cc53898 Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 20:49:33 -0800 Subject: [PATCH 1/6] fix: add missing showNativeManageAgentsWindow stub for non-darwin platforms The systray package was missing a stub implementation of showNativeManageAgentsWindow in windows_other.go, causing build failures on Linux and Windows. This adds the no-op stub with the correct signature to match windows_darwin.go. --- internal/systray/windows_other.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/systray/windows_other.go b/internal/systray/windows_other.go index 2e23e2b..73e7c6e 100644 --- a/internal/systray/windows_other.go +++ b/internal/systray/windows_other.go @@ -2,7 +2,10 @@ package systray -import "github.com/kevinelliott/agentmgr/pkg/agent" +import ( + "github.com/kevinelliott/agentmgr/pkg/agent" + "github.com/kevinelliott/agentmgr/pkg/catalog" +) // showNativeSettingsWindow is not available on this platform. func (a *App) showNativeSettingsWindow() { @@ -10,6 +13,11 @@ func (a *App) showNativeSettingsWindow() { a.showSettings() } +// showNativeManageAgentsWindow is not available on this platform. +func (a *App) showNativeManageAgentsWindow(_ []catalog.AgentDef, _ []agent.Installation) { + // No-op on non-darwin platforms; caller should check hasNativeWindowSupport() +} + // showNativeAgentDetailsWindow is not available on this platform. func (a *App) showNativeAgentDetailsWindow(inst agent.Installation) { // Fall back to platform-specific dialog From 906768ba454ec87224fdfa884ba0e2c091811e1f Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 20:52:22 -0800 Subject: [PATCH 2/6] ci: add Linux system dependencies for systray The getlantern/systray library requires libayatana-appindicator3-dev and libgtk-3-dev on Linux for building. Added apt-get install steps to all jobs that run on ubuntu-latest. --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b47f3c..a4d2bea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y libayatana-appindicator3-dev libgtk-3-dev + - name: Set up Go uses: actions/setup-go@v5 with: @@ -39,6 +44,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install Linux dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libayatana-appindicator3-dev libgtk-3-dev + - name: Set up Go uses: actions/setup-go@v5 with: @@ -69,6 +80,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install Linux dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libayatana-appindicator3-dev libgtk-3-dev + - name: Set up Go uses: actions/setup-go@v5 with: @@ -107,6 +124,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Install Linux dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libayatana-appindicator3-dev libgtk-3-dev + - name: Set up Go uses: actions/setup-go@v5 with: From 0de43b5e8647031bec81359e011e0a8bf28af7c9 Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 21:41:24 -0800 Subject: [PATCH 3/6] fix: address lint errors in linux platform - Handle os.UserHomeDir() errors in getSystemdUserDir and getXDGAutostartDir - Add #nosec directives for G204 (subprocess) where input is from controlled sources --- pkg/platform/linux.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/platform/linux.go b/pkg/platform/linux.go index 762357f..0d5e2e7 100644 --- a/pkg/platform/linux.go +++ b/pkg/platform/linux.go @@ -150,7 +150,10 @@ func (l *linuxPlatform) getSystemdUserDir() string { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" { return filepath.Join(xdgConfig, "systemd", "user") } - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + if err != nil { + return filepath.Join("/tmp", ".config", "systemd", "user") + } return filepath.Join(home, ".config", "systemd", "user") } @@ -194,7 +197,10 @@ func (l *linuxPlatform) getXDGAutostartDir() string { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" { return filepath.Join(xdgConfig, "autostart") } - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + if err != nil { + return filepath.Join("/tmp", ".config", "autostart") + } return filepath.Join(home, ".config", "autostart") } @@ -253,6 +259,7 @@ func (l *linuxPlatform) ShowNotification(title, message string) error { } // Try zenity if _, err := exec.LookPath("zenity"); err == nil { + // #nosec G204 -- title and message are from controlled internal sources return exec.Command("zenity", "--notification", "--text="+title+"\n"+message).Run() } return fmt.Errorf("no notification system available") @@ -273,6 +280,7 @@ func (l *linuxPlatform) ShowChangelogDialog(agentName, fromVer, toVer, changelog func (l *linuxPlatform) showZenityDialog(agentName, fromVer, toVer, changelog string) DialogResult { text := fmt.Sprintf("%s\n\n%s → %s\n\n%s", agentName, fromVer, toVer, changelog) + // #nosec G204 -- arguments are from controlled catalog sources, not user input cmd := exec.Command("zenity", "--question", "--title=Update Available", "--text="+text, From 90e22194366e32272d33f69f97fc65451b8cebc9 Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 22:05:47 -0800 Subject: [PATCH 4/6] ci: fix Windows test command by using cmd shell instead of PowerShell PowerShell was misinterpreting ./... and coverage.out, causing Go to look for a package called '.out'. Using cmd shell avoids this parsing issue. --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4d2bea..a6e4d55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,13 @@ jobs: - name: Get dependencies run: go mod download - - name: Run tests + - name: Run tests (Unix) + if: matrix.os != 'windows-latest' + run: go test -race -coverprofile=coverage.out -covermode=atomic ./... + + - name: Run tests (Windows) + if: matrix.os == 'windows-latest' + shell: cmd run: go test -race -coverprofile=coverage.out -covermode=atomic ./... - name: Upload coverage to Codecov From 2d2be9589eb0125f9a470174af27613d5b08e9e8 Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 22:09:32 -0800 Subject: [PATCH 5/6] fix: address remaining lint issues - Use os.TempDir() instead of literal /tmp path (gocritic filepathJoin) - Add nolint:errcheck for intentional error ignoring in DisableAutoStart - Properly handle error from isSystemdEnabled - Add nolint:unused for uninstallCLI (reserved for future use) --- internal/systray/systray.go | 2 ++ pkg/platform/linux.go | 13 +++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/systray/systray.go b/internal/systray/systray.go index 7dae9fc..435b4ec 100644 --- a/internal/systray/systray.go +++ b/internal/systray/systray.go @@ -1390,6 +1390,8 @@ func (a *App) installCLIToPathWindows(sourcePath, targetPath string) { } // uninstallCLI removes the CLI binary from the system path. +// +//nolint:unused // Reserved for future use in systray menu func (a *App) uninstallCLI() bool { targetPath := "/usr/local/bin/agentmgr" diff --git a/pkg/platform/linux.go b/pkg/platform/linux.go index 0d5e2e7..8681e7c 100644 --- a/pkg/platform/linux.go +++ b/pkg/platform/linux.go @@ -76,16 +76,17 @@ func (l *linuxPlatform) EnableAutoStart(ctx context.Context) error { } func (l *linuxPlatform) DisableAutoStart(ctx context.Context) error { - // Try both methods - l.disableSystemdAutoStart(ctx) - l.disableXDGAutoStart() + // Try both methods - errors are intentionally ignored as this is best-effort cleanup + _ = l.disableSystemdAutoStart(ctx) //nolint:errcheck + _ = l.disableXDGAutoStart() //nolint:errcheck return nil } func (l *linuxPlatform) IsAutoStartEnabled(ctx context.Context) (bool, error) { // Check systemd if l.hasSystemd() { - if enabled, _ := l.isSystemdEnabled(ctx); enabled { + enabled, err := l.isSystemdEnabled(ctx) + if err == nil && enabled { return true, nil } } @@ -152,7 +153,7 @@ func (l *linuxPlatform) getSystemdUserDir() string { } home, err := os.UserHomeDir() if err != nil { - return filepath.Join("/tmp", ".config", "systemd", "user") + return filepath.Join(os.TempDir(), ".config", "systemd", "user") } return filepath.Join(home, ".config", "systemd", "user") } @@ -199,7 +200,7 @@ func (l *linuxPlatform) getXDGAutostartDir() string { } home, err := os.UserHomeDir() if err != nil { - return filepath.Join("/tmp", ".config", "autostart") + return filepath.Join(os.TempDir(), ".config", "autostart") } return filepath.Join(home, ".config", "autostart") } From 6479036653777e5b5d7e74dc8bdb8ae35bc2a17f Mon Sep 17 00:00:00 2001 From: Kevin Elliott Date: Fri, 23 Jan 2026 23:00:42 -0800 Subject: [PATCH 6/6] fix: handle os.UserHomeDir errors in GetDataDir, GetConfigDir, GetCacheDir --- pkg/platform/linux.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/platform/linux.go b/pkg/platform/linux.go index 8681e7c..48b2ece 100644 --- a/pkg/platform/linux.go +++ b/pkg/platform/linux.go @@ -34,7 +34,10 @@ func (l *linuxPlatform) GetDataDir() string { if xdgData := os.Getenv("XDG_DATA_HOME"); xdgData != "" { return filepath.Join(xdgData, "agentmgr") } - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + if err != nil { + return filepath.Join(os.TempDir(), ".local", "share", "agentmgr") + } return filepath.Join(home, ".local", "share", "agentmgr") } @@ -42,7 +45,10 @@ func (l *linuxPlatform) GetConfigDir() string { if xdgConfig := os.Getenv("XDG_CONFIG_HOME"); xdgConfig != "" { return filepath.Join(xdgConfig, "agentmgr") } - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + if err != nil { + return filepath.Join(os.TempDir(), ".config", "agentmgr") + } return filepath.Join(home, ".config", "agentmgr") } @@ -50,7 +56,10 @@ func (l *linuxPlatform) GetCacheDir() string { if xdgCache := os.Getenv("XDG_CACHE_HOME"); xdgCache != "" { return filepath.Join(xdgCache, "agentmgr") } - home, _ := os.UserHomeDir() + home, err := os.UserHomeDir() + if err != nil { + return filepath.Join(os.TempDir(), ".cache", "agentmgr") + } return filepath.Join(home, ".cache", "agentmgr") }