# Claude Mnemonic Makefile VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") # Pass version to both main package and hooks package LDFLAGS := -ldflags "-X main.Version=$(VERSION) -X github.com/lukaszraczylo/claude-mnemonic/pkg/hooks.Version=$(VERSION) -s -w" -buildvcs=false BUILD_DIR := bin PLUGIN_DIR := plugin STABLE_BIN := $(HOME)/.claude-mnemonic/bin # Go settings GOOS ?= $(shell go env GOOS) GOARCH ?= $(shell go env GOARCH) # CGO settings for SQLite FTS5 support export CGO_ENABLED=1 BUILD_TAGS := -tags "fts5" .PHONY: all build clean test install lint hooks worker mcp stop-worker start-worker restart-worker dashboard website dev-website setup-libs update-version all: build # Download ONNX runtime libraries (all platforms for local dev, skips if present) setup-libs: @./scripts/download-onnx-libs.sh all # Download ONNX models from Hugging Face (for local dev, skips if present) setup-models: @./scripts/download-models.sh # Update version in committed plugin metadata update-version: @if [ -f .claude-plugin/plugin.json ]; then \ sed 's/"version": "[^"]*"/"version": "$(VERSION)"/' .claude-plugin/plugin.json > .claude-plugin/plugin.json.tmp && mv .claude-plugin/plugin.json.tmp .claude-plugin/plugin.json; \ echo "Updated .claude-plugin/plugin.json to version $(VERSION)"; \ fi @if [ -f marketplace.json ]; then \ sed 's/"version": "[^"]*"/"version": "$(VERSION)"/' marketplace.json > marketplace.json.tmp && mv marketplace.json.tmp marketplace.json; \ echo "Updated marketplace.json version fields to $(VERSION)"; \ fi # Build all binaries build: setup-libs update-version dashboard worker hooks mcp # Build Vue dashboard dashboard: @echo "Building Vue dashboard..." @sed 's/{{ .Version }}/$(VERSION)/g' ui/package.json.tpl > ui/package.json @cd ui && npm install --silent && npm run build @rm -rf internal/worker/static @mkdir -p internal/worker/static @touch internal/worker/static/placeholder.html @cp -r ui/dist/* internal/worker/static/ # Build worker service worker: @echo "Building worker..." @mkdir -p $(BUILD_DIR) go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/worker ./cmd/worker # Build all hooks hooks: @echo "Building hooks..." @mkdir -p $(BUILD_DIR)/hooks go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/session-start ./cmd/hooks/session-start go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/user-prompt ./cmd/hooks/user-prompt go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/post-tool-use ./cmd/hooks/post-tool-use go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/subagent-stop ./cmd/hooks/subagent-stop go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/stop ./cmd/hooks/stop go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/hooks/statusline ./cmd/hooks/statusline # Build MCP server mcp: @echo "Building MCP server..." @mkdir -p $(BUILD_DIR) go build $(BUILD_TAGS) $(LDFLAGS) -o $(BUILD_DIR)/mcp-server ./cmd/mcp # Build for all platforms build-all: build-linux build-darwin build-windows build-linux: @echo "Building for Linux..." @mkdir -p $(BUILD_DIR)/linux-amd64/hooks GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/worker ./cmd/worker GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/mcp-server ./cmd/mcp GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/session-start ./cmd/hooks/session-start GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/user-prompt ./cmd/hooks/user-prompt GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/post-tool-use ./cmd/hooks/post-tool-use GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/subagent-stop ./cmd/hooks/subagent-stop GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/stop ./cmd/hooks/stop GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/linux-amd64/hooks/statusline ./cmd/hooks/statusline build-darwin: @echo "Building for macOS..." @mkdir -p $(BUILD_DIR)/darwin-amd64/hooks $(BUILD_DIR)/darwin-arm64/hooks GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/worker ./cmd/worker GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/worker ./cmd/worker GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/mcp-server ./cmd/mcp GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/mcp-server ./cmd/mcp GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/session-start ./cmd/hooks/session-start GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/session-start ./cmd/hooks/session-start GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/user-prompt ./cmd/hooks/user-prompt GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/user-prompt ./cmd/hooks/user-prompt GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/post-tool-use ./cmd/hooks/post-tool-use GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/post-tool-use ./cmd/hooks/post-tool-use GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/subagent-stop ./cmd/hooks/subagent-stop GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/subagent-stop ./cmd/hooks/subagent-stop GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/stop ./cmd/hooks/stop GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/stop ./cmd/hooks/stop GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-amd64/hooks/statusline ./cmd/hooks/statusline GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BUILD_DIR)/darwin-arm64/hooks/statusline ./cmd/hooks/statusline build-windows: @echo "Building for Windows..." @mkdir -p $(BUILD_DIR)/windows-amd64/hooks GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/worker.exe ./cmd/worker GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/mcp-server.exe ./cmd/mcp GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/session-start.exe ./cmd/hooks/session-start GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/user-prompt.exe ./cmd/hooks/user-prompt GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/post-tool-use.exe ./cmd/hooks/post-tool-use GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/subagent-stop.exe ./cmd/hooks/subagent-stop GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/stop.exe ./cmd/hooks/stop GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BUILD_DIR)/windows-amd64/hooks/statusline.exe ./cmd/hooks/statusline # Stop any running worker stop-worker: @echo "Stopping worker..." @-pkill -TERM -f 'claude-mnemonic.*worker' 2>/dev/null || true @-pkill -TERM -f '\.claude-mnemonic/bin/worker' 2>/dev/null || true @-pkill -TERM -f '\.claude/plugins/.*/worker' 2>/dev/null || true @sleep 1 @-pkill -9 -f 'claude-mnemonic.*worker' 2>/dev/null || true @-pkill -9 -f '\.claude-mnemonic/bin/worker' 2>/dev/null || true @-pkill -9 -f '\.claude/plugins/.*/worker' 2>/dev/null || true @-lsof -ti :37777 | xargs kill -9 2>/dev/null || true @sleep 1 # Start worker in background start-worker: @echo "Starting worker..." @nohup $(STABLE_BIN)/worker > /tmp/claude-mnemonic-worker.log 2>&1 & @sleep 1 @if curl -s http://localhost:37777/health > /dev/null 2>&1; then \ echo "Worker started successfully (http://localhost:37777)"; \ else \ echo "Warning: Worker may not have started. Check /tmp/claude-mnemonic-worker.log"; \ fi # Restart worker restart-worker: stop-worker start-worker # Install to stable binary location and register with Claude Code install: build stop-worker @echo "Installing claude-mnemonic..." @# Verify build output binaries exist @test -f $(BUILD_DIR)/worker || { echo "ERROR: $(BUILD_DIR)/worker not found. Build may have failed."; exit 1; } @test -f $(BUILD_DIR)/mcp-server || { echo "ERROR: $(BUILD_DIR)/mcp-server not found. Build may have failed."; exit 1; } @test -d $(BUILD_DIR)/hooks || { echo "ERROR: $(BUILD_DIR)/hooks not found. Build may have failed."; exit 1; } @# Install binaries to stable location (survives Claude Code updates) @mkdir -p $(STABLE_BIN)/hooks cp $(BUILD_DIR)/worker $(STABLE_BIN)/ cp $(BUILD_DIR)/mcp-server $(STABLE_BIN)/ cp $(BUILD_DIR)/hooks/* $(STABLE_BIN)/hooks/ @echo "Binaries installed to $(STABLE_BIN)" @# Set up marketplace directory with wrapper scripts and metadata @mkdir -p $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/.claude-plugin @mkdir -p $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/hooks @mkdir -p $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/commands @cp .claude-plugin/plugin.json $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/.claude-plugin/ @cp marketplace.json $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/.claude-plugin/marketplace.json 2>/dev/null || true @cp hooks/hooks.json $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/hooks/ @cp hooks/session-start hooks/user-prompt hooks/post-tool-use hooks/stop hooks/subagent-stop hooks/statusline $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/hooks/ @chmod +x $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/hooks/* @cp mcp-server $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/ @chmod +x $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/mcp-server @cp commands/restart.md $(HOME)/.claude/plugins/marketplaces/claude-mnemonic/commands/ @echo "Registering plugin with Claude Code..." @./scripts/register-plugin.sh "$(VERSION)" @$(MAKE) start-worker @echo "Installation complete!" # Uninstall uninstall: stop-worker @echo "Uninstalling..." @./scripts/unregister-plugin.sh rm -rf $(HOME)/.claude/plugins/marketplaces/claude-mnemonic @echo "Uninstallation complete!" # Run tests (with FTS5 support) # CLAUDE_MNEMONIC_MODEL_DIR points to a common model directory for tests. # Run setup-models first to download models from Hugging Face. test: setup-libs setup-models CLAUDE_MNEMONIC_MODEL_DIR=$$(pwd)/testdata/models go test $(BUILD_TAGS) -v -race ./... # Run tests with coverage (with FTS5 support) test-coverage: setup-libs setup-models CLAUDE_MNEMONIC_MODEL_DIR=$$(pwd)/testdata/models go test $(BUILD_TAGS) -v -race -coverprofile=coverage.out ./... go tool cover -html=coverage.out -o coverage.html @go tool cover -func=coverage.out | tail -1 # Run benchmarks bench: go test -bench=. -benchmem ./... # Run linter lint: golangci-lint run ./... # Format code fmt: go fmt ./... # Clean build artifacts clean: rm -rf $(BUILD_DIR) rm -f coverage.out coverage.html # Run worker in development mode dev: worker ./$(BUILD_DIR)/worker # Download dependencies deps: go mod download go mod tidy # Build website for production website: @echo "Building website..." @cd docs && npm install --silent && npm run build @echo "Website built to docs/dist/" # Run website in development mode dev-website: @echo "Starting website dev server..." @cd docs && npm install --silent && npm run dev # Show help help: @echo "Claude Mnemonic Build System" @echo "" @echo "Usage:" @echo " make build - Build all binaries" @echo " make worker - Build worker service only" @echo " make mcp - Build MCP server only" @echo " make hooks - Build hooks only" @echo " make build-all - Build for all platforms" @echo " make install - Install to Claude plugins directory (restarts worker)" @echo " make uninstall - Remove from Claude plugins directory" @echo " make stop-worker - Stop the running worker" @echo " make start-worker - Start the worker in background" @echo " make restart-worker - Restart the worker" @echo " make test - Run tests" @echo " make bench - Run benchmarks" @echo " make lint - Run linter" @echo " make fmt - Format code" @echo " make clean - Clean build artifacts" @echo " make dev - Run worker in development mode" @echo " make update-version - Update version in plugin metadata files" @echo " make deps - Download dependencies" @echo " make website - Build website for production" @echo " make dev-website - Run website dev server" @echo "" @echo "Variables:" @echo " VERSION=$(VERSION)" @echo " GOOS=$(GOOS)" @echo " GOARCH=$(GOARCH)"