Skip to content

Latest commit

 

History

History
126 lines (83 loc) · 3.96 KB

File metadata and controls

126 lines (83 loc) · 3.96 KB

Build & Run

Prerequisites

A Go toolchain is required. The project uses mise to manage it (mise.toml).

mise install

If go is not on PATH, resolve it through mise:

export PATH="$(mise where go)/bin:$PATH"

Build

go build -o bin/sah ./cmd/sah

For release builds, inject the version via ldflags.

go build -trimpath -ldflags="-s -w -X main.version=$(cat VERSION)" -o bin/sah ./cmd/sah

Run

Run from the project root.

sah auth login
sah run
sah me
sah daemon install

sah daemon install both installs and starts the per-user background service. Use sah daemon start only after a manual stop or after logging back into the relevant service manager session.

On Linux, sah daemon install writes a per-user systemd --user unit and restarts it immediately. On macOS, it writes a per-user launchd plist and bootstraps it immediately. Unless you pass --agent, --agents, or --rotate-installed, the install command detects every installed supported agent CLI and persists round-robin mode for the daemon automatically.

If you want the Linux user service to keep running without an active login session, enable lingering first:

loginctl enable-linger "$USER"

If the daemon cannot find codex, gemini, claude, or qwen, sah daemon install fails before it starts the service. Run sah agents to inspect detection, then re-run the install from a shell where at least one supported CLI is already on PATH. The install command captures the current shell environment for the background service manager, stores absolute agent binary paths, and runs the daemon from the saved config directory instead of the shell's working directory.

sah auth login prints a verification URL and short code. Open the URL in any browser, sign in if needed, enter the code, and the CLI will finish automatically once sign-in is approved.

Test

go test ./...

Detailed test-layer and quality-gate guidance lives in testing.md.

Coverage is enforced through the shared helper script used by pre-commit and CI.

./scripts/check_coverage.sh 35

Lint

golangci-lint run

The lint profile also enforces:

  • cognitive complexity (gocognit)
  • function length (funlen)
  • duplicate blocks (dupl)

To match the Linux CI target from macOS, also run:

GOOS=linux GOARCH=amd64 golangci-lint run ./...

Pre-commit Hook

The repository includes a pre-commit hook in .githooks/. Enable it once after cloning:

git config core.hooksPath .githooks

The hook runs:

  • go mod verify
  • go mod tidy and checks that it does not rewrite go.mod or go.sum
  • CGO_ENABLED=1 go test -race ./...
  • ./scripts/check_coverage.sh 35
  • golangci-lint config verify
  • golangci-lint run ./...
  • GOOS=linux GOARCH=amd64 golangci-lint run ./...
  • go build -o .tmp-bin/sah ./cmd/sah

Release

main now treats VERSION as the release source of truth.

When VERSION changes on main, GitHub Actions (.github/workflows/tag-release.yml) creates the corresponding annotated v* tag automatically and then dispatches the existing release workflow (.github/workflows/release.yml) for that tag. The release workflow runs GoReleaser, builds macOS and Linux binaries, creates archives with checksums, publishes a GitHub Release, and updates the Homebrew tap by writing the formula into the tap repository's Formula/ directory.

Typical release flow:

printf 'v0.8.0\n' > VERSION
git add VERSION
git commit -m "Release v0.8.0"
git push origin main

Manual tags are no longer the normal path. If VERSION already has a matching tag on the current commit, the tag workflow exits without doing anything. If the tag already exists on a different commit, the workflow fails instead of silently reusing the old release.

Required repository secrets:

  • HOMEBREW_TAP_TOKEN: token with write access to corca-ai/homebrew-tap

Configuration is in .goreleaser.yaml.