Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
747d23a
feat: add dual release channel system documentation and automate beta…
samueltuyizere Jul 12, 2026
bb499da
docs: update documentation for dual release channel system and beta/p…
samueltuyizere Jul 12, 2026
9e17222
feat: enhance versioning script and documentation for beta releases; …
samueltuyizere Jul 12, 2026
18ee2be
feat: Enhance OpenRouter integration and improve streaming error hand…
samueltuyizere Jul 12, 2026
0c0c616
feat: Update README and CONFIGURATION.md to enhance OpenRouter integr…
samueltuyizere Jul 12, 2026
7b82b55
Add OpenRouter support and enhance AWS Bedrock integration
samueltuyizere Jul 12, 2026
2bb025b
feat: Implement analytics handler and storage for dashboard metrics
samueltuyizere Jul 12, 2026
b776ac9
feat: Add analytics endpoints for summary, token trends, and latency …
samueltuyizere Jul 12, 2026
31852e4
feat: Implement analytics dashboard with update channel management an…
samueltuyizere Jul 12, 2026
9f216e8
feat: Implement update command with channel management and release fe…
samueltuyizere Jul 12, 2026
ff22c98
feat: Refactor update channel command and improve channel preference …
samueltuyizere Jul 12, 2026
11773e3
feat: Implement start command to launch proxy server with GUI dashboa…
samueltuyizere Jul 12, 2026
998916c
feat: Enhance update channel management and add background daemon sup…
samueltuyizere Jul 12, 2026
fe442e7
feat: Update entry point to start in headless mode and adjust autosta…
samueltuyizere Jul 12, 2026
2421570
feat: Improve update channel command documentation and error handling
samueltuyizere Jul 12, 2026
44641f4
feat: Clean up import statements and adjust struct field formatting i…
samueltuyizere Jul 12, 2026
4161b64
fix: lint errors (errcheck, unused)
samueltuyizere Jul 12, 2026
33fffe3
fix: remaining errcheck
samueltuyizere Jul 12, 2026
ece171f
feat: Enhance build info with version, commit, and date extraction; a…
samueltuyizere Jul 12, 2026
fda9ea2
refactor: Simplify test cases for build info; improve error messages …
samueltuyizere Jul 12, 2026
3210302
fix: add missing buildinfo functions
samueltuyizere Jul 12, 2026
76f5985
fix: buildinfo tests and PIDString
samueltuyizere Jul 12, 2026
cd3fa8f
feat: macOS native GUI for start command, Linux/Windows print URL
samueltuyizere Jul 12, 2026
33e6391
fix: Docker uses serve (no GUI) instead of invalid --headless flag
samueltuyizere Jul 12, 2026
616dab2
fix: Docker uses start --background for unified headless mode
samueltuyizere Jul 12, 2026
6a35c3b
feat: implement --headless flag for start command
samueltuyizere Jul 12, 2026
0adf498
fix: correct syntax for --headless implementation
samueltuyizere Jul 12, 2026
7e4a2ba
fix: update start command description to clarify optional dashboard u…
samueltuyizere Jul 12, 2026
7780c7d
fix: update release workflow to use fetch-depth 0 for full history
samueltuyizere Jul 12, 2026
e5b2113
fix: add IsNewerVersion function for semantic version comparison
samueltuyizere Jul 12, 2026
1b9dfe5
fix: remove unnecessary 'with' block from checkout step in release wo…
samueltuyizere Jul 12, 2026
1d49ae9
fix: add 'with' block to checkout step for fetch-depth configuration
samueltuyizere Jul 12, 2026
31f7581
fix: refactor GUI port handling to use instance variable
samueltuyizere Jul 12, 2026
c54b861
fix: update GUI handling to ensure proper initialization and use atom…
samueltuyizere Jul 12, 2026
8b6c8f9
fix: enhance shutdown handling and add headless mode flag
samueltuyizere Jul 12, 2026
6d320b6
fix: refine process name check in isRoutaticProxyProcess function
samueltuyizere Jul 12, 2026
4cf8ac1
Update internal/gui/server.go
samueltuyizere Jul 12, 2026
76ab66d
fix: update UI messages for better clarity and adjust styles for impr…
samueltuyizere Jul 12, 2026
351a0fe
fix: update token handling in AnalyticsModule for consistency with ne…
samueltuyizere Jul 12, 2026
2ee733a
Update internal/gui/assets/style.css
samueltuyizere Jul 12, 2026
f2dc2c6
Update internal/gui/assets/style.css
samueltuyizere Jul 12, 2026
4e20447
Update internal/gui/assets/index.html
samueltuyizere Jul 12, 2026
7506614
Update internal/gui/assets/index.html
samueltuyizere Jul 12, 2026
ca9643e
fix: add estimated cost calculation to TokenSummary in GetTokenSummar…
samueltuyizere Jul 12, 2026
3507c57
fix: correct JSON field name for estimated cost in TokenSummary and u…
samueltuyizere Jul 12, 2026
b68c780
fix: update estimated cost field name in AnalyticsModule
samueltuyizere Jul 12, 2026
7528b42
fix: add .gstack/ to .gitignore
samueltuyizere Jul 12, 2026
38989aa
Refactor code structure for improved readability and maintainability
samueltuyizere Jul 12, 2026
309141b
feat: enhance FallbackModule with new model handling and performance …
samueltuyizere Jul 12, 2026
89ae990
refactor: streamline FallbackModule chains and enhance scenario handling
samueltuyizere Jul 12, 2026
542e883
fix: update fallback scenario and model selection elements for improv…
samueltuyizere Jul 12, 2026
c935b58
fix: update AnalyticsModule to improve loading behavior and user feed…
samueltuyizere Jul 12, 2026
fc7ff0c
feat: enhance catalog and analytics handling with latency tracking an…
samueltuyizere Jul 12, 2026
2ea7bfc
refactor: simplify provider and model record creation with dedicated …
samueltuyizere Jul 12, 2026
d865f49
fix: suppress error on response body close in ensurePortAvailable method
samueltuyizere Jul 12, 2026
5e9f7ad
chore: add Tailwind CSS as a dev dependency and configure Tailwind
samueltuyizere Jul 12, 2026
43c502a
docs: add code review guide with standards and checks
samueltuyizere Jul 12, 2026
355cc49
refactor: update documentation completeness checks and reorganize dup…
samueltuyizere Jul 12, 2026
afe958c
docs: update universal rules in the code review guide for clarity and…
samueltuyizere Jul 12, 2026
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
95 changes: 95 additions & 0 deletions .github/scripts/get-versions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/sh
# get-versions.sh - Detects versions for dual release channel system
#
# This script:
# 1. Gets the latest production version from releases branch tags
# 2. Generates a beta version with timestamp (industry standard: base on upcoming version + timestamp)
# 3. Outputs both versions as JSON
#
# Version Format:
# - Beta: v{UPCOMING_VERSION}-beta.{YYYYMMDD.HHMMSS}
# - Example: v1.3.0-beta.20260712.143015
# - The timestamp ensures uniqueness even with multiple beta releases in a day

