f99010fae1
Desktop Artifacts / Desktop Build (Linux) (push) Waiting to run
Desktop Artifacts / Desktop Build (Windows) (push) Waiting to run
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Waiting to run
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
568 lines
23 KiB
Makefile
568 lines
23 KiB
Makefile
.DEFAULT_GOAL := help
|
|
|
|
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
|
COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
|
|
LDFLAGS := -X main.version=$(VERSION) \
|
|
-X main.commit=$(COMMIT) \
|
|
-X main.buildDate=$(BUILD_DATE)
|
|
|
|
LDFLAGS_RELEASE := $(LDFLAGS) -s -w
|
|
DESKTOP_DIST_DIR := dist/desktop
|
|
GOLANGCI_LINT_VERSION ?= v2.11.4
|
|
# Isolate each checkout from stale sibling-worktree fixes and issue positions.
|
|
GOLANGCI_LINT_CACHE ?= $(CURDIR)/.golangci-cache
|
|
export GOLANGCI_LINT_CACHE
|
|
CUSTOM_GCL := ./custom-gcl
|
|
PRICING_SNAPSHOT_FILE := internal/pricing/snapshot/litellm_snapshot.json.gz
|
|
|
|
# sqlite-vec's cgo bindings #include "sqlite3.h". Without an override the
|
|
# compiler falls back to the system header (the macOS SDK one marks
|
|
# sqlite3_auto_extension deprecated, warning on every build) which can also
|
|
# drift from the amalgamation mattn/go-sqlite3 statically links. Compile
|
|
# against the bundled amalgamation's own header instead, mirroring the
|
|
# Linux release workflow in .github/workflows/release.yml.
|
|
# Setting CGO_CFLAGS replaces Go's built-in default of "-O2 -g", so restate
|
|
# it explicitly or the SQLite amalgamation compiles unoptimized (2-3x slower
|
|
# queries, caught by the bench gate). Caller-provided flags stay last so
|
|
# they can still override.
|
|
SQLITE_INCLUDE_DIR := .sqlite-include
|
|
export CGO_CFLAGS := -O2 -g -I$(CURDIR)/$(SQLITE_INCLUDE_DIR) $(CGO_CFLAGS)
|
|
|
|
GOPATH_FIRST := $(shell go env GOPATH | cut -d: -f1)
|
|
AIR_BIN := $(shell if command -v air >/dev/null 2>&1; then command -v air; \
|
|
elif [ -n "$$(go env GOBIN)" ] && [ -x "$$(go env GOBIN)/air" ]; then printf "%s" "$$(go env GOBIN)/air"; \
|
|
elif [ -x "$(GOPATH_FIRST)/bin/air" ]; then printf "%s" "$(GOPATH_FIRST)/bin/air"; \
|
|
fi)
|
|
|
|
.PHONY: build build-release install frontend frontend-dev dev check-air air-install desktop-dev desktop-build desktop-macos-app desktop-macos-dmg desktop-windows-installer desktop-linux-appimage desktop-app docs-install docs-build docs-serve docs-check docs-screenshots docs-assets-branch docs-generated-assets-branch docs-deploy-staging docs-deploy test test-short test-evalingest bench-backends bench-gate bench-gate-config test-postgres test-postgres-ci test-s3 postgres-up postgres-down test-ssh test-ssh-ci ssh-up ssh-down e2e e2e-duckdb vet lint lint-ci lint-golangci lint-golangci-ci nilaway nilaway-golangci-build lint-tools tidy clean release release-darwin-arm64 release-darwin-amd64 release-linux-amd64 install-hooks ensure-embed-dir pricing-snapshot sqlite-vec-header dev-snapshot help
|
|
|
|
# Ensure go:embed has at least one file (no-op if frontend is built)
|
|
ensure-embed-dir:
|
|
@mkdir -p internal/web/dist
|
|
@test -f internal/web/dist/.keep \
|
|
|| printf '%s\n' \
|
|
'keep embed dir for generated frontend assets' \
|
|
> internal/web/dist/.keep
|
|
|
|
# Copy the go-sqlite3 amalgamation header where CGO_CFLAGS points.
|
|
# Chained from pricing-snapshot so every Go-compiling target stages it
|
|
# without lengthening each prerequisite list.
|
|
sqlite-vec-header:
|
|
@go mod download github.com/mattn/go-sqlite3
|
|
@mkdir -p $(SQLITE_INCLUDE_DIR)
|
|
@install -m 0644 \
|
|
"$$(go list -m -f '{{.Dir}}' github.com/mattn/go-sqlite3)/sqlite3-binding.h" \
|
|
$(SQLITE_INCLUDE_DIR)/sqlite3.h
|
|
|
|
# Restore the generated LiteLLM fallback snapshot from its artifact branch.
|
|
# Pinned ref, SHA256, and branch are compiled into the snapshot tool.
|
|
pricing-snapshot: sqlite-vec-header
|
|
go run ./internal/pricing/cmd/litellm-snapshot -restore
|
|
|
|
# Build the binary (debug, with embedded pricing snapshot and frontend)
|
|
build: pricing-snapshot frontend
|
|
CGO_ENABLED=1 go build -tags fts5 -ldflags="$(LDFLAGS)" -o agentsview ./cmd/agentsview
|
|
@chmod +x agentsview
|
|
|
|
# Build with optimizations (release)
|
|
build-release: pricing-snapshot frontend
|
|
CGO_ENABLED=1 go build -tags fts5 -ldflags="$(LDFLAGS_RELEASE)" -trimpath -o agentsview ./cmd/agentsview
|
|
@chmod +x agentsview
|
|
|
|
# Install to ~/.local/bin, $GOBIN, or $GOPATH/bin.
|
|
# Copy to a temp file in the destination directory, then rename into place.
|
|
# Rename is atomic and produces a fresh inode, so overwriting the binary while
|
|
# an old agentsview is still running does not leave the kernel validating exec
|
|
# against stale code-signature pages (which SIGKILLs the new process on macOS).
|
|
install: build-release
|
|
@if [ -d "$(HOME)/.local/bin" ]; then \
|
|
INSTALL_DIR="$(HOME)/.local/bin"; \
|
|
else \
|
|
INSTALL_DIR="$${GOBIN:-$$(go env GOBIN)}"; \
|
|
if [ -z "$$INSTALL_DIR" ]; then \
|
|
GOPATH_FIRST="$$(go env GOPATH | cut -d: -f1)"; \
|
|
INSTALL_DIR="$$GOPATH_FIRST/bin"; \
|
|
fi; \
|
|
mkdir -p "$$INSTALL_DIR"; \
|
|
fi; \
|
|
echo "Installing to $$INSTALL_DIR/agentsview"; \
|
|
tmp="$$(mktemp "$$INSTALL_DIR/agentsview.tmp.XXXXXX")" || exit $$?; \
|
|
cleanup() { rm -f "$$tmp"; }; \
|
|
trap cleanup EXIT HUP INT TERM; \
|
|
cp agentsview "$$tmp" && chmod 755 "$$tmp" && mv -f "$$tmp" "$$INSTALL_DIR/agentsview"; \
|
|
status=$$?; \
|
|
trap - EXIT HUP INT TERM; \
|
|
cleanup; \
|
|
exit $$status
|
|
|
|
# Build frontend SPA and copy into embed directory
|
|
frontend:
|
|
cd frontend && npm ci && npm run build
|
|
rm -rf internal/web/dist
|
|
cp -r frontend/dist internal/web/dist
|
|
printf '%s\n' \
|
|
'keep embed dir for generated frontend assets' \
|
|
> internal/web/dist/.keep
|
|
|
|
# Run Vite+ dev server (use alongside `make dev`)
|
|
frontend-dev:
|
|
cd frontend && npm run dev
|
|
|
|
# Build and run agentsview against a fresh snapshot of the prod SQLite DB.
|
|
# Prod DB is never written; sqlite3 .backup is WAL-safe even with prod running.
|
|
# Prod config.toml is NOT copied, so remote PG push is disabled in the snapshot.
|
|
# Overrides:
|
|
# PROD_DATA_DIR - source data dir (default: $$HOME/.agentsview)
|
|
# SNAPSHOT_DIR - destination dir (default: tmp/prod-snapshot)
|
|
# RESNAPSHOT=0 - reuse existing snapshot instead of re-cloning
|
|
PROD_DATA_DIR ?= $(HOME)/.agentsview
|
|
SNAPSHOT_DIR ?= tmp/prod-snapshot
|
|
# Resolve SNAPSHOT_DIR so relative and absolute paths both work.
|
|
SNAPSHOT_ABS := $(abspath $(SNAPSHOT_DIR))
|
|
|
|
# Sentinel file written into a snapshot directory the first time
|
|
# we populate it. Subsequent runs require this marker before
|
|
# touching any contents, so pointing SNAPSHOT_DIR at an
|
|
# unrelated existing directory cannot accidentally delete
|
|
# someone's files. The previous version used rm -rf on the
|
|
# whole directory; that left dangerous edge cases (e.g.
|
|
# SNAPSHOT_DIR=tmp wiping unrelated tmp/ contents) even with a
|
|
# denylist, so we now only ever delete a small set of files we
|
|
# know we wrote.
|
|
SNAPSHOT_MARKER := .agentsview-snapshot
|
|
|
|
dev-snapshot: build
|
|
@if [ ! -f "$(PROD_DATA_DIR)/sessions.db" ]; then \
|
|
echo "error: prod sessions.db not found at $(PROD_DATA_DIR)/sessions.db" >&2; \
|
|
exit 1; \
|
|
fi
|
|
@if [ -z "$(SNAPSHOT_ABS)" ]; then \
|
|
echo "error: SNAPSHOT_DIR resolved to empty path" >&2; \
|
|
exit 1; \
|
|
fi
|
|
@if [ -d "$(SNAPSHOT_ABS)" ] && [ ! -f "$(SNAPSHOT_ABS)/$(SNAPSHOT_MARKER)" ]; then \
|
|
if [ -n "$$(ls -A "$(SNAPSHOT_ABS)" 2>/dev/null)" ]; then \
|
|
echo "error: $(SNAPSHOT_ABS) is non-empty and missing the $(SNAPSHOT_MARKER) marker" >&2; \
|
|
echo " refusing to touch a directory we did not create" >&2; \
|
|
echo " remove the directory manually if you want to reuse this path" >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
fi
|
|
@mkdir -p "$(SNAPSHOT_ABS)"
|
|
@touch "$(SNAPSHOT_ABS)/$(SNAPSHOT_MARKER)"
|
|
@if [ "$${RESNAPSHOT:-1}" = "1" ] || [ ! -f "$(SNAPSHOT_ABS)/sessions.db" ]; then \
|
|
echo "Snapshotting $(PROD_DATA_DIR)/sessions.db -> $(SNAPSHOT_ABS)/sessions.db"; \
|
|
for f in sessions.db sessions.db-wal sessions.db-shm \
|
|
config.toml config.json config.json.bak \
|
|
debug.log; do \
|
|
rm -f "$(SNAPSHOT_ABS)/$$f"; \
|
|
done; \
|
|
sqlite3 "$(PROD_DATA_DIR)/sessions.db" \
|
|
".backup $(SNAPSHOT_ABS)/sessions.db"; \
|
|
else \
|
|
echo "Reusing existing snapshot at $(SNAPSHOT_ABS)/sessions.db"; \
|
|
fi
|
|
AGENTSVIEW_DATA_DIR="$(SNAPSHOT_ABS)" ./agentsview serve --port 0
|
|
|
|
# Ensure air is installed for backend live reload
|
|
check-air:
|
|
@if [ -z "$(AIR_BIN)" ]; then \
|
|
echo "air not found. Install with: make air-install" >&2; \
|
|
exit 1; \
|
|
fi
|
|
|
|
# Install air for backend live reload
|
|
air-install:
|
|
go install github.com/air-verse/air@latest
|
|
|
|
# Run Go server in dev mode with live reload (use with frontend-dev).
|
|
# Edits to .go files trigger a rebuild + restart via air.
|
|
dev: pricing-snapshot ensure-embed-dir check-air
|
|
"$(AIR_BIN)" -c .air.toml -- $(ARGS)
|
|
|
|
# Run the Tauri desktop wrapper in development mode
|
|
desktop-dev:
|
|
cd desktop && npm ci && npm run tauri:dev
|
|
|
|
# Build desktop app bundles via Tauri
|
|
desktop-build:
|
|
cd desktop && npm ci && npm run tauri:build
|
|
|
|
# Build only the macOS .app bundle (skip DMG packaging).
|
|
# Skips updater artifact signing when TAURI_SIGNING_PRIVATE_KEY
|
|
# is not set so local builds succeed without release keys.
|
|
desktop-macos-app:
|
|
cd desktop && npm ci && npm run tauri:build:macos-app \
|
|
$(if $(TAURI_SIGNING_PRIVATE_KEY),,-- --config '{"bundle":{"createUpdaterArtifacts":false}}')
|
|
mkdir -p $(DESKTOP_DIST_DIR)/macos
|
|
rm -rf $(DESKTOP_DIST_DIR)/macos/AgentsView.app
|
|
cp -R desktop/src-tauri/target/release/bundle/macos/AgentsView.app \
|
|
$(DESKTOP_DIST_DIR)/macos/AgentsView.app
|
|
@echo "macOS app bundle copied to $(DESKTOP_DIST_DIR)/macos/AgentsView.app"
|
|
|
|
# Build macOS DMG installer
|
|
desktop-macos-dmg:
|
|
cd desktop && npm ci && npm run tauri:build:macos-dmg
|
|
mkdir -p $(DESKTOP_DIST_DIR)/macos
|
|
rm -f $(DESKTOP_DIST_DIR)/macos/*.dmg
|
|
@dmg_count=$$(find desktop/src-tauri/target/release/bundle/dmg \
|
|
-maxdepth 1 -type f -name '*.dmg' | wc -l | tr -d ' '); \
|
|
if [ "$$dmg_count" -eq 0 ]; then \
|
|
echo "error: no DMG installer found in bundle output" >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
find desktop/src-tauri/target/release/bundle/dmg \
|
|
-maxdepth 1 -type f -name '*.dmg' \
|
|
-exec cp {} $(DESKTOP_DIST_DIR)/macos/ \;; \
|
|
echo "Copied $$dmg_count DMG installer(s) to $(DESKTOP_DIST_DIR)/macos/"
|
|
|
|
# Build Windows NSIS installer bundle (.exe)
|
|
# Run on Windows runner/host.
|
|
desktop-windows-installer:
|
|
cd desktop && npm ci && npm run tauri:build:windows
|
|
mkdir -p $(DESKTOP_DIST_DIR)/windows
|
|
rm -f $(DESKTOP_DIST_DIR)/windows/*.exe
|
|
@bundle_dir="desktop/src-tauri/target/release/bundle/nsis"; \
|
|
target_triple="$${TAURI_ENV_TARGET_TRIPLE:-$${CARGO_BUILD_TARGET:-}}"; \
|
|
if [ -z "$$target_triple" ] && command -v rustc >/dev/null 2>&1; then \
|
|
host_triple=$$(rustc -vV | awk '/^host: /{print $$2}'); \
|
|
if [ "$$host_triple" = "aarch64-pc-windows-msvc" ]; then \
|
|
target_triple="$$host_triple"; \
|
|
fi; \
|
|
fi; \
|
|
if [ -n "$$target_triple" ] && \
|
|
[ -d "desktop/src-tauri/target/$$target_triple/release/bundle/nsis" ]; then \
|
|
bundle_dir="desktop/src-tauri/target/$$target_triple/release/bundle/nsis"; \
|
|
fi; \
|
|
if [ ! -d "$$bundle_dir" ]; then \
|
|
echo "error: Windows bundle output directory not found: $$bundle_dir" >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
exe_count=$$(find "$$bundle_dir" \
|
|
-maxdepth 1 -type f -name '*.exe' | wc -l | tr -d ' '); \
|
|
if [ "$$exe_count" -eq 0 ]; then \
|
|
echo "error: no Windows installer (.exe) found in $$bundle_dir" >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
find "$$bundle_dir" \
|
|
-maxdepth 1 -type f -name '*.exe' \
|
|
-exec cp {} $(DESKTOP_DIST_DIR)/windows/ \;; \
|
|
echo "Copied $$exe_count Windows installer(s) to $(DESKTOP_DIST_DIR)/windows/"
|
|
|
|
# Build Linux AppImage bundle
|
|
# Run on a Linux host.
|
|
desktop-linux-appimage:
|
|
cd desktop && npm ci && npm run tauri:build:linux \
|
|
$(if $(TAURI_SIGNING_PRIVATE_KEY),,-- --config '{"bundle":{"createUpdaterArtifacts":false}}')
|
|
cd desktop && bash scripts/repair-appimage-diricon.sh \
|
|
src-tauri/target/release/bundle/appimage/*.AppImage
|
|
mkdir -p $(DESKTOP_DIST_DIR)/linux
|
|
rm -f $(DESKTOP_DIST_DIR)/linux/*.AppImage
|
|
@ai_count=$$(find desktop/src-tauri/target/release/bundle/appimage \
|
|
-maxdepth 1 -type f -name '*.AppImage' | wc -l | tr -d ' '); \
|
|
if [ "$$ai_count" -eq 0 ]; then \
|
|
echo "error: no AppImage found in bundle output" >&2; \
|
|
exit 1; \
|
|
fi; \
|
|
find desktop/src-tauri/target/release/bundle/appimage \
|
|
-maxdepth 1 -type f -name '*.AppImage' \
|
|
-exec cp {} $(DESKTOP_DIST_DIR)/linux/ \;; \
|
|
echo "Copied $$ai_count AppImage(s) to $(DESKTOP_DIST_DIR)/linux/"
|
|
|
|
# Backward-compatible alias (macOS .app)
|
|
desktop-app: desktop-macos-app
|
|
|
|
# Run tests
|
|
test: pricing-snapshot ensure-embed-dir
|
|
go test -tags "fts5" ./... -v -count=1
|
|
|
|
# Run fast tests only
|
|
test-short: pricing-snapshot ensure-embed-dir
|
|
go test -tags "fts5" ./... -short -count=1
|
|
|
|
# Run the quarantined eval-ingest endpoint tests under their build tag.
|
|
test-evalingest: pricing-snapshot ensure-embed-dir
|
|
CGO_ENABLED=1 go test -tags "fts5,evalingest" \
|
|
./internal/db ./internal/server -v -count=1
|
|
|
|
# Compare db.Store read-query performance across SQLite, DuckDB, and PostgreSQL.
|
|
# Requires Docker because the PostgreSQL backend is started with testcontainers.
|
|
BENCH_BACKENDS_FLAGS ?= -bench . -run '^$$' -benchmem
|
|
BENCH_BACKENDS_SESSIONS ?= 1000
|
|
BENCH_BACKENDS_MESSAGES_PER_SESSION ?= 64
|
|
bench-backends: pricing-snapshot ensure-embed-dir
|
|
AGENTSVIEW_BENCH_SESSIONS=$(BENCH_BACKENDS_SESSIONS) \
|
|
AGENTSVIEW_BENCH_MESSAGES_PER_SESSION=$(BENCH_BACKENDS_MESSAGES_PER_SESSION) \
|
|
CGO_ENABLED=1 go test -tags "fts5,benchdb" ./internal/backendbench $(BENCH_BACKENDS_FLAGS)
|
|
|
|
# Hot-path benchmark gate. Runs every benchmark in the gated packages
|
|
# (sync engine warm/cold/append, message write paths, usage
|
|
# aggregation, secret scanning). This target is the single source of
|
|
# truth for the gate configuration: CI's bench.yml runs it on both
|
|
# the PR head and the merge base, then compares the outputs with
|
|
# `go run ./cmd/benchgate -old old.txt -new new.txt`. Run it before
|
|
# and after touching a sync or DB hot path.
|
|
BENCH_GATE_PACKAGES ?= ./internal/sync ./internal/db ./internal/secrets
|
|
# Count must stay >= 5: benchgate's time gate needs at least 5
|
|
# candidate samples for its significance test.
|
|
BENCH_GATE_COUNT ?= 6
|
|
# Fixed iterations, not a duration: some gated benchmarks grow their
|
|
# fixture as they iterate, so baseline and candidate must run the
|
|
# same iteration count to measure identical workloads.
|
|
BENCH_GATE_TIME ?= 20x
|
|
bench-gate: pricing-snapshot ensure-embed-dir
|
|
CGO_ENABLED=1 go test -tags "fts5" -run '^$$' \
|
|
-bench . -benchmem \
|
|
-count $(BENCH_GATE_COUNT) -benchtime $(BENCH_GATE_TIME) \
|
|
-timeout 25m $(BENCH_GATE_PACKAGES)
|
|
|
|
# Prints the gate's sample/iteration configuration in shell-evalable
|
|
# form. CI evaluates this on the PR head and passes the values into
|
|
# the merge-base `make bench-gate` invocation, so both sides measure
|
|
# identical workloads even when a PR changes the defaults above (the
|
|
# package list intentionally stays per-side).
|
|
bench-gate-config:
|
|
@echo "BENCH_GATE_COUNT=$(BENCH_GATE_COUNT) BENCH_GATE_TIME=$(BENCH_GATE_TIME)"
|
|
|
|
# Start test PostgreSQL container
|
|
postgres-up:
|
|
docker compose -f docker-compose.test.yml up -d --wait
|
|
|
|
# Stop test PostgreSQL container
|
|
postgres-down:
|
|
docker compose -f docker-compose.test.yml down
|
|
|
|
# Run PostgreSQL integration tests (starts postgres automatically)
|
|
test-postgres: pricing-snapshot ensure-embed-dir postgres-up
|
|
@echo "Waiting for postgres to be ready..."
|
|
@sleep 2
|
|
TEST_PG_URL="postgres://agentsview_test:agentsview_test_password@localhost:5433/agentsview_test?sslmode=disable" \
|
|
CGO_ENABLED=1 go test -tags "fts5,pgtest" -v ./internal/postgres/... ./internal/activity/... -count=1
|
|
|
|
# PostgreSQL integration tests for CI (postgres already running as service)
|
|
test-postgres-ci: pricing-snapshot ensure-embed-dir
|
|
CGO_ENABLED=1 go test -tags "fts5,pgtest" -v ./internal/postgres/... ./internal/activity/... -count=1
|
|
|
|
# S3 discovery integration tests. testcontainers starts and tears down a
|
|
# rustfs (S3-compatible) container automatically, so only a working Docker
|
|
# daemon is required.
|
|
test-s3: pricing-snapshot ensure-embed-dir
|
|
CGO_ENABLED=1 go test -tags "fts5,s3test" -v ./internal/sync/... -run TestS3 -count=1
|
|
|
|
# Start test SSH container
|
|
ssh-up:
|
|
docker compose -f docker-compose.test.yml up -d --build --wait sshd
|
|
docker cp "$$(docker compose -f docker-compose.test.yml ps -q sshd)":/tmp/test_ssh_key testdata/ssh/test_key
|
|
chmod 600 testdata/ssh/test_key
|
|
|
|
# Stop test SSH container
|
|
ssh-down:
|
|
docker compose -f docker-compose.test.yml down sshd
|
|
|
|
# Run SSH integration tests (starts sshd automatically)
|
|
test-ssh: pricing-snapshot ensure-embed-dir ssh-up
|
|
TEST_SSH_HOST=localhost TEST_SSH_PORT=2222 TEST_SSH_USER=testuser \
|
|
TEST_SSH_KEY=$(CURDIR)/testdata/ssh/test_key \
|
|
CGO_ENABLED=1 go test -tags "fts5,sshtest" -v ./internal/ssh/... -count=1
|
|
|
|
# SSH integration tests for CI (sshd already running)
|
|
test-ssh-ci: pricing-snapshot ensure-embed-dir
|
|
CGO_ENABLED=1 go test -tags "fts5,sshtest" -v ./internal/ssh/... -count=1
|
|
|
|
# Run Playwright E2E tests
|
|
e2e:
|
|
cd frontend && npx playwright test
|
|
|
|
# Run focused Playwright smoke tests against duckdb serve.
|
|
e2e-duckdb:
|
|
cd frontend && AGENTSVIEW_E2E_BACKEND=duckdb npx playwright test \
|
|
e2e/duckdb-backend.spec.ts e2e/session-list.spec.ts --project=chromium
|
|
|
|
# Vet
|
|
vet: pricing-snapshot ensure-embed-dir
|
|
go vet -tags fts5 ./...
|
|
|
|
# Lint Go code and auto-fix where possible (local development)
|
|
lint: lint-golangci nilaway
|
|
|
|
# Run golangci-lint with auto-fixes for local development.
|
|
lint-golangci: pricing-snapshot ensure-embed-dir
|
|
@if ! command -v golangci-lint >/dev/null 2>&1; then \
|
|
echo "golangci-lint not found. Install with: make lint-tools" >&2; \
|
|
exit 1; \
|
|
fi
|
|
golangci-lint run --fix ./...
|
|
|
|
# Lint Go code without fixing (for CI)
|
|
lint-ci: lint-golangci-ci nilaway
|
|
|
|
# Run golangci-lint without auto-fixes for CI.
|
|
lint-golangci-ci: pricing-snapshot ensure-embed-dir
|
|
@if ! command -v golangci-lint >/dev/null 2>&1; then \
|
|
echo "golangci-lint not found. Install with: make lint-tools" >&2; \
|
|
exit 1; \
|
|
fi
|
|
golangci-lint run ./...
|
|
|
|
# Build a custom golangci-lint binary with the NilAway module plugin.
|
|
# Strip every repo-local Git env var (GIT_DIR, GIT_INDEX_FILE,
|
|
# GIT_CONFIG_PARAMETERS, etc.) and disable VCS stamping so the inner
|
|
# `git clone` and `go build` don't inherit the parent repo's state.
|
|
# When `make nilaway` runs from a pre-commit hook, git exports those
|
|
# vars pointing at the parent repo, which makes the clone and the
|
|
# VCS-stamped build fail with exit 128. The list comes from
|
|
# `git rev-parse --local-env-vars` so it tracks whatever Git considers
|
|
# repo-local at runtime.
|
|
nilaway-golangci-build:
|
|
@if ! command -v golangci-lint >/dev/null 2>&1; then \
|
|
echo "golangci-lint not found. Install with: make lint-tools" >&2; \
|
|
exit 1; \
|
|
fi
|
|
@unset_args=$$(git rev-parse --local-env-vars 2>/dev/null | sed 's/^/-u /' | tr '\n' ' '); \
|
|
env $$unset_args GOFLAGS=-buildvcs=false \
|
|
golangci-lint custom --version "$(GOLANGCI_LINT_VERSION)" --name custom-gcl
|
|
|
|
# Run NilAway through the custom golangci-lint module plugin.
|
|
nilaway: pricing-snapshot ensure-embed-dir nilaway-golangci-build
|
|
@set -e; \
|
|
root=$$(pwd); \
|
|
dirs=$$(go list -f '{{.Dir}}' ./...); \
|
|
for dir in $$dirs; do \
|
|
if [ "$$dir" = "$$root" ]; then \
|
|
pkg="."; \
|
|
else \
|
|
pkg="./$${dir#$$root/}"; \
|
|
fi; \
|
|
echo "$(CUSTOM_GCL) run --config .golangci.nilaway.yml $$pkg"; \
|
|
GOMAXPROCS=$${GOMAXPROCS:-1} GOGC=$${GOGC:-10} GOMEMLIMIT=$${GOMEMLIMIT:-512MiB} \
|
|
$(CUSTOM_GCL) run --config .golangci.nilaway.yml "$$pkg"; \
|
|
done
|
|
|
|
# Install pinned local lint tools.
|
|
lint-tools:
|
|
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
|
|
|
|
# Tidy dependencies
|
|
tidy: pricing-snapshot
|
|
go mod tidy
|
|
|
|
# Clean build artifacts
|
|
clean:
|
|
rm -f agentsview agentsv
|
|
rm -f $(PRICING_SNAPSHOT_FILE)
|
|
rm -rf internal/web/dist dist/ tmp/ $(SQLITE_INCLUDE_DIR)
|
|
mkdir -p internal/web/dist
|
|
printf '%s\n' \
|
|
'keep embed dir for generated frontend assets' \
|
|
> internal/web/dist/.keep
|
|
|
|
docs-install:
|
|
cd docs && uv sync --frozen --no-dev
|
|
|
|
docs-build:
|
|
cd docs && uv run --frozen bash ./vercel-build.sh
|
|
|
|
docs-serve:
|
|
cd docs && bash assets/hydrate-assets.sh && uv run bash ./zensical-docs.sh serve
|
|
|
|
docs-check:
|
|
bash scripts/check-docs.sh
|
|
|
|
docs-screenshots:
|
|
bash docs/screenshots/run.sh
|
|
|
|
docs-assets-branch:
|
|
bash docs/assets/update-static-assets-branch.sh
|
|
|
|
docs-generated-assets-branch:
|
|
bash docs/screenshots/update-generated-assets-branch.sh
|
|
|
|
docs-deploy-staging:
|
|
vercel deploy docs
|
|
|
|
docs-deploy:
|
|
vercel deploy docs --prod
|
|
|
|
# Build release binary for current platform (CGO required for sqlite3)
|
|
release: pricing-snapshot frontend
|
|
mkdir -p dist
|
|
CGO_ENABLED=1 go build -tags fts5 \
|
|
-ldflags="$(LDFLAGS_RELEASE)" -trimpath \
|
|
-o dist/agentsview-$$(go env GOOS)-$$(go env GOARCH) ./cmd/agentsview
|
|
|
|
# Cross-compile targets (require CC set to target cross-compiler)
|
|
release-darwin-arm64: pricing-snapshot frontend
|
|
mkdir -p dist
|
|
GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go build -tags fts5 \
|
|
-ldflags="$(LDFLAGS_RELEASE)" -trimpath \
|
|
-o dist/agentsview-darwin-arm64 ./cmd/agentsview
|
|
|
|
release-darwin-amd64: pricing-snapshot frontend
|
|
mkdir -p dist
|
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -tags fts5 \
|
|
-ldflags="$(LDFLAGS_RELEASE)" -trimpath \
|
|
-o dist/agentsview-darwin-amd64 ./cmd/agentsview
|
|
|
|
release-linux-amd64: pricing-snapshot frontend
|
|
mkdir -p dist
|
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags fts5 \
|
|
-ldflags="$(LDFLAGS_RELEASE)" -trimpath \
|
|
-o dist/agentsview-linux-amd64 ./cmd/agentsview
|
|
|
|
# Install pre-commit and pre-push hooks via prek
|
|
install-hooks:
|
|
@if ! command -v prek >/dev/null 2>&1; then \
|
|
echo "prek not found. Install with: brew install prek" >&2; \
|
|
exit 1; \
|
|
fi
|
|
prek install -f
|
|
|
|
# Show help
|
|
help:
|
|
@echo "agentsview build targets:"
|
|
@echo ""
|
|
@echo " build - Build with embedded frontend"
|
|
@echo " build-release - Release build (optimized, stripped)"
|
|
@echo " pricing-snapshot - Restore LiteLLM snapshot from artifact branch"
|
|
@echo " install - Build and install to ~/.local/bin or GOPATH"
|
|
@echo ""
|
|
@echo " dev - Run Go server with live reload via air (use with frontend-dev)"
|
|
@echo " dev-snapshot - Run agentsview against a fresh snapshot of prod sessions.db"
|
|
@echo " air-install - Install air for backend live reload"
|
|
@echo " frontend - Build frontend SPA"
|
|
@echo " frontend-dev - Run Vite+ dev server"
|
|
@echo " desktop-dev - Run Tauri desktop wrapper in dev mode"
|
|
@echo " desktop-build - Build Tauri desktop app bundles"
|
|
@echo " desktop-macos-app - Build macOS .app bundle only"
|
|
@echo " desktop-macos-dmg - Build macOS DMG installer"
|
|
@echo " desktop-windows-installer - Build Windows NSIS installer"
|
|
@echo " desktop-linux-appimage - Build Linux AppImage"
|
|
@echo " desktop-app - Alias for desktop-macos-app"
|
|
@echo ""
|
|
@echo " test - Run all tests"
|
|
@echo " test-short - Run fast tests only"
|
|
@echo " bench-backends - Benchmark SQLite, DuckDB, and PostgreSQL stores"
|
|
@echo " bench-gate - Run the hot-path benchmarks CI gates PRs on"
|
|
@echo " test-postgres - Run PostgreSQL integration tests"
|
|
@echo " test-s3 - Run S3 discovery integration tests (Docker)"
|
|
@echo " postgres-up - Start test PostgreSQL container"
|
|
@echo " postgres-down - Stop test PostgreSQL container"
|
|
@echo " test-ssh - Run SSH integration tests"
|
|
@echo " ssh-up - Start test SSH container"
|
|
@echo " ssh-down - Stop test SSH container"
|
|
@echo " e2e - Run Playwright E2E tests"
|
|
@echo " e2e-duckdb - Run DuckDB-backed Playwright smoke tests"
|
|
@echo " vet - Run go vet"
|
|
@echo " lint - Run golangci-lint and NilAway (auto-fix golangci issues)"
|
|
@echo " lint-ci - Run golangci-lint and NilAway (no fix, for CI)"
|
|
@echo " lint-golangci - Run golangci-lint with auto-fix"
|
|
@echo " nilaway - Run NilAway through custom golangci-lint"
|
|
@echo " lint-tools - Install pinned lint tools"
|
|
@echo " tidy - Tidy go.mod"
|
|
@echo ""
|
|
@echo " release - Release build for current platform"
|
|
@echo " clean - Remove build artifacts"
|
|
@echo " install-hooks - Install pre-commit and pre-push git hooks"
|