Author SHA1 Message Date
james.maes 050304ff51 build(release): add release automation
Closes #9
2026-05-26 17:03:05 -05:00
james.maes 0812c7a772 fix(exec): resolve handoff executable 2026-05-26 16:28:57 -05:00
james.maes f576463c04 fix(ui): use prefix picker filtering 2026-05-26 16:28:57 -05:00
james.maes 4ed2cb28f4 feat(ui): add picker typeahead 2026-05-26 16:28:57 -05:00
james.maes 9b100de2d9 feat(ui): add terminal picker
Closes #4
2026-05-26 16:28:57 -05:00
8 changed files with 342 additions and 26 deletions

No files matched your search

+208
View File
@@ -0,0 +1,208 @@
name: Release
on:
push:
tags:
- "v*"
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
test:
name: Go checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: go vet
run: go vet ./...
- name: go test
run: go test -race -count=1 ./...
- name: go build
run: go build ./...
build:
name: Build ${{ matrix.artifact }}
needs: test
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- artifact: limen-linux-amd64
goos: linux
goarch: amd64
- artifact: limen-linux-arm64
goos: linux
goarch: arm64
- artifact: limen-macos-amd64
goos: darwin
goarch: amd64
- artifact: limen-macos-arm64
goos: darwin
goarch: arm64
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Resolve version
id: version
run: |
VERSION="${GITHUB_REF_NAME#v}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
- name: Build binary
env:
CGO_ENABLED: "0"
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
VERSION: ${{ steps.version.outputs.version }}
run: |
mkdir -p dist
go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o "dist/${{ matrix.artifact }}" .
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: dist/${{ matrix.artifact }}
release:
name: Publish GitHub release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release
find artifacts -type f -exec cp {} release/ \;
cd release
shasum -a 256 ./limen-* > checksums.txt
ls -la
- name: Create release
uses: softprops/action-gh-release@v2
with:
files: release/*
generate_release_notes: true
update-homebrew:
name: Update Homebrew tap
needs: release
runs-on: ubuntu-latest
env:
HOMEBREW_TAP_TOKEN_SET: ${{ secrets.HOMEBREW_TAP_TOKEN != '' }}
steps:
- name: Verify Homebrew tap token
run: |
if [ "${HOMEBREW_TAP_TOKEN_SET}" != "true" ]; then
echo "::error::HOMEBREW_TAP_TOKEN repo secret is required to update KofTwentyTwo/homebrew-tap."
exit 1
fi
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Checkout Homebrew tap
uses: actions/checkout@v4
with:
repository: KofTwentyTwo/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-tap
- name: Update formula
env:
TAG_NAME: ${{ github.ref_name }}
run: |
VERSION="${TAG_NAME#v}"
SHA_MACOS_ARM64=$(shasum -a 256 artifacts/limen-macos-arm64/limen-macos-arm64 | cut -d' ' -f1)
SHA_MACOS_AMD64=$(shasum -a 256 artifacts/limen-macos-amd64/limen-macos-amd64 | cut -d' ' -f1)
SHA_LINUX_ARM64=$(shasum -a 256 artifacts/limen-linux-arm64/limen-linux-arm64 | cut -d' ' -f1)
SHA_LINUX_AMD64=$(shasum -a 256 artifacts/limen-linux-amd64/limen-linux-amd64 | cut -d' ' -f1)
FORMULA="homebrew-tap/Formula/limen.rb"
mkdir -p "$(dirname "$FORMULA")"
cat > "$FORMULA" <<RUBY
class Limen < Formula
desc "Terminal launcher TUI for tmux and SSH"
homepage "https://github.com/KofTwentyTwo/limen"
version "${VERSION}"
license "GPL-3.0-only"
depends_on "tmux"
on_macos do
on_arm do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-macos-arm64"
sha256 "${SHA_MACOS_ARM64}"
end
on_intel do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-macos-amd64"
sha256 "${SHA_MACOS_AMD64}"
end
end
on_linux do
on_arm do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-linux-arm64"
sha256 "${SHA_LINUX_ARM64}"
end
on_intel do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-linux-amd64"
sha256 "${SHA_LINUX_AMD64}"
end
end
def install
binary = Dir["limen-*"].first
chmod 0755, binary
bin.install binary => "limen"
end
test do
assert_match version.to_s, shell_output("#{bin}/limen --version")
end
end
RUBY
- name: Commit and push
run: |
cd homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/limen.rb
if git status -s | grep -q "Formula/limen.rb"; then
git commit -m "Update limen to ${GITHUB_REF_NAME}"
git push
else
echo "Formula already current."
fi
+12 -11
View File
@@ -8,29 +8,30 @@ Project memory for AI assistants working in this repo. Read this first.
## Current status
**Design phase.** No Go source yet. The repository contains:
**Early implementation.** The repository contains:
- `docs/DESIGN.md` — full design and requirements document.
- Standard repo scaffolding (README, LICENSE, CONTRIBUTING, etc.).
- `.github/` — CI workflow placeholder, issue templates, PR template.
- `internal/` packages for config, state, probing, SSH, tmux parsing, exec planning, formatting, and UI.
- `main.go`, `go.mod`, and `flake.nix` for the working binary and Nix package.
- `.github/` — CI and release workflows, issue templates, PR template.
Implementation work has not started. The next milestone is to:
The next implementation milestones are to:
1. Add `go.mod`, `main.go`, and a minimal `internal/` package skeleton matching §6.3 of `DESIGN.md`.
2. Wire up the Nix flake (`flake.nix`) so `nix run` produces a binary.
3. Implement stages incrementally — config parsing first, then probing, then UI.
1. Harden the terminal UI with real-world tmux and SSH smoke testing.
2. Keep release automation green for tagged releases and downstream package managers.
3. Continue from `docs/DESIGN.md`; if behavior changes, update the design doc in the same PR.
## Key conventions
| Topic | Convention |
| ------------------ | ------------------------------------------------------------------------- |
| Language | Go 1.21+, no CGO |
| Language | Go 1.24+, no CGO |
| TUI framework | `bubbletea` + `lipgloss` |
| Default branch | `develop` (PRs target this); `main` reserved for tagged releases |
| Commit style | Conventional Commits (`feat:`, `fix:`, `docs:` …) — see `CONTRIBUTING.md` |
| License | GPL-3.0 |
| Build | Nix flake (`packages.default`) + plain `go build` for dev |
| Release | goreleaser via GitHub Actions on tag push |
| Release | GitHub Actions tag workflow, direct Go cross-builds, GitHub Releases, Homebrew tap |
| Test framework | Standard `testing` package; `teatest` for TUI integration |
| Go modules | One `internal/` per concern (config, state, probe, ssh, ui, exec, format) |
@@ -47,8 +48,8 @@ Implementation work has not started. The next milestone is to:
Targets in order of priority:
1. **Nix flake** (`nix run github:KofTwentyTwo/limen`) — primary distribution channel.
2. **Homebrew tap** at `KofTwentyTwo/homebrew-tap` (not yet created) — `brew install KofTwentyTwo/tap/limen`.
3. **GitHub Releases** with goreleaser-built binaries for darwin/linux × amd64/arm64.
2. **Homebrew tap** at `KofTwentyTwo/homebrew-tap` — `brew install KofTwentyTwo/tap/limen`.
3. **GitHub Releases** with direct Go-built binaries for macOS/Linux × amd64/arm64.
Eventual goal: submit to `homebrew-core` once the tool stabilizes.
+7 -1
View File
@@ -39,6 +39,7 @@ Examples:
- Go: standard `gofmt`. `golangci-lint` runs in CI (will be added once Go code lands).
- Markdown: 100-column soft wrap; tables and code blocks may exceed.
- Comments: explain *why*, not *what*. Code shows what.
- Local tool dependencies are listed in [`docs/DEV-TOOLS.md`](docs/DEV-TOOLS.md).
## Tests
@@ -60,7 +61,12 @@ Examples:
## Releases
Tags trigger goreleaser via GitHub Actions, which cross-compiles for darwin/linux × amd64/arm64 and publishes binaries to the GitHub Releases page. See [`docs/DESIGN.md` §10.4](docs/DESIGN.md).
Tags trigger GitHub Actions, which runs the Go checks, builds macOS/Linux binaries for amd64/arm64, publishes GitHub Release assets, and updates the `KofTwentyTwo/homebrew-tap` formula. See [`docs/DESIGN.md` §10.4](docs/DESIGN.md).
Release prerequisites:
- `KofTwentyTwo/homebrew-tap` must exist.
- The `limen` repository must have a `HOMEBREW_TAP_TOKEN` Actions secret with contents read/write access to `KofTwentyTwo/homebrew-tap`.
- The release tag must use the `vMAJOR.MINOR.PATCH` form, for example `v0.1.0`.
## Code of conduct
+21 -6
View File
@@ -4,7 +4,7 @@
A terminal launcher TUI for tmux and SSH. The first thing you see when you open a new terminal: pick a host, pick a session, get to work.
**Status:** Design phase. No working binary yet — see [`docs/DESIGN.md`](docs/DESIGN.md) for the spec we're building toward.
**Status:** Early implementation. The binary can launch the host and session picker; see [`docs/DESIGN.md`](docs/DESIGN.md) for the canonical spec.
---
@@ -38,11 +38,26 @@ Press `Esc` at any point and `limen` drops you into a fresh unnamed tmux session
## Install
Coming soon. The design targets these distribution channels:
Install with Nix:
- **Nix flake** — `nix run github:KofTwentyTwo/limen`
- **Homebrew tap** — `brew install KofTwentyTwo/tap/limen` (planned)
- **Binary releases** — GitHub Releases page (planned)
```bash
nix run github:KofTwentyTwo/limen
```
Install with Homebrew after the first tagged release:
```bash
brew install KofTwentyTwo/tap/limen
```
Prebuilt binaries are published to the GitHub Releases page for:
| Platform | Architecture | Binary |
|----------|--------------|--------|
| Linux | x64 | `limen-linux-amd64` |
| Linux | ARM64 | `limen-linux-arm64` |
| macOS | Intel | `limen-macos-amd64` |
| macOS | Apple Silicon | `limen-macos-arm64` |
## Configuration
@@ -70,7 +85,7 @@ The full design and requirements document lives at [`docs/DESIGN.md`](docs/DESIG
## Status & roadmap
This repository currently contains only the design document and standard repo scaffolding. Implementation will land on the `develop` branch.
Implementation lands on the `develop` branch. Tagged releases publish prebuilt binaries and update the Homebrew tap.
## Contributing
+6 -7
View File
@@ -616,7 +616,7 @@ limen/
├── .github/
│ └── workflows/
│ ├── ci.yml # go test + go vet on push/PR
│ └── release.yml # tag → goreleaser → binaries + checksums
│ └── release.yml # tag -> Go cross-builds -> releases + Homebrew tap
├── docs/
│ ├── DESIGN.md # This document (or a slightly edited copy)
│ └── README.md # User-facing docs
@@ -626,7 +626,6 @@ limen/
├── go.mod
├── go.sum
├── main.go
├── .goreleaser.yaml # Cross-compile darwin + linux, amd64 + arm64
├── LICENSE # GPL-3.0 (matches KofTwentyTwo OSS standard)
└── README.md # Repo top-level readme
```
@@ -679,7 +678,7 @@ home.packages = [ inputs.limen.packages.${system}.default ];
Path A — **personal tap (preferred for initial release):**
The user creates `github.com/<owner>/homebrew-tap` with a `Formula/limen.rb` that fetches the GitHub release tarball and `go build`s, OR (better) fetches the pre-built binary published by goreleaser. Users install via `brew install <owner>/tap/limen`.
The user creates `github.com/<owner>/homebrew-tap` with a `Formula/limen.rb` that fetches the pre-built binary published to GitHub Releases. Users install via `brew install <owner>/tap/limen`.
Path B — **homebrew-core (later):**
@@ -700,10 +699,10 @@ git push origin v0.1.0
GitHub Actions runs `release.yml`:
1. Checks out at the tag.
2. Runs `goreleaser release --clean`.
3. goreleaser cross-compiles for `darwin/amd64`, `darwin/arm64`, `linux/amd64`, `linux/arm64`.
4. Uploads release artifacts (tarballs + `checksums.txt`) to the GitHub release page.
5. (Optional) Updates the homebrew tap formula via a goreleaser hook.
2. Runs `go vet`, `go test -race -count=1 ./...`, and `go build ./...`.
3. Cross-compiles with CGO disabled for `darwin/amd64`, `darwin/arm64`, `linux/amd64`, `linux/arm64`.
4. Uploads release artifacts and `checksums.txt` to the GitHub release page.
5. Updates the `KofTwentyTwo/homebrew-tap` formula with release URLs and SHA256 hashes using `HOMEBREW_TAP_TOKEN`.
---
+43
View File
@@ -0,0 +1,43 @@
# Development Tools
This repo is intentionally light on local tooling. The following packages cover
normal development, release verification, and runtime smoke testing.
## Home Manager Package Set
```nix
home.packages = with pkgs; [
go_1_24
gopls
gotools
git
gh
ripgrep
nix
actionlint
shellcheck
ruby
tmux
openssh
];
```
## Why Each Tool Is Here
| Tool | Use |
|------|-----|
| `go_1_24` | Builds and tests the Go module declared in `go.mod`. |
| `gopls` | Go language-server support for editors. |
| `gotools` | Standard Go helper tools used by editors and local workflows. |
| `git` | Source control, branches, tags, and tap repo updates. |
| `gh` | GitHub issue, PR, repository, and release workflows. |
| `ripgrep` | Fast repo search while developing and reviewing. |
| `nix` | Flake checks, package builds, and downstream Nix integration testing. |
| `actionlint` | Static validation for GitHub Actions workflows. |
| `shellcheck` | Shell validation used directly and by `actionlint`. |
| `ruby` | Local syntax checks for the Homebrew formula. |
| `tmux` | Runtime dependency for local session creation and attachment. |
| `openssh` | Runtime dependency for remote host connections. |
+3 -1
View File
@@ -10,17 +10,19 @@
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
version = "0.1.0";
in
{
packages.default = pkgs.buildGoModule {
pname = "limen";
version = "0.1.0";
inherit version;
src = ./.;
vendorHash = "sha256-zYQ6hMFBFDPNlViB7EmnxbXozardyYeHiUSiG4uS/9Y=";
ldflags = [
"-s"
"-w"
"-X main.version=${version}"
];
meta = {
+42
View File
@@ -0,0 +1,42 @@
class Limen < Formula
desc "Terminal launcher TUI for tmux and SSH"
homepage "https://github.com/KofTwentyTwo/limen"
version "0.1.0"
license "GPL-3.0-only"
depends_on "tmux"
on_macos do
on_arm do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-macos-arm64"
sha256 "PLACEHOLDER_MACOS_ARM64_SHA256"
end
on_intel do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-macos-amd64"
sha256 "PLACEHOLDER_MACOS_AMD64_SHA256"
end
end
on_linux do
on_arm do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-linux-arm64"
sha256 "PLACEHOLDER_LINUX_ARM64_SHA256"
end
on_intel do
url "https://github.com/KofTwentyTwo/limen/releases/download/v#{version}/limen-linux-amd64"
sha256 "PLACEHOLDER_LINUX_AMD64_SHA256"
end
end
def install
binary = Dir["limen-*"].first
chmod 0755, binary
bin.install binary => "limen"
end
test do
assert_match version.to_s, shell_output("#{bin}/limen --version")
end
end