diff --git a/apps/web/src/i18n/locales/en.json b/apps/web/src/i18n/locales/en.json index f519883a..f34cea54 100644 --- a/apps/web/src/i18n/locales/en.json +++ b/apps/web/src/i18n/locales/en.json @@ -122,7 +122,10 @@ "themeLight": "Light", "themeDark": "Dark", "langZh": "中文", - "langEn": "English" + "langEn": "English", + "version": "Version", + "versionTag": "v{version}", + "commitHash": "Commit" }, "chat": { "greeting": "Hi! How can I help you today?", diff --git a/apps/web/src/i18n/locales/zh.json b/apps/web/src/i18n/locales/zh.json index eadc772d..f8b931e1 100644 --- a/apps/web/src/i18n/locales/zh.json +++ b/apps/web/src/i18n/locales/zh.json @@ -118,7 +118,10 @@ "themeLight": "浅色", "themeDark": "深色", "langZh": "中文", - "langEn": "English" + "langEn": "English", + "version": "版本", + "versionTag": "v{version}", + "commitHash": "提交" }, "chat": { "greeting": "你好!有什么我可以帮你的吗?", diff --git a/apps/web/src/pages/profile/index.vue b/apps/web/src/pages/profile/index.vue index 9eb2a86b..27166a54 100644 --- a/apps/web/src/pages/profile/index.vue +++ b/apps/web/src/pages/profile/index.vue @@ -1,5 +1,5 @@ @@ -215,6 +233,7 @@ import { useRouter } from 'vue-router' import { toast } from 'vue-sonner' import { useI18n } from 'vue-i18n' import { storeToRefs } from 'pinia' +import { Settings, Network } from 'lucide-vue-next' import ConfirmPopover from '@/components/confirm-popover/index.vue' import ProfileSection from './components/profile-section.vue' import PasswordSection from './components/password-section.vue' @@ -224,6 +243,7 @@ import { client } from '@memohai/sdk/client' import type { AccountsAccount, AccountsUpdateProfileRequest, AccountsUpdatePasswordRequest, IdentitiesChannelIdentity } from '@memohai/sdk' import { useUserStore } from '@/store/user' import { useSettingsStore } from '@/store/settings' +import { useCapabilitiesStore } from '@/store/capabilities' import type { Locale } from '@/i18n' import { resolveApiErrorMessage } from '@/utils/api-error' import { formatDateTime } from '@/utils/date-time' @@ -251,6 +271,10 @@ const settingsStore = useSettingsStore() const { language, theme } = storeToRefs(settingsStore) const { setLanguage, setTheme } = settingsStore +// ---- Server version ---- +const capabilitiesStore = useCapabilitiesStore() +const { serverVersion, commitHash } = storeToRefs(capabilitiesStore) + // ---- User data ---- const account = ref(null) const identities = ref([]) diff --git a/apps/web/src/store/capabilities.ts b/apps/web/src/store/capabilities.ts index 03dfd4f3..803665ea 100644 --- a/apps/web/src/store/capabilities.ts +++ b/apps/web/src/store/capabilities.ts @@ -5,6 +5,8 @@ import { getPing } from '@memohai/sdk' export const useCapabilitiesStore = defineStore('capabilities', () => { const containerBackend = ref('containerd') const snapshotSupported = ref(true) + const serverVersion = ref('') + const commitHash = ref('') const loaded = ref(false) async function load() { @@ -14,6 +16,8 @@ export const useCapabilitiesStore = defineStore('capabilities', () => { if (data) { containerBackend.value = data.container_backend ?? 'containerd' snapshotSupported.value = data.snapshot_supported !== false + serverVersion.value = data.version ?? '' + commitHash.value = data.commit_hash ?? '' } } catch { // fallback: assume containerd @@ -21,5 +25,5 @@ export const useCapabilitiesStore = defineStore('capabilities', () => { loaded.value = true } - return { containerBackend, snapshotSupported, loaded, load } + return { containerBackend, snapshotSupported, serverVersion, commitHash, loaded, load } }) diff --git a/internal/handlers/ping.go b/internal/handlers/ping.go index 6d6eab88..eeb4483f 100644 --- a/internal/handlers/ping.go +++ b/internal/handlers/ping.go @@ -7,12 +7,15 @@ import ( "github.com/labstack/echo/v4" "github.com/memohai/memoh/internal/boot" + "github.com/memohai/memoh/internal/version" ) type PingResponse struct { Status string `json:"status"` ContainerBackend string `json:"container_backend"` SnapshotSupported bool `json:"snapshot_supported"` + Version string `json:"version"` + CommitHash string `json:"commit_hash"` } type PingHandler struct { @@ -42,6 +45,8 @@ func (h *PingHandler) Ping(c echo.Context) error { Status: "ok", ContainerBackend: h.runtime.ContainerBackend, SnapshotSupported: h.runtime.ContainerBackend != "apple", + Version: version.Version, + CommitHash: version.ShortCommitHash(), }) } diff --git a/internal/version/version.go b/internal/version/version.go index d1d9857e..e8a4cc76 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -17,8 +17,9 @@ var ( BuildTime = "" ) -// GetInfo returns a formatted version string including the version and commit hash. -func GetInfo() string { +// EnsureBuildInfo populates CommitHash and BuildTime from Go build info +// when they were not set via ldflags. +func EnsureBuildInfo() { if CommitHash == "" { if info, ok := debug.ReadBuildInfo(); ok { for _, setting := range info.Settings { @@ -31,15 +32,23 @@ func GetInfo() string { } } } +} +// ShortCommitHash returns the first 7 characters of the commit hash. +func ShortCommitHash() string { + EnsureBuildInfo() + if len(CommitHash) > 7 { + return CommitHash[:7] + } + return CommitHash +} + +// GetInfo returns a formatted version string including the version and commit hash. +func GetInfo() string { + EnsureBuildInfo() res := Version - if CommitHash != "" { - // Only use the first 7 characters of the commit hash if it's long - shortHash := CommitHash - if len(shortHash) > 7 { - shortHash = shortHash[:7] - } - res += fmt.Sprintf(" (%s)", shortHash) + if h := ShortCommitHash(); h != "" { + res += fmt.Sprintf(" (%s)", h) } return res } diff --git a/packages/sdk/src/types.gen.ts b/packages/sdk/src/types.gen.ts index dab1506e..3b4dec6e 100644 --- a/packages/sdk/src/types.gen.ts +++ b/packages/sdk/src/types.gen.ts @@ -878,9 +878,11 @@ export type HandlersModelTokenUsage = { }; export type HandlersPingResponse = { + commit_hash?: string; container_backend?: string; snapshot_supported?: boolean; status?: string; + version?: string; }; export type HandlersProbeResponse = { diff --git a/spec/docs.go b/spec/docs.go index d42d1795..3469a39b 100644 --- a/spec/docs.go +++ b/spec/docs.go @@ -10960,6 +10960,9 @@ const docTemplate = `{ "handlers.PingResponse": { "type": "object", "properties": { + "commit_hash": { + "type": "string" + }, "container_backend": { "type": "string" }, @@ -10968,6 +10971,9 @@ const docTemplate = `{ }, "status": { "type": "string" + }, + "version": { + "type": "string" } } }, diff --git a/spec/swagger.json b/spec/swagger.json index ffc17786..7bd8f7b2 100644 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -10951,6 +10951,9 @@ "handlers.PingResponse": { "type": "object", "properties": { + "commit_hash": { + "type": "string" + }, "container_backend": { "type": "string" }, @@ -10959,6 +10962,9 @@ }, "status": { "type": "string" + }, + "version": { + "type": "string" } } }, diff --git a/spec/swagger.yaml b/spec/swagger.yaml index 9b8c4b72..1b7607fb 100644 --- a/spec/swagger.yaml +++ b/spec/swagger.yaml @@ -1445,12 +1445,16 @@ definitions: type: object handlers.PingResponse: properties: + commit_hash: + type: string container_backend: type: string snapshot_supported: type: boolean status: type: string + version: + type: string type: object handlers.ProbeResponse: properties: