mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-15 12:15:11 +00:00
SDK 仓已迁到 GitHub 作为权威源,go module 路径同步: `gitcode.com/JianFeeeee/homeagent-sdk` → `github.com/JianFeeeee/homeagentsdk` ## 范围 74 个文件:71 个 Go 源码 + go.mod/go.sum + hmapdev 模板 + CI 与打包脚本。 主仓(HomeAgent)侧对应改动是 6d38a164。本仓这些文件当时**不在工作树上** (见下),所以那次的批量替换扫不到它们——这里是补偿。 ## 为何这批文件当时不在工作树上(事故与恢复) 10-08 07:58 主仓做 checkout/cherry-pick 序列时,把本仓工作树的 20 个文件 误清理了(`example/*/plugin.go` + `plg.json`,10 个示例)。 根因是**结构误判**:本仓是「一目录两仓库」结构下主仓 `third_party/` 里的 **独立 git 仓库**,而主仓 .gitignore 忽略了 `example/`,于是它在主仓 `git status` 里不可见 —— 看着像「不受跟踪的构建产物」,实际是本仓受跟踪的源码。 已全部恢复(`git checkout -- <D 文件>`,只恢复删除、不动迁移改动), 20 个文件与 HEAD 逐字节一致。 **破坏的连锁后果**:恢复出来的 `plugin.go` 仍写着旧 module 路径, 因为迁移时它们已不在工作树上。所以这次补偿是必须的,不是可选优化。 ## 保留 gitcode 引用 以下位置的 `gitcode` **有意保留**,不要"顺手清掉": - README.md / docs 里「二进制实际分发地址目前是 gitcode」的说明 - mkdocs.yml 的 gitcode 镜像链接(国内直连更快) - `tools/hmapdev/templates.go` 里「SDK 已从 gitcode 迁到 GitHub」的注释 gitcode 仍是**只读镜像**(源码同步;release 附件暂时仍在那边)。 ## 验证 - 本仓根 module:`go build ./...` + `go test ./...` 全通过 - 全部 20 个 example:`go vet` 通过(补偿前 10 个因旧 module 路径失败) - example/qq:`go test` 通过,且能从源码 build 出可用 plugin 产物
252 lines
10 KiB
YAML
252 lines
10 KiB
YAML
# HomeAgent SDK 仓 CI。
|
||
#
|
||
# 与 release.yml 分工:本文件管「推送到 main / PR 时的检查」,release.yml 管
|
||
# 「release/** 推送时的发版」。此前本仓**只有** release.yml —— main 的推送与
|
||
# PR 完全没有检查,而 SDK 是被外部插件开发者直接依赖的契约面(sdk/plugin.go
|
||
# 的接口一旦破,所有外部插件编译失败),必须有门。
|
||
#
|
||
# 设计原则与主仓一致:**CI 里每条命令都是本地已实测通过的**。
|
||
# 不写「应该有用来试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态。
|
||
#
|
||
# 明确不进 CI 的:
|
||
# - `hmapdev skill install`(会写 ~/.claude、~/.codex 等**开发者本机目录**)
|
||
# - 需要内核仓在场的检查(本仓独立可测;sync-lua-sdk.sh 会在缺内核时
|
||
# 明确 skip 而不是假装成功)
|
||
# - 任何网络/真机依赖
|
||
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main, 'release/**']
|
||
pull_request:
|
||
workflow_dispatch:
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
# SDK 本身不需要 cgo(hmapdev 与 sdk 包都是纯 Go)—— 与主仓相反。
|
||
CGO_ENABLED: 0
|
||
GOFLAGS: -buildvcs=false
|
||
|
||
jobs:
|
||
# ── 根模块:SDK 对外接口所在 ──
|
||
go:
|
||
name: Go build / vet / test
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
- name: go build ./...
|
||
run: go build ./...
|
||
- name: go vet ./...
|
||
run: go vet ./...
|
||
- name: go test ./...
|
||
run: go test ./... -count=1 -timeout 10m
|
||
|
||
# ── hmapdev 工具链(嵌套 module,根模块的 ./... 不会进入它)──
|
||
hmapdev:
|
||
name: hmapdev (${{ matrix.goos }}/${{ matrix.goarch }})
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
include:
|
||
- goos: linux
|
||
goarch: amd64
|
||
ext: ''
|
||
- goos: linux
|
||
goarch: arm64
|
||
ext: ''
|
||
- goos: darwin
|
||
goarch: amd64
|
||
ext: ''
|
||
- goos: darwin
|
||
goarch: arm64
|
||
ext: ''
|
||
- goos: windows
|
||
goarch: amd64
|
||
ext: '.exe'
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
# tools/hmapdev 是**独立 module**(有自己的 go.mod)——
|
||
# 根模块的 `go test ./...` 不会进入它,必须单独跑,否则它的测试
|
||
# 永远不在 CI 里执行。这是 Go 的模块边界,不是配置问题。
|
||
- name: go test(嵌套 module)
|
||
working-directory: tools/hmapdev
|
||
run: go test ./... -count=1 -timeout 10m
|
||
|
||
# main 包在 tools/hmapdev —— 不指定工作目录会在仓库根跑 `go build .`,
|
||
# 而根目录没有 Go 文件(包在 sdk/ 子目录),报 "no Go files in ..."。
|
||
- name: 交叉编译
|
||
working-directory: tools/hmapdev
|
||
env:
|
||
GOOS: ${{ matrix.goos }}
|
||
GOARCH: ${{ matrix.goarch }}
|
||
run: |
|
||
set -euo pipefail
|
||
out="hmapdev_${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.ext }}"
|
||
go build -trimpath \
|
||
-ldflags "-X github.com/JianFeeeee/homeagentsdk/meta.Version=0.0.0-ci" \
|
||
-o "/tmp/$out" .
|
||
test -s "/tmp/$out" || { echo "ERROR: 未产出 $out"; exit 1; }
|
||
printf " ✓ %-28s %s 字节\n" "$out" "$(stat -c %s "/tmp/$out")"
|
||
file "/tmp/$out"
|
||
|
||
# ── 示例插件:发版产物里最容易被使用者直接安装的东西 ──
|
||
#
|
||
# 为什么必须验:示例是使用者的模板(拷了就改),且**发版会连同 .hmap 一起发**
|
||
# —— 插件二进制与内核是协议绑定的(ProtocolVersion + 统一共享内存区魔数),
|
||
# 示例编不出来就意味着这次发版发不出配套产物。
|
||
#
|
||
# ★ 示例**不能**用 `go build` 验:它们是插件(只有 plugin.go、没有 func main),
|
||
# 必须由 hmapdev 注入 main 包装。直接 go build 会得到
|
||
# "function main is undeclared in the main package" —— 那不是缺陷,
|
||
# 是构建方式不对(本地实测确认)。
|
||
examples:
|
||
name: Examples (${{ matrix.target }})
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 30
|
||
strategy:
|
||
fail-fast: false
|
||
matrix:
|
||
# windows 不在列:build-examples.sh 会明确拒绝(协议 2 的统一共享
|
||
# 内存区未移植到 Windows),那是有意的设计而不是待修缺陷。
|
||
target: ['linux/amd64', 'darwin/arm64']
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
- name: 构建 hmapdev(宿主)
|
||
run: |
|
||
set -euo pipefail
|
||
cd tools/hmapdev
|
||
go build -o "$GITHUB_WORKSPACE/build/hmapdev_host" .
|
||
|
||
# 用发版同一个脚本(package/build-examples.sh),避免 CI 与发版路径分叉。
|
||
- name: 构建全部示例
|
||
env:
|
||
HMAPDEV: ${{ github.workspace }}/build/hmapdev_host
|
||
TARGET: ${{ matrix.target }}
|
||
run: |
|
||
set -euo pipefail
|
||
bash package/build-examples.sh "$TARGET" /tmp/examples
|
||
echo
|
||
n=$(find /tmp/examples -name '*.hmap' | wc -l)
|
||
echo " .hmap 产物数: $n"
|
||
# 示例目录数应与产物数一致(少一个都要红)
|
||
want=$(find example -mindepth 2 -maxdepth 2 -name plugin.go | wc -l)
|
||
echo " 示例源码数: $want"
|
||
[ "$n" -ge "$want" ] || { echo "ERROR: 产物少于示例数"; exit 1; }
|
||
for f in /tmp/examples/*.hmap; do
|
||
printf " %9.1fKB %s\n" \
|
||
"$(stat -c %s "$f" | awk '{print $1/1024}')" "$(basename "$f")"
|
||
done
|
||
|
||
# ── 一致性与文档 ──
|
||
consistency:
|
||
name: Consistency & docs
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
# sdk.lua 有**四份**副本(本仓三份 + 内核仓一份),历史上漂移过,
|
||
# 出现「mock 有、内核没有」的静默失配。此处钉住本仓内的三份。
|
||
- name: Lua SDK 副本一致性
|
||
run: |
|
||
set -euo pipefail
|
||
canon=sdk/lua/sdk.lua
|
||
[ -f "$canon" ] || { echo "ERROR: 缺 $canon"; exit 1; }
|
||
want=$(sha256sum "$canon" | cut -d' ' -f1)
|
||
fail=0
|
||
for f in tools/hmapdev/assets/sdk.lua example/luademo/sdk.lua; do
|
||
have=$(sha256sum "$f" | cut -d' ' -f1)
|
||
if [ "$have" = "$want" ]; then
|
||
echo " ✓ $f"
|
||
else
|
||
echo " ✗ $f 与 $canon 不一致" >&2
|
||
echo " canon=$want" >&2
|
||
echo " this =$have" >&2
|
||
echo " 解法:bash scripts/sync-lua-sdk.sh" >&2
|
||
fail=1
|
||
fi
|
||
done
|
||
[ "$fail" = "0" ] || exit 1
|
||
|
||
# ★ 钉 1.25 而不是 go-version-file: go.mod —— 根 go.mod 写的是
|
||
# go 1.21.0,但 20 个 example/*/go.mod 都要求 go 1.25.0。
|
||
# 读根 go.mod 会装 1.21,examples 构建必然失败
|
||
# ("go.mod requires go >= 1.25.0 (running go 1.21.0; GOTOOLCHAIN=local)")。
|
||
# GitHub runner 上 GOTOOLCHAIN=local,Go 不会自动下载更高工具链,
|
||
# 所以本地「能过」不代表 CI 能过。
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version: '1.25'
|
||
cache: true
|
||
|
||
# skills/ 会随 SDK store 分发给所有 agent(hmapdev skill install)。
|
||
# skill list 会读 skills/ 目录并报告可用项 —— 目录结构坏掉会在这里红。
|
||
- name: 技能目录可被 hmapdev 识别
|
||
run: |
|
||
set -euo pipefail
|
||
# ★ 必须把 hmapdev 建在**仓库内**:resolveSkillsSource() 先从
|
||
# 可执行文件位置向上找仓库(tools/hmapdev → ../../skills),
|
||
# 落空才回退到 SDK store 的活跃版本 —— 而 CI 里没有 store,
|
||
# 于是报 "no active SDK version set"。建到 /tmp 就会落空。
|
||
mkdir -p build
|
||
( cd tools/hmapdev && go build -o "$GITHUB_WORKSPACE/build/hmapdev_ci" . )
|
||
./build/hmapdev_ci skill list
|
||
./build/hmapdev_ci skill path
|
||
|
||
- uses: actions/setup-python@v7
|
||
with:
|
||
python-version: '3.12'
|
||
|
||
# 文档站会被部署(deploy-sdk-site.sh)——站点构建坏了此前无从发现。
|
||
# --strict 把 warning 升级为 error:断链、缺失引用都会红。
|
||
#
|
||
# ★ 不能用 yaml.safe_load 校验 mkdocs.yml:它含 mkdocs-material 的
|
||
# `!!python/name:` 标签(配置 emoji 的官方写法),safe_load 处理不了,
|
||
# 会报 ConstructorError —— 那是校验方式不对,不是配置有问题。
|
||
- name: 文档站构建(mkdocs --strict)
|
||
run: |
|
||
set -euo pipefail
|
||
python3 -m pip install --quiet mkdocs-material
|
||
mkdocs build --strict --site-dir /tmp/site
|