mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-09 00:54:42 +00:00
GUI 与服务端 WebUI 插件共享同一套 REST 接口,但两边独立演进、没有任何
强制手段。这次核实发现三处真实漂移(服务端 42 路由 / GUI 只用 29)。
1) 星图接上服务端专为它造的轻量活动端点
服务端 handleMemoryGraphPulse 的注释写了动机:生产实例全量图谱
408KB / 1151 节点,为了「知道哪些节点是新的」而每 N 秒拉全量是把
带宽和 JSON.parse 全花在重复数据上;pulse 只回 id+name+type+
mention_count+updated_at,几百字节 ~ 几 KB,差两个数量级。
WebUI dashboard 接了它,GUI 此前只在初始化拉一次全量且完全不轮询
⇒ 星图停在打开那一刻的快照,agent 后来学的东西它永远看不到。
现接入:/runtime 3s + /memory/graph/pulse 10s,两路轮询幂等、
切连接时停;新实体标「生长」;SSE 的 tool_call/stage/agent_output
也会触发脉冲(用工具名与回复前 60 字当 hint,让点亮落到本轮相关实体)。
pulse 检出「全量图里没有的新实体」时置脏,由下一次 renderChatStarmap
惰性重拉全量 —— 不在脉冲回调里直接拉,否则会把轻量活动源变成每 10s
拉一次 408KB 全量,正好是 pulse 端点要消除的浪费。
2) 前端依赖本地化,顺带修掉一处安全边界
四个库从 internal/plugins/webui/static/ 复制到 renderer/vendor/
(字节一致,由门禁钉住),index.html 不再引用任何公网 CDN。
与服务端同一理由(见 webui/starmap_vendor_test.go 的注释):
HomeAgent 支持离线/内网部署,换 CDN 只是把同一个赌注重下一遍。
★ renderMd() 的净化器缺失分支不再回退到手写正则(剥 <script>/on*=/
javascript:)—— 那不是完备的 HTML sanitizer,漏 <iframe srcdoc>、
SVG 内联事件、data: URI 等,而它渲染的是模型输出与记忆文本,
都算不可信输入。现在直接退纯文本:库已本地化,走不到该分支。
3) 新增 endpoint-align.test.mjs(进 npm test / CI)
扫描 app.js 的 api("...") 与 handler.go 的 mux.HandleFunc 对账,
7 条判据。与既有判据同一路子:读真实源码,不抄逻辑重写。
反向差集只报告不门禁(管理面端点接不接是产品决策),
只硬钉「服务端已明确为其设计」的 pulse —— 即本判据的由来。
已做变异测试:改错 pulse 路径、改回 CDN 均能判红。
protocol-align.test.mjs 是真浏览器判据(需 Electron+Xvfb+真后端),
CI 明确不跑,所以这类漂移此前无人发现。
顺带:connectSSE 由隐式全局赋值改为 function 声明(加 "use strict"
会在文件靠后处 ReferenceError,报错点离调用点很远)。
判据:cmd/gui 下 npm test 全绿(4 个 .mjs / 25 条)。
204 lines
6.6 KiB
YAML
204 lines
6.6 KiB
YAML
# HomeAgent 主仓 CI。
|
||
#
|
||
# 设计原则:**CI 里跑的每一条命令,都是本地已实测通过的命令**。
|
||
# 不写「应该有用来试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态,
|
||
# 最后所有人学会忽略它。
|
||
#
|
||
# 覆盖范围与本地 `make test` 对齐(build / vet / test / client-versions /
|
||
# gui / csrc),并按依赖拆成独立 job,便于失败定位。
|
||
#
|
||
# 明确**不在** CI 里跑的东西(依赖真机/密钥/内网,跑了只会变 flaky 噪音):
|
||
# - deploy-*.sh / homed 生产部署
|
||
# - waiter 真机验证(192.168.2.x)
|
||
# - cmd/gui 的 `npm run test-live`(需真 Electron + Xvfb + 真后端)
|
||
# - scripts/kernel-stress/*(需 llmsproxy 与压测端点)
|
||
# - 需要 DEEPSEEK_API_KEY / MEDIALIVE_* 的真实 LLM 测试(已自带 t.Skip)
|
||
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches: [main, 'release/**']
|
||
pull_request:
|
||
workflow_dispatch:
|
||
|
||
# 只读权限:CI 不需要写仓库。
|
||
permissions:
|
||
contents: read
|
||
|
||
# 同一分支连续推送时取消旧跑,省额度也避免过期结果误导。
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
env:
|
||
# gojieba / onnx 相关包需要 cgo ⇒ 不能用 CGO_ENABLED=0。
|
||
CGO_ENABLED: 1
|
||
# 减少 go test 输出噪音。
|
||
GOFLAGS: -buildvcs=false
|
||
|
||
jobs:
|
||
# ── Go 后端:构建 + 静态检查 + 全量测试 + 跨平台客户端版本一致性 ──
|
||
go:
|
||
name: Go build / vet / test
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 30
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
|
||
# cgo 需要 gcc/g++(gojieba 会编译自带 C++ 源码)。
|
||
- name: 确认 cgo 工具链
|
||
run: |
|
||
gcc --version | head -1
|
||
g++ --version | head -1
|
||
|
||
- name: go build ./...
|
||
run: go build ./...
|
||
|
||
- name: go vet ./...
|
||
run: go vet ./...
|
||
|
||
# ./... 不点名 cmd/gui(该目录是纯 Electron,无 .go 文件):
|
||
# 显式 `go test ./cmd/gui` 会报 "no Go files",那是误报,不是缺陷。
|
||
- name: go test ./...
|
||
run: go test ./... -count=1 -timeout 20m
|
||
|
||
# 跨平台客户端版本一致性:内核 internal/meta 是唯一事实源,
|
||
# GUI(package.json) / 鸿蒙(AppScope/app.json5) / waiter 都必须跟它一致。
|
||
- name: 客户端版本一致性
|
||
run: make check-client-versions
|
||
|
||
# ── 竞态检测(并发改动的主要防线)──
|
||
race:
|
||
name: Race detector
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
- name: go test -race(并发核心)
|
||
run: |
|
||
go test -race \
|
||
./internal/agent/core/ ./cmd/waiter/ \
|
||
-count=1 -timeout 15m
|
||
|
||
# ── 交叉编译:可在无 cgo 下构建的客户端/工具 ──
|
||
#
|
||
# 只有这三个 cmd 支持纯交叉编译。另外三个依赖 cgo(gojieba / onnx):
|
||
# homed / memgc / homed-kb-migrate → internal/memory(gojieba)
|
||
# homed → internal/agent/api(onnx)
|
||
# 它们必须在原生平台构建(见 Makefile 的 build target)。
|
||
cross:
|
||
name: Cross-compile
|
||
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
|
||
- uses: actions/setup-go@v7
|
||
with:
|
||
go-version-file: go.mod
|
||
cache: true
|
||
- name: 构建 ${{ matrix.goos }}/${{ matrix.goarch }}
|
||
env:
|
||
GOOS: ${{ matrix.goos }}
|
||
GOARCH: ${{ matrix.goarch }}
|
||
CGO_ENABLED: 0
|
||
run: |
|
||
set -euo pipefail
|
||
mkdir -p dist
|
||
for c in waiter initconfig mock-server; do
|
||
out="dist/${c}_${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.ext }}"
|
||
go build -trimpath -o "$out" "./cmd/${c}"
|
||
echo " ✓ ${c} ${{ matrix.goos }}/${{ matrix.goarch }}"
|
||
done
|
||
|
||
# ── Electron GUI(纯 Node 测试,零依赖)──
|
||
#
|
||
# `npm test` 跑四个 .mjs,全部只 import node: 内置模块(fs/url/path/vm),
|
||
# 所以**不需要 npm ci、不需要 electron**,秒级完成。
|
||
# `npm run test-live` 需真 Electron + 真后端 ⇒ 不进 CI。
|
||
#
|
||
# endpoint-align.test.mjs 跨出 cmd/gui 读 ../../internal/plugins/webui/handler.go
|
||
# 做端点对账 —— checkout 深度足够(默认 fetch-depth:1 已含工作树文件),
|
||
# 不需要额外 checkout 步骤。
|
||
gui:
|
||
name: GUI (node)
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 10
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-node@v7
|
||
with:
|
||
node-version: '22'
|
||
- name: npm test
|
||
working-directory: cmd/gui
|
||
run: npm test
|
||
|
||
# ── C 基础设施门禁(ABI / 告警 / ASan+UBSan / 跨架构)──
|
||
csrc:
|
||
name: C infrastructure gates
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 20
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
|
||
# clang 供双编译器告警对照;gcc-aarch64 供跨架构编译门禁。
|
||
# 门禁在缺工具时是显式 SKIP 而不是假通过,这里装齐以免静默降级。
|
||
- name: 安装 C 工具链
|
||
run: |
|
||
sudo apt-get update -qq
|
||
sudo apt-get install -y -qq cmake clang gcc-aarch64-linux-gnu
|
||
|
||
- name: make check-csrc
|
||
run: make check-csrc
|
||
|
||
# ── 文档站构建(mkdocs,纯 Python,无外部依赖)──
|
||
docs:
|
||
name: Docs build
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 10
|
||
steps:
|
||
- uses: actions/checkout@v7
|
||
- uses: actions/setup-python@v7
|
||
with:
|
||
python-version: '3.12'
|
||
- name: 校验站点配置可解析
|
||
# 这里只做「配置与文档源没坏」的轻量校验,不做完整 mkdocs build
|
||
# (站点发布有独立流水线,见 deploy-sdk-site.sh)。
|
||
run: |
|
||
set -euo pipefail
|
||
if [ -f mkdocs.yml ]; then
|
||
python -c \
|
||
"import yaml; yaml.safe_load(open('mkdocs.yml'))" \
|
||
&& echo "mkdocs.yml OK"
|
||
else
|
||
echo "无 mkdocs.yml,跳过"
|
||
fi
|
||
test -d docs || echo "无 docs/,跳过"
|