diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 03fe435..3da0edf 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,6 +29,8 @@ jobs: npm ci - name: Build Web UI + env: + VITE_APP_VERSION: ${{ github.ref_name }} run: | cd webui npm run build diff --git a/cmd/server/main.go b/cmd/server/main.go index 6ede011..7433c78 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -11,6 +11,11 @@ import ( "syscall" ) +// version is set at build time using -ldflags "-X main.version=1.0.0" +var version string = "unknown" +var commitHash string = "unknown" +var buildTime string = "unknown" + // @title llamactl API // @version 1.0 // @description llamactl is a control server for managing Llama Server instances. @@ -19,6 +24,14 @@ import ( // @basePath /api/v1 func main() { + // --version flag to print the version + if len(os.Args) > 1 && os.Args[1] == "--version" { + fmt.Printf("llamactl version: %s\n", version) + fmt.Printf("Commit hash: %s\n", commitHash) + fmt.Printf("Build time: %s\n", buildTime) + return + } + configPath := os.Getenv("LLAMACTL_CONFIG_PATH") cfg, err := config.LoadConfig(configPath) if err != nil { @@ -26,6 +39,11 @@ func main() { fmt.Println("Using default configuration.") } + // Set version information + cfg.Version = version + cfg.CommitHash = commitHash + cfg.BuildTime = buildTime + // Create the data directory if it doesn't exist if cfg.Instances.AutoCreateDirs { if err := os.MkdirAll(cfg.Instances.InstancesDir, 0755); err != nil { diff --git a/pkg/config/config.go b/pkg/config/config.go index dac781c..fd33715 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -12,9 +12,12 @@ import ( // AppConfig represents the configuration for llamactl type AppConfig struct { - Server ServerConfig `yaml:"server"` - Instances InstancesConfig `yaml:"instances"` - Auth AuthConfig `yaml:"auth"` + Server ServerConfig `yaml:"server"` + Instances InstancesConfig `yaml:"instances"` + Auth AuthConfig `yaml:"auth"` + Version string `yaml:"-"` + CommitHash string `yaml:"-"` + BuildTime string `yaml:"-"` } // ServerConfig contains HTTP server configuration diff --git a/pkg/server/handlers.go b/pkg/server/handlers.go index 9eeb2a2..a5147e5 100644 --- a/pkg/server/handlers.go +++ b/pkg/server/handlers.go @@ -28,7 +28,23 @@ func NewHandler(im manager.InstanceManager, cfg config.AppConfig) *Handler { } } -// HelpHandler godoc +// VersionHandler godoc +// @Summary Get llamactl version +// @Description Returns the version of the llamactl command +// @Tags version +// @Security ApiKeyAuth +// @Produces text/plain +// @Success 200 {string} string "Version information" +// @Failure 500 {string} string "Internal Server Error" +// @Router /version [get] +func (h *Handler) VersionHandler() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + fmt.Fprintf(w, "Version: %s\nCommit: %s\nBuild Time: %s\n", h.cfg.Version, h.cfg.CommitHash, h.cfg.BuildTime) + } +} + +// LlamaServerHelpHandler godoc // @Summary Get help for llama server // @Description Returns the help text for the llama server command // @Tags server @@ -37,7 +53,7 @@ func NewHandler(im manager.InstanceManager, cfg config.AppConfig) *Handler { // @Success 200 {string} string "Help text" // @Failure 500 {string} string "Internal Server Error" // @Router /server/help [get] -func (h *Handler) HelpHandler() http.HandlerFunc { +func (h *Handler) LlamaServerHelpHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { helpCmd := exec.Command("llama-server", "--help") output, err := helpCmd.CombinedOutput() @@ -50,7 +66,7 @@ func (h *Handler) HelpHandler() http.HandlerFunc { } } -// VersionHandler godoc +// LlamaServerVersionHandler godoc // @Summary Get version of llama server // @Description Returns the version of the llama server command // @Tags server @@ -59,7 +75,7 @@ func (h *Handler) HelpHandler() http.HandlerFunc { // @Success 200 {string} string "Version information" // @Failure 500 {string} string "Internal Server Error" // @Router /server/version [get] -func (h *Handler) VersionHandler() http.HandlerFunc { +func (h *Handler) LlamaServerVersionHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { versionCmd := exec.Command("llama-server", "--version") output, err := versionCmd.CombinedOutput() @@ -72,7 +88,7 @@ func (h *Handler) VersionHandler() http.HandlerFunc { } } -// ListDevicesHandler godoc +// LlamaServerListDevicesHandler godoc // @Summary List available devices for llama server // @Description Returns a list of available devices for the llama server // @Tags server @@ -81,7 +97,7 @@ func (h *Handler) VersionHandler() http.HandlerFunc { // @Success 200 {string} string "List of devices" // @Failure 500 {string} string "Internal Server Error" // @Router /server/devices [get] -func (h *Handler) ListDevicesHandler() http.HandlerFunc { +func (h *Handler) LlamaServerListDevicesHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { listCmd := exec.Command("llama-server", "--list-devices") output, err := listCmd.CombinedOutput() diff --git a/pkg/server/routes.go b/pkg/server/routes.go index b400742..a867131 100644 --- a/pkg/server/routes.go +++ b/pkg/server/routes.go @@ -42,10 +42,12 @@ func SetupRouter(handler *Handler) *chi.Mux { r.Use(authMiddleware.AuthMiddleware(KeyTypeManagement)) } + r.Get("/version", handler.VersionHandler()) // Get server version + r.Route("/server", func(r chi.Router) { - r.Get("/help", handler.HelpHandler()) - r.Get("/version", handler.VersionHandler()) - r.Get("/devices", handler.ListDevicesHandler()) + r.Get("/help", handler.LlamaServerHelpHandler()) + r.Get("/version", handler.LlamaServerVersionHandler()) + r.Get("/devices", handler.LlamaServerListDevicesHandler()) }) // Instance management endpoints diff --git a/webui/src/components/SystemInfoDialog.tsx b/webui/src/components/SystemInfoDialog.tsx index 2b24a0a..8eb03f5 100644 --- a/webui/src/components/SystemInfoDialog.tsx +++ b/webui/src/components/SystemInfoDialog.tsx @@ -19,6 +19,15 @@ import { } from 'lucide-react' import { serverApi } from '@/lib/api' +// Helper to get version from environment +const getAppVersion = (): string => { + try { + return (import.meta.env as Record).VITE_APP_VERSION || 'unknown' + } catch { + return 'unknown' + } +} + interface SystemInfoModalProps { open: boolean onOpenChange: (open: boolean) => void @@ -109,9 +118,20 @@ const SystemInfoDialog: React.FC = ({ ) : systemInfo ? (
- {/* Version Section */} + {/* Llamactl Version Section */}
-

Version

+

Llamactl Version

+ +
+
+                    {getAppVersion()}
+                  
+
+
+ + {/* Llama Server Version Section */} +
+

Llama Server Version

diff --git a/webui/src/vite-env.d.ts b/webui/src/vite-env.d.ts new file mode 100644 index 0000000..3a1fe33 --- /dev/null +++ b/webui/src/vite-env.d.ts @@ -0,0 +1,13 @@ +/// + +declare global { + interface ImportMetaEnv { + readonly VITE_APP_VERSION?: string + } + + interface ImportMeta { + readonly env: ImportMetaEnv + } +} + +export {} diff --git a/webui/tsconfig.json b/webui/tsconfig.json index c20738e..2eed951 100644 --- a/webui/tsconfig.json +++ b/webui/tsconfig.json @@ -18,8 +18,9 @@ "baseUrl": ".", "paths": { "@/*": ["./src/*"] - } + }, + "types": ["vite/client"] }, - "include": ["src"], + "include": ["src", "src/vite-env.d.ts"], "references": [{ "path": "./tsconfig.node.json" }] }