set -eu

# Configuration
RELEASES_BRANCH="origin/releases"
TAG_PATTERN="v[0-9]*"

# Default fallback version (used when no tags found)
DEFAULT_VERSION="v0.0.0"

# Get current UTC timestamp for beta version
# Format: YYYYMMDD.HHMMSS (dot separator for SemVer compatibility)
get_timestamp() {
date -u +"%Y%m%d.%H%M%S"
}

# Get the latest production version from releases branch
get_prod_version() {
# Fetch tags from the releases branch
git fetch "${RELEASES_BRANCH}" 2>/dev/null || true

# Get the latest tag matching the pattern
# Sort versions in descending order and take the first one
latest_tag=$(git tag -l "${TAG_PATTERN}" --sort=-version:refname | head -1)

# If no tags found, use default
if [ -z "${latest_tag}" ]; then
echo "${DEFAULT_VERSION}"
else
echo "${latest_tag}"
fi
}

# Increment minor version for beta (e.g., v1.2.3 → v1.3.0)
increment_minor_version() {
local prod_version="$1"
# Parse version components using sed (POSIX compliant)
major=$(echo "${prod_version}" | sed 's/^v\([0-9]*\)\..*/\1/')
minor=$(echo "${prod_version}" | sed 's/^v[0-9]*\.\([0-9]*\).*/\1/')

if [ -z "${major}" ] || [ -z "${minor}" ]; then
echo "${DEFAULT_VERSION}"
return
fi

# Increment minor version, reset patch to 0
new_minor=$((minor + 1))
echo "v${major}.${new_minor}.0"
}

# Generate beta version based on upcoming version + timestamp
# Industry standard: v{UPCOMING_VERSION}-beta.{TIMESTAMP}
# Example: v1.3.0-beta.20260712.143015
generate_beta_version() {
upcoming_version=$(increment_minor_version "$1")
timestamp="$2"
echo "${upcoming_version}-beta.${timestamp}"
}

