chore(version): 客户端版本与内核对齐(唯一事实源 internal/meta.Version)

此前三份版本号互不相干:内核 1.4.0、GUI 1.0.0、鸿蒙 1.1.1。手工各改各的
必然漂移,所以把「对齐」做成机械动作而不是约定:

- deploy/scripts/sync-client-versions.sh:从 internal/meta.Version 读版本,
  同步 cmd/gui/package.json 与鸿蒙 AppScope/app.json5(versionName +
  versionCode=X*1e6+Y*1e3+Z);--check 给 CI/Makefile 做漂移门禁。
- Makefile 新增 sync-client-versions / check-client-versions;build-cli 也注入
  LDFLAGS,waiter 与 homed 同版本。
- 鸿蒙:新增 common/AppVersion.ets,从 bundleManager 读安装包 versionName,
  BridgeProtocol/BridgeCaps 里两处硬编码 '1.1.1' 改为读它——版本只剩
  app.json5 一份,杜绝第二真相。
- waiter:`-version` 打印版本,启动横幅与设备桥 hello 的 version 字段
  直接引用 internal/meta,与内核天然同源。

对齐后:GUI 1.4.0 / 鸿蒙 1.4.0(1004000) / waiter 1.4.0 / 内核 1.4.0。
This commit is contained in:
JianFeeeee
2026-09-15 11:03:26 +08:00
parent a9ad97240b
commit 065732f42e
9 changed files with 156 additions and 10 deletions

View File

@ -1,4 +1,4 @@
.PHONY: all build build-plain build-cli build-gui clean install test run build-static build-linux-arm64 lint fmt
.PHONY: all build build-plain build-cli build-gui clean install test run build-static build-linux-arm64 lint fmt sync-client-versions check-client-versions
# HOMED_TAGS 默认带 onnxruntime发行版**默认启用**本地向量空间(与
# deploy/packaging/build.sh 保持一致)。
@ -37,8 +37,8 @@ build:
build-cli:
@mkdir -p $(BUILD_DIR)
CGO_ENABLED=0 $(GO) build -installsuffix dynlink -o $(BUILD_DIR)/$(CLI_BINARY) ./cmd/waiter/
@echo "Built: $(BUILD_DIR)/$(CLI_BINARY)"
CGO_ENABLED=0 $(GO) build -installsuffix dynlink -ldflags '$(LDFLAGS)' -o $(BUILD_DIR)/$(CLI_BINARY) ./cmd/waiter/
@echo "Built: $(BUILD_DIR)/$(CLI_BINARY) ($(VERSION))"
build-gui:
@cd cmd/gui && npm install --production && npx electron-packager . $(GUI_BINARY) --out=../../$(BUILD_DIR) --overwrite --no-sandbox
@ -77,6 +77,14 @@ fmt:
lint:
$(GO) vet ./...
# 客户端版本与内核版本同步(唯一事实源 internal/meta.Version
# GUI/鸿蒙各有自版本字段手工改必漂——用脚本拉齐check 版给门禁用。
sync-client-versions:
@bash deploy/scripts/sync-client-versions.sh
check-client-versions:
@bash deploy/scripts/sync-client-versions.sh --check
# lint-full在 vet 之外跑 golangci-lint阈值见 .golangci.yml起步 warn-only
# 未安装时给出可执行的安装提示与跳过原因,而不是静默成功。
.PHONY: lint-full

View File

