Skip to content

Commit 066afad

Browse files
committed
initial code port
1 parent 6df552b commit 066afad

18 files changed

Lines changed: 3294 additions & 0 deletions

.github/workflows/govulncheck.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Run govulncheck
2+
on:
3+
schedule:
4+
- cron: "0 12 * * *" # 8am EST / 10am PST / 12pm UTC
5+
workflow_dispatch: # allow manual trigger for testing
6+
pull_request:
7+
paths:
8+
- ".github/workflows/govulncheck.yaml"
9+
jobs:
10+
govulncheck:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
14+
15+
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
16+
with:
17+
go-version-file: go.mod
18+
cache: false
19+
20+
- name: Install govulncheck
21+
run: go install golang.org/x/vuln/cmd/govulncheck@latest
22+
23+
- name: Scan source code for known vulnerabilities
24+
run: govulncheck -test ./...
25+
26+
- name: Post to slack
27+
if: failure() && github.event_name == 'schedule'
28+
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
29+
with:
30+
method: chat.postMessage
31+
token: ${{ secrets.GOVULNCHECK_BOT_TOKEN }}
32+
payload: |
33+
{
34+
"channel": "TO_BE_MANUALLY_INPUT_LATER",
35+
"blocks": [
36+
{
37+
"type": "section",
38+
"text": {
39+
"type": "mrkdwn",
40+
"text": "Govulncheck failed in ${{ github.repository }}"
41+
},
42+
"accessory": {
43+
"type": "button",
44+
"text": {
45+
"type": "plain_text",
46+
"text": "View results"
47+
},
48+
"url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
49+
}
50+
}
51+
]
52+
}

.github/workflows/release.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: release-on-tag
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
# Allows manual triggering of the workflow
9+
workflow_dispatch:
10+
inputs:
11+
tag:
12+
description: 'Tag release (e.g. v1.2.3)'
13+
required: true
14+
15+
# allow for testing of PR updating this file
16+
pull_request:
17+
paths:
18+
- ".github/workflows/release.yaml"
19+
20+
permissions:
21+
contents: write
22+
23+
jobs:
24+
goreleaser:
25+
runs-on: ubuntu-latest
26+
steps:
27+
-
28+
name: Checkout
29+
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # 4.3.0
30+
with:
31+
fetch-depth: 0
32+
ref: ${{ github.event.inputs.tag || github.ref }}
33+
-
34+
name: Set up Go
35+
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
36+
with:
37+
go-version-file: go.mod
38+
cache: false
39+
-
40+
name: Set GoReleaser args for PR dry run
41+
id: goreleaser-args
42+
run: |
43+
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
44+
echo "args=release --clean --skip=publish --snapshot" >> $GITHUB_OUTPUT
45+
else
46+
echo "args=release --clean" >> $GITHUB_OUTPUT
47+
fi
48+
-
49+
name: Run GoReleaser
50+
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a #v6.4.0
51+
with:
52+
distribution: goreleaser
53+
version: '~> v2'
54+
args: ${{ steps.goreleaser-args.outputs.args }}
55+
env:
56+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
aperture
2+
dist/
3+
*.test
4+
*.out

.goreleaser.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
version: 2
2+
3+
before:
4+
hooks:
5+
- go mod tidy
6+
7+
builds:
8+
- id: aperture
9+
binary: aperture
10+
main: ./cmd/aperture
11+
ldflags:
12+
- -s -w
13+
- -X main.buildCommit={{.ShortCommit}}
14+
- -X main.buildDate={{.Date}}
15+
env:
16+
- CGO_ENABLED=0
17+
goos:
18+
- linux
19+
- darwin
20+
- windows
21+
goarch:
22+
- amd64
23+
- arm64
24+
25+
archives:
26+
- formats:
27+
- tar.gz
28+
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
29+
format_overrides:
30+
- goos: windows
31+
formats:
32+
- zip
33+
34+
checksum:
35+
name_template: "checksums.txt"
36+
37+
changelog:
38+
sort: asc
39+
filters:
40+
exclude:
41+
- "^docs:"
42+
- "^test:"
43+
- "^chore:"

AGENTS.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# aperture-launcher Architecture
2+
3+
## Overview
4+
5+
`cmd/launcher` makes it very easy to launch a coding agent
6+
preconfigured to work with Aperture.
7+
8+
Coding agents have different environment variables and configuration
9+
files that they use to work with various upstream providers. Managing
10+
these can be complex and error prone. launcher captures this complex
11+
into Profiles.
12+
13+
A profile exists for each supported coding agant and the backends it
14+
works with.
15+

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

Makefile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: build test clean install
2+
3+
build:
4+
go build -o aperture ./cmd/aperture
5+
6+
test:
7+
go test ./...
8+
9+
install:
10+
go install ./cmd/aperture
11+
12+
clean:
13+
rm -f aperture

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# aperture-cli
2+
3+
> [!WARNING]
4+
> **This repository is experimental.** It is under active development, may change significantly without notice.
5+
6+
A CLI launcher for coding agents preconfigured to work with [Aperture](https://aperture.tailscale.com). It manages installation, configuration and environment variables that make using multiple providers and models very easy.
7+
8+
## Supported agents
9+
10+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
11+
- [Gemini CLI](https://github.com/google-gemini/gemini-cli)
12+
- [OpenCode](https://github.com/sst/opencode)
13+
- [Codex](https://github.com/openai/codex)
14+
15+
## Installation
16+
17+
```sh
18+
go install github.com/tailscale/aperture-cli/cmd/aperture@latest
19+
```
20+
21+
Or build from source:
22+
23+
```sh
24+
make build
25+
```
26+
27+
## Usage
28+
29+
```sh
30+
aperture
31+
```
32+
33+
On first run, `aperture` will attempt to connect to `http://ai`. If it cannot reach that host, it will prompt you to configure an Aperture endpoint.
34+
35+
### Flags
36+
37+
| Flag | Description |
38+
|------|-------------|
39+
| `-version` | Print build version and exit |
40+
| `-debug` | Print environment variables set before launching the agent |
41+
42+
## Development
43+
44+
```sh
45+
make build # build ./aperture
46+
make test # run tests
47+
make install # install to $GOPATH/bin
48+
make clean # remove built binary
49+
```

go.mod

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module github.com/tailscale/aperture-cli
2+
3+
go 1.23
4+
5+
require (
6+
github.com/charmbracelet/bubbletea v1.3.4
7+
github.com/charmbracelet/lipgloss v1.1.0
8+
)
9+
10+
require (
11+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
12+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
13+
github.com/charmbracelet/x/ansi v0.8.0 // indirect
14+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
15+
github.com/charmbracelet/x/term v0.2.1 // indirect
16+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
17+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
18+
github.com/mattn/go-isatty v0.0.20 // indirect
19+
github.com/mattn/go-localereader v0.0.1 // indirect
20+
github.com/mattn/go-runewidth v0.0.16 // indirect
21+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
22+
github.com/muesli/cancelreader v0.2.2 // indirect
23+
github.com/muesli/termenv v0.16.0 // indirect
24+
github.com/rivo/uniseg v0.4.7 // indirect
25+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
26+
golang.org/x/sync v0.11.0 // indirect
27+
golang.org/x/sys v0.30.0 // indirect
28+
golang.org/x/text v0.3.8 // indirect
29+
)

go.sum

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
2+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
3+
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
4+
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
5+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
6+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
7+
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
8+
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
9+
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
10+
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
11+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
12+
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
13+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
14+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
15+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
16+
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
17+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
18+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
19+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
20+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
21+
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
22+
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
23+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
24+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
25+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
26+
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
27+
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
28+
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
29+
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
30+
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
31+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
32+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
33+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
34+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
35+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
36+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
37+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
38+
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
39+
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
40+
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
41+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
43+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
44+
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
45+
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=

0 commit comments

Comments
 (0)