# Output JSON
output_json() {
prod_version="$1"
upcoming_version=$(increment_minor_version "$prod_version")
beta_version="$2"

printf '{
"prod_version": "%s",
"upcoming_version": "%s",
"beta_version": "%s"
}
' "${prod_version}" "${upcoming_version}" "${beta_version}"
}

# Main execution
main() {
prod_version=$(get_prod_version)
timestamp=$(get_timestamp)
beta_version=$(generate_beta_version "${prod_version}" "${timestamp}")

output_json "${prod_version}" "${beta_version}"
}

main
270 changes: 270 additions & 0 deletions .github/workflows/beta-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
name: Beta Release

on:
push:
branches: [main]

permissions:
contents: write

jobs:
# ── Stage 1: Test & Build Validation ──────────────────────────────
validate:
name: Test & Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: "1.25"

- name: Download dependencies
run: go mod download

- name: Vet
run: go vet ./...

- name: Test
run: go test ./... -v -race

- name: Build (sanity check)
run: go build -o /dev/null ./cmd/routatic-proxy

# ── Stage 2: Build & Release (macOS runner for DMG support) ──────
release:
name: Build & Release
needs: validate
runs-on: macos-latest
outputs:
beta_tag: ${{ steps.version.outputs.beta_tag }}
prod_version: ${{ steps.version.outputs.prod_version }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
fetch-depth: 0

- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: "1.25"
cache: true

- name: Get versions
id: version
run: |
# Make script executable and run it
chmod +x .github/scripts/get-versions.sh

# Run script and capture JSON output
VERSIONS_JSON=$(.github/scripts/get-versions.sh)

# Extract values using jq
PROD_VERSION=$(echo "$VERSIONS_JSON" | jq -r '.prod_version')
BETA_VERSION=$(echo "$VERSIONS_JSON" | jq -r '.beta_version')

echo "prod_version=${PROD_VERSION}" >> "$GITHUB_OUTPUT"
echo "beta_tag=${BETA_VERSION}" >> "$GITHUB_OUTPUT"
echo "version=${BETA_VERSION#v}" >> "$GITHUB_OUTPUT"

echo "Production version: ${PROD_VERSION}"
echo "Beta tag: ${BETA_VERSION}"

- name: Build cross-platform binaries
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
mkdir -p dist

LDFLAGS="-X main.version=${VERSION}"

# Define target platforms (bash 3 compatible — macOS default)
TARGETS="darwin-amd64:darwin/amd64 darwin-arm64:darwin/arm64 linux-amd64:linux/amd64 linux-arm64:linux/arm64 windows-amd64:windows/amd64 windows-arm64:windows/arm64"

for TARGET in $TARGETS; do
NAME="${TARGET%%:*}"
PAIR="${TARGET##*:}"
GOOS="${PAIR%/*}"
GOARCH="${PAIR#*/}"
EXT=""
[ "$GOOS" = "windows" ] && EXT=".exe"

echo "Building ${NAME}..."
CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" \
go build -ldflags "$LDFLAGS -s -w" \
-o "dist/routatic-proxy_${NAME}${EXT}" \
./cmd/routatic-proxy
done

echo ""
echo "Built binaries:"
ls -lh dist/

- name: Generate checksums
run: |
cd dist
sha256sum routatic-proxy_* > checksums.txt
cat checksums.txt

- name: Build CGO-enabled binary (for DMG)
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
CGO_ENABLED=1 go build -tags darwin -ldflags "-X main.version=${VERSION}" -o bin/routatic-proxy ./cmd/routatic-proxy

- name: Build macOS DMG
env:
VERSION: ${{ steps.version.outputs.beta_tag }}
run: |
brew install create-dmg
make dmg VERSION=${{ env.VERSION }}

- name: Generate AI Changelog
id: changelog
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
OPENROUTER_MODEL: ${{ secrets.OPENROUTER_MODEL }}
OPENROUTER_TEMPERATURE: ${{ secrets.OPENROUTER_TEMPERATURE }}
OPENROUTER_MAX_TOKENS: ${{ secrets.OPENROUTER_MAX_TOKENS }}
run: |
brew install jq

# Configuration with defaults
MODEL="${OPENROUTER_MODEL:-openai/gpt-4o-mini}"
TEMP="${OPENROUTER_TEMPERATURE:-0.3}"
TOKENS="${OPENROUTER_MAX_TOKENS:-2000}"

echo "Using OpenRouter model: $MODEL"

# Generate changelog for commits since previous beta tag or prod tag
PREVIOUS_TAG=$(git describe --tags --abbrev=0 --match "v*-*" 2>/dev/null || git describe --tags --abbrev=0 --match "v[0-9]*.[0-9]*.[0-9]*" 2>/dev/null || echo "")

if [ -n "$PREVIOUS_TAG" ]; then
echo "Generating AI changelog from $PREVIOUS_TAG to ${{ steps.version.outputs.beta_tag }}"

COMMITS=$(git log "${PREVIOUS_TAG}..HEAD" --pretty=format:"%H%n%s%n%b%n---COMMIT_SEP---")
FILE_CHANGES=$(git diff --stat "${PREVIOUS_TAG}..HEAD")

PROMPT="You are a technical writer generating release notes for a Go proxy server project (routatic-proxy).

Analyze the provided git commits and file changes, then generate a well-structured
changelog in Markdown format. Follow these guidelines:

1. Start with a brief summary paragraph (2-3 sentences) describing the overall theme of this beta release
2. Group changes into sections with these exact headers:
- **New Features** - New capabilities, enhancements, additions
- **Bug Fixes** - Fixes for reported or discovered issues
- **Improvements** - Performance, reliability, or code quality improvements
- **Documentation** - README, docs, comments, config updates
- **Chores** - Build, CI/CD, dependency updates, refactoring
3. Each bullet should be concise but descriptive (one line)
4. Mention breaking changes prominently with a warning emoji Breaking Changes section at the top
5. Use present tense, imperative mood (e.g., Add feature not Added feature)
6. Keep it technical but accessible - target audience is developers using this tool
7. This is a beta release - include a note at the end about testing and feedback

Format output as clean Markdown without any preamble or explanation. Do not wrap the entire response in a code block."

USER_CONTENT="Git commits since ${PREVIOUS_TAG}:\n\n${COMMITS}\n\nFiles changed:\n\n${FILE_CHANGES}"

# Truncate if too long (~4 chars per token)
MAX_CHARS=12000
if [ "${#USER_CONTENT}" -gt "$MAX_CHARS" ]; then
USER_CONTENT="${USER_CONTENT:0:MAX_CHARS}\n\n[...truncated for length...]"
fi

RESPONSE=$(curl -s -L -X POST "https://openrouter.ai/api/v1/chat/completions" \
-H "Authorization: Bearer ${OPENROUTER_API_KEY}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg prompt "$PROMPT" \
--arg user "$USER_CONTENT" \
--arg model "$MODEL" \
--arg temp "$TEMP" \
--arg tokens "$TOKENS" \
'{
model: $model,
messages: [
{role: "system", content: $prompt},
{role: "user", content: $user}
],
temperature: ($temp | tonumber),
max_tokens: ($tokens | tonumber)
}' \
)" \
)

CHANGELOG=$(echo "$RESPONSE" | jq -r '.choices[0].message.content // empty')

if [ -z "$CHANGELOG" ] || [ "$CHANGELOG" = "null" ]; then
echo "Warning: AI changelog generation failed, using commit list instead" >&2
echo "API response: $RESPONSE" >&2
CHANGELOG="## Commits\n\n$(git log \"${PREVIOUS_TAG}..HEAD\" --pretty=format:'- %s')"
fi
else
echo "No previous tag found, using commit list"
CHANGELOG="## Commits\n\n$(git log --pretty=format:'- %s' -20)"
fi

echo "$CHANGELOG" > changelog.md
cat changelog.md

# GITHUB_TOKEN works here — same repo
- name: Create GitHub Prerelease
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
tag_name: ${{ steps.version.outputs.beta_tag }}
name: Beta Release ${{ steps.version.outputs.beta_tag }}
body_path: changelog.md
draft: false
prerelease: true
files: |
dist/routatic-proxy_*
dist/checksums.txt
bin/RoutaticProxy.dmg

# ── Stage 3: Publish Docker Image ───────────────────────────────
docker:
name: Publish Docker Image
needs: release
permissions:
contents: read
packages: write
if: github.repository == 'routatic/proxy'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0

- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

- uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ needs.release.outputs.beta_tag }}
type=raw,value=beta-${{ needs.release.outputs.prod_version }}

- name: Strip v prefix from version
id: version
env:
TAG: ${{ needs.release.outputs.beta_tag }}
run: echo "value=${TAG#v}" >> "$GITHUB_OUTPUT"

- uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: VERSION=${{ steps.version.outputs.value }}
cache-from: type=gha
cache-to: type=gha,mode=max
Loading
Loading