@ -1,6 +1,6 @@
{
"name": "homeagent-gui",
"version": "1.0.0",
"version": "1.4.0",
"author": "JianFeeeee <jianfeeeee@homeagent.local>",
"homepage": "https://gitcode.com/JianFeeeee/HomeAgent",
"description": "HomeAgent Desktop GUI - Multi-connection management dashboard",

View File

@ -2,8 +2,8 @@
"app": {
"bundleName": "com.example.homeagent",
"vendor": "HomeAgent",
"versionCode": 1001001,
"versionName": "1.1.1",
"versionCode": 1004000,
"versionName": "1.4.0",
// 分层图标:前景是字形,背景(沉淀色)在 base/ 与 dark/ 各一份,随系统主题切换。
// 直接指向位图会把浅色底烧进图标,深色模式下桌面和启动页都会跳脱。
"icon": "$media:layered_image",

View File

@ -0,0 +1,19 @@
import { bundleManager } from '@kit.AbilityKit';
/**
* 应用版本号:从 bundle 元数据读取,而不是在 .ets 里再抄一份。
*
* AppScope/app.json5 是版本的唯一来源(由 deploy/scripts/sync-client-versions.sh
* 与内核 internal/meta.Version 对齐)。在代码里再写一个字面量就是第二份真相,
* 实测已经漂过app.json5 写 1.1.1、设备桥上又是一份 1.1.1,而内核早已 1.4.0。
* 设备桥上报 / deviceinfo 回显的真实安装包版本,应当来自同一个来源。
*/
export function appVersion(): string {
try {
const info: bundleManager.BundleInfo =
bundleManager.getBundleInfoForSelfSync(bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT);
return info.versionName;
} catch (e) {
return '';
}
}

View File

@ -5,6 +5,7 @@ import { deviceInfo } from '@kit.BasicServicesKit';
import { textToSpeech } from '@kit.CoreSpeechKit';
import { componentSnapshot } from '@kit.ArkUI';
import { abilityAccessCtrl, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
import { appVersion } from './AppVersion';
// ===== 能力结果 =====
@ -249,7 +250,7 @@ export function capDeviceInfo(deviceId: string, deviceName: string): CapResult {
platform: 'OpenHarmony',
arch: deviceInfo.abiList,
os_release: deviceInfo.osFullName,
version: '1.1.1',
version: appVersion(),
cpus: 0,
brand: deviceInfo.brand,
manufacturer: deviceInfo.manufacture,

View File

@ -10,6 +10,7 @@
*/
import { CapResult } from './BridgeCaps';
import { appVersion } from './AppVersion';
// ===== 协议消息(与 remotedevice 插件对齐)=====
@ -83,7 +84,7 @@ export function bridgeHelloFrame(deviceId: string, name: string, kind: string,
platform: 'OpenHarmony',
arch: '',
os_release: '',
version: '1.1.1',
version: appVersion(),
cpus: 0,
};
const device: HelloDevice = {

View File

@ -15,6 +15,7 @@ import (
"time"
"gitcode.com/JianFeeeee/HomeAgent/internal/devicebridge/client"
"gitcode.com/JianFeeeee/HomeAgent/internal/meta"
)
// ===== 设备桥管理 =====
@ -46,6 +47,9 @@ func startDeviceBridge(addr, token string) error {
"platform": runtime.GOOS,
"arch": runtime.GOARCH,
"cpus": runtime.NumCPU(),
// 客户端版本与内核同源internal/metadeviceinfo 回显的软件版本
// 因此与 homed 一致,不再是一个空缺字段。
"version": meta.Version,
}
// 确保 gateway URL 格式正确

View File

@ -11,6 +11,8 @@ import (
"sync"
"syscall"
"time"
"gitcode.com/JianFeeeee/HomeAgent/internal/meta"
)
const (
@ -129,8 +131,15 @@ func main() {
daemonMode := flag.Bool("daemon", false, "后台驻留模式:维持 homed 连接 + 设备桥,等待 TUI 实例接入")
testCap := flag.String("test-cap", "", "测试本地能力screensue/speakeruse/screensee/clipboardsee/clipboardsue/computeruse/camerasue如 --test-cap screensue")
testCapArgs := flag.String("test-cap-args", "", "测试能力的参数")
showVersion := flag.Bool("version", false, "打印版本并退出")
flag.Parse()
// 版本号直接来自 internal/meta与 homed 同一事实源,不可能各写一个)。
if *showVersion {
fmt.Printf("waiter %s (commit %s, built %s)\n", meta.Version, meta.Commit, meta.BuildTime)
return
}
// 本地能力测试模式(无需连接服务器)
if *testCap != "" {
runCapTest(*testCap, *testCapArgs)
@ -270,9 +279,9 @@ func runLineMode(state *State, cfg *Config, history *History) {
addrLabel = cfg.Remote
}
if colors {
fmt.Printf("%sHomeAgent CLI%s %s(%s://%s)%s\n", colorBold, colorReset, colorDim, modeLabel, addrLabel, colorReset)
fmt.Printf("%sHomeAgent CLI%s %s%s (%s://%s)%s\n", colorBold, colorReset, colorDim, "v"+meta.Version, modeLabel, addrLabel, colorReset)
} else {
fmt.Printf("HomeAgent CLI (%s://%s)\n", modeLabel, addrLabel)
fmt.Printf("HomeAgent CLI v%s (%s://%s)\n", meta.Version, modeLabel, addrLabel)
}
fmt.Println("Type /help for commands.")

View File

@ -0,0 +1,104 @@
#!/usr/bin/env bash
#
# 客户端版本与内核版本同步。
#
# 为什么要有这个脚本:内核的 internal/meta/meta.go Version 是唯一事实源,
# 而各客户端各有各的版本字段——GUI 在 package.json、鸿蒙在 AppScope/app.json5、
# waiter 走编译期注入。手工各改各的必然漂移(写这个脚本时的现状:内核 1.4.0、
# GUI 1.0.0、鸿蒙 1.1.1,三个号互不相干)。
#
# 用法:
# bash deploy/scripts/sync-client-versions.sh # 同步到内核当前版本
# bash deploy/scripts/sync-client-versions.sh 1.4.0 # 同步到指定版本
# bash deploy/scripts/sync-client-versions.sh --check # 只校验,漂移则退出 1
#
# 同步目标:
# cmd/gui/package.json version
# cmd/ohos/HomeAgent/AppScope/app.json5 versionName + versionCode
#
# waiter 不在此列:它直接引用 internal/meta.Version同一进程内编译
# 没有第二份版本字段可漂。
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
CHECK=0
VERSION=""
for arg in "$@"; do
case "$arg" in
--check) CHECK=1 ;;
*) VERSION="$arg" ;;
esac
done
# 未显式给版本时,从内核唯一事实源读。
if [ -z "$VERSION" ]; then
VERSION="$(grep -oE 'Version = "[^"]+"' "$ROOT/internal/meta/meta.go" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')"
fi
[ -n "$VERSION" ] || { echo "sync-client-versions: 无法确定版本号internal/meta/meta.go 里没找到 Version" >&2; exit 1; }
# versionCode 规则X*1e6 + Y*1e3 + Z。鸿蒙要求 versionCode 单调递增的整数,
# 直接搬 semver 会丢信息,所以用主/次/补丁三段编码1.4.0 → 1004000
CODE="$(python3 - "$VERSION" <<'PY'
import re, sys
m = re.match(r'^(\d+)\.(\d+)\.(\d+)', sys.argv[1])
if not m:
sys.exit("sync-client-versions: 版本号必须是 X.Y.Z 形态,得到 %r" % sys.argv[1])
print(int(m.group(1)) * 1000000 + int(m.group(2)) * 1000 + int(m.group(3)))
PY
)"
GUI_PKG="$ROOT/cmd/gui/package.json"
OHOS_APP="$ROOT/cmd/ohos/HomeAgent/AppScope/app.json5"
DRIFT=0
note() { printf ' %-52s %s\n' "$1" "$2"; }
# ── GUI ──
gui_cur="$(python3 - "$GUI_PKG" <<'PY'
import json, sys
print(json.load(open(sys.argv[1]))["version"])
PY
)"
if [ "$gui_cur" != "$VERSION" ]; then
DRIFT=1
if [ "$CHECK" -eq 1 ]; then
note "cmd/gui/package.json" "$gui_cur → 应为 $VERSION"
else
python3 - "$GUI_PKG" "$VERSION" <<'PY'
import json, sys
p, v = sys.argv[1], sys.argv[2]
d = json.load(open(p))
d["version"] = v
# indent=2 保留原格式;末尾补换行,避免 diff 噪声
with open(p, "w") as f:
json.dump(d, f, indent=2, ensure_ascii=False)
f.write("\n")
PY
note "cmd/gui/package.json" "$gui_cur$VERSION"
fi
fi
# ── 鸿蒙 ──
ohos_name="$(grep -oE '"versionName"[[:space:]]*:[[:space:]]*"[^"]+"' "$OHOS_APP" | head -1 | sed -E 's/.*"([^"]+)"$/\1/')"
ohos_code="$(grep -oE '"versionCode"[[:space:]]*:[[:space:]]*[0-9]+' "$OHOS_APP" | head -1 | grep -oE '[0-9]+$')"
if [ "$ohos_name" != "$VERSION" ] || [ "$ohos_code" != "$CODE" ]; then
DRIFT=1
if [ "$CHECK" -eq 1 ]; then
note "cmd/ohos AppScope/app.json5" "$ohos_name/$ohos_code → 应为 $VERSION/$CODE"
else
# app.json5 带注释,不是严格 JSON用 sed 定点替换两个字段。
sed -i -E "s/(\"versionCode\"[[:space:]]*:[[:space:]]*)[0-9]+/\1$CODE/" "$OHOS_APP"
sed -i -E "s/(\"versionName\"[[:space:]]*:[[:space:]]*\")[^\"]+/\1$VERSION/" "$OHOS_APP"
note "cmd/ohos AppScope/app.json5" "$ohos_name/$ohos_code$VERSION/$CODE"
fi
fi
echo "内核版本: $VERSION (versionCode $CODE)"
if [ "$CHECK" -eq 1 ]; then
if [ "$DRIFT" -eq 1 ]; then
echo "sync-client-versions: 客户端版本与内核不一致(见上);跑 bash deploy/scripts/sync-client-versions.sh 同步" >&2
exit 1
fi
echo "sync-client-versions: OK客户端与内核版本一致"
fi