Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,53 @@ jobs:
args: release --clean
env:
GITHUB_TOKEN: ${{ steps.app_token.outputs.token }}

release-menubar:
needs: release
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- uses: actions/setup-go@v6
with:
check-latest: true
go-version-file: go.mod

- id: app_token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.TOKEN_APP_ID }}
private_key: ${{ secrets.TOKEN_APP_PRIVATE_KEY }}

- name: Build .app bundles
env:
VERSION: ${{ github.ref_name }}
run: |
set -euo pipefail
V="${VERSION#v}"
mkdir -p dist
for ARCH in arm64 amd64; do
APP="dist/dockprox.app"
rm -rf "$APP"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources"
sed "s/__VERSION__/${V}/g" cmd/dockprox-menubar/Info.plist > "$APP/Contents/Info.plist"
CARCH="${ARCH}"
[ "$ARCH" = "amd64" ] && CARCH="x86_64"
CGO_ENABLED=1 \
CGO_CFLAGS="-arch ${CARCH}" \
CGO_LDFLAGS="-arch ${CARCH}" \
GOOS=darwin GOARCH="${ARCH}" \
go build -tags=safe -trimpath \
-ldflags="-s -w -X github.com/foomo/dockprox/internal/cli.version=${V} -X github.com/foomo/dockprox/internal/cli.commitHash=${{ github.sha }}" \
-o "$APP/Contents/MacOS/dockprox-menubar" ./cmd/dockprox-menubar
tar -czf "dist/dockprox-menubar_${V}_darwin_${ARCH}.tar.gz" -C dist dockprox.app
done

- name: Upload to release
env:
GH_TOKEN: ${{ steps.app_token.outputs.token }}
run: |
gh release upload "${{ github.ref_name }}" \
dist/dockprox-menubar_*_darwin_*.tar.gz --clobber
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ build:
@rm -f bin/dockprox
@go build -o bin/dockprox cmd/dockprox/dockprox.go

.PHONY: build.menubar
## Build macOS menubar app binary (darwin only)
build.menubar:
ifeq ($(shell uname),Darwin)
@echo "〉go build bin/dockprox-menubar"
@rm -f bin/dockprox-menubar
@go build -tags=safe -o bin/dockprox-menubar ./cmd/dockprox-menubar
else
$(error build.menubar requires macOS)
endif

.PHONY: build.debug
## Build binary in debug mode
build.debug:
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,24 +155,24 @@ Requires Go 1.26+.

## macOS menu bar app

A native menu bar (tray) app ships as the `menubar` subcommand of the `dockprox` binary. It runs a dockprox proxy in-process and exposes Start / Stop / Restart / Reveal-config-in-Finder / Quit from the system tray.
A native menu bar (tray) app ships as a separate `dockprox-menubar` binary (macOS only, Wails-backed). It runs a dockprox proxy in-process and exposes Start / Stop / Restart / Reveal-config-in-Finder / Quit from the system tray.

Build:

```shell
make build
make build.menubar
```

Run:

```shell
bin/dockprox menubar
bin/dockprox-menubar
```

Run from source:

```shell
go run -tags=safe ./cmd/dockprox menubar
go run -tags=safe ./cmd/dockprox-menubar
```

Config is resolved from `$XDG_CONFIG_HOME/dockprox/config.yaml` (or `~/.config/dockprox/config.yaml` if `XDG_CONFIG_HOME` is unset), falling back to `~/.dockprox.yaml`. If neither exists at launch, a default config is written to one of those locations (XDG when `$XDG_CONFIG_HOME` is set; otherwise the dotfile).
Expand Down
26 changes: 26 additions & 0 deletions cmd/dockprox-menubar/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.foomo.dockprox</string>
<key>CFBundleName</key>
<string>dockprox</string>
<key>CFBundleDisplayName</key>
<string>dockprox</string>
<key>CFBundleExecutable</key>
<string>dockprox-menubar</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>__VERSION__</string>
<key>CFBundleShortVersionString</key>
<string>__VERSION__</string>
<key>LSUIElement</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>11.0</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
28 changes: 13 additions & 15 deletions internal/cli/menubar_darwin.go → cmd/dockprox-menubar/main.go
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
//go:build darwin

package cli
// Command dockprox-menubar runs the macOS menu bar (tray) app that drives a
// dockprox proxy in-process.
package main

import (
"flag"
"os"
"os/signal"
"syscall"

"github.com/charmbracelet/log"
"github.com/foomo/dockprox/internal/menubar"
"github.com/spf13/cobra"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)

func newMenubarCmd() *cobra.Command {
var cfgPath string
func main() {
cfgPath := flag.String("config", "", "YAML config file (default: auto-resolve)")

cmd := &cobra.Command{
Use: "menubar",
Short: "Run the macOS menu bar app",
RunE: func(cmd *cobra.Command, _ []string) error {
return runMenubar(cmd, cfgPath)
},
}
cmd.Flags().StringVar(&cfgPath, "config", "", "YAML config file (default: auto-resolve)")
flag.Parse()

return cmd
if err := run(*cfgPath); err != nil {
log.Error("menubar exited with error", "err", err)
os.Exit(1)
}
}

func runMenubar(cmd *cobra.Command, cfgPath string) error {
logger := log.NewWithOptions(cmd.ErrOrStderr(), log.Options{ReportTimestamp: true})
func run(cfgPath string) error {
logger := log.NewWithOptions(os.Stderr, log.Options{ReportTimestamp: true})

if cfgPath == "" {
resolved, err := menubar.Resolve()
Expand Down
13 changes: 13 additions & 0 deletions cmd/dockprox-menubar/main_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build !darwin

package main

import (
"fmt"
"os"
)

func main() {
fmt.Fprintln(os.Stderr, "dockprox-menubar is only supported on macOS")
os.Exit(1)
}
1 change: 0 additions & 1 deletion docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export default defineConfig({
items: [
{ text: 'dockprox', link: '/reference/cli/dockprox' },
{ text: 'dockprox serve', link: '/reference/cli/dockprox_serve' },
{ text: 'dockprox menubar', link: '/reference/cli/dockprox_menubar' },
{ text: 'dockprox version', link: '/reference/cli/dockprox_version' },
],
},
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ Requires Go 1.26+.

## macOS menu bar app

The `dockprox` binary includes a macOS tray app — see [Menu bar app](./menubar.md).
A separate `dockprox-menubar` binary ships the macOS tray app — see [Menu bar app](./menubar.md).
23 changes: 8 additions & 15 deletions docs/guide/menubar.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,32 @@
# Menu bar app (macOS)

A native menu bar (tray) app ships as the `menubar` subcommand of the `dockprox` binary. It runs a `dockprox` proxy in-process and exposes Start / Stop / Restart / Reveal-config-in-Finder / Quit from the system tray.
A native menu bar (tray) app ships as a separate `dockprox-menubar` binary. It runs a `dockprox` proxy in-process and exposes Start / Stop / Restart / Reveal-config-in-Finder / Quit from the system tray.

::: info Platform
The menu bar app is **macOS only**. On other operating systems the `menubar` subcommand is registered but exits with an unsupported-platform error.
The menu bar app is **macOS only** (Wails-backed, requires cgo + macOS SDK). It is not part of the standard `dockprox` release archives — build it locally on a Mac.
:::

## Run
## Build & run

After [installing](./installation.md) `dockprox`:
From this repo on macOS:

```sh
dockprox menubar
```

Or build and run from this repo:

```sh
make build
bin/dockprox menubar
make build.menubar
bin/dockprox-menubar
```

Or run from source:

```sh
go run -tags=safe ./cmd/dockprox menubar
go run -tags=safe ./cmd/dockprox-menubar
```

The proxy auto-starts when the app launches. The tray icon reflects the running / stopped state.

## Flags

```sh
dockprox menubar [--config PATH]
dockprox-menubar [--config PATH]
```

| Flag | Description |
Expand Down Expand Up @@ -68,5 +62,4 @@ Edit the resolved config file with any editor and use **Restart** to apply chang

## See also

- [`dockprox menubar`](../reference/cli/dockprox_menubar.md) CLI reference
- [Configuration](./configuration.md)
1 change: 0 additions & 1 deletion docs/reference/cli/dockprox.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dockprox is a local HTTP(S) proxy that bypasses traffic by default and routes on

### SEE ALSO

* [dockprox menubar](dockprox_menubar.md) - Run the macOS menu bar app
* [dockprox serve](dockprox_serve.md) - Run the proxy server
* [dockprox version](dockprox_version.md) - Print version information

19 changes: 0 additions & 19 deletions docs/reference/cli/dockprox_menubar.md

This file was deleted.

18 changes: 0 additions & 18 deletions internal/cli/menubar_other.go

This file was deleted.

2 changes: 1 addition & 1 deletion internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewRoot() *cobra.Command {
SilenceErrors: true,
SilenceUsage: true,
}
root.AddCommand(newServeCmd(), newMenubarCmd(), newVersionCmd())
root.AddCommand(newServeCmd(), newVersionCmd())

return root
}
Expand Down