Commit Graph

2 Commits

Author SHA1 Message Date
53d9af446c feat(gui): 星图接上 /memory/graph/pulse + 前端依赖本地化 + 端点对齐门禁
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 条)。
2026-10-01 18:23:20 +08:00
c22c84f8d6 ci: 建立 GitHub Actions 流水线(六个 job,全部命令已本地实测)
## 为什么现在做

这次排查「QQ 收不到回复」花了大半程才定位到根因,途中我犯了两类错:
先断言「提示词没写 output_send 规则」(实际 buildSystemPrompt:48-52 写了),
又断言「适配器丢了内容」(实际两版等价、直连上游正常)。
两次都是**在无自动化判据的情况下凭局部证据外推**。

仓库已有 60 个 Go 包、`go build ./...` 仅 2.2 秒,成本极低却无人强制跑。
AtomGit 停用流水线后更无兜底,故迁到 GitHub 补齐。

## 设计原则:CI 里每条命令都是本地已实测通过的

不写「可能有用先试试」的步骤 —— 未验证的 CI 步骤会把假红灯变成常态,
最后所有人都学会忽略它。本文六个 job 的每条命令都本地跑过:

  go build ./...                      ✓
  go vet ./...                        ✓
  go test ./... -count=1              ✓(干净克隆亦通过)
  make check-client-versions          ✓
  go test -race core + waiter         ✓
  waiter/initconfig/mock-server 交叉  ✓(5 平台)
  npm test(cmd/gui)                 ✓
  make check-csrc                     ✓(告警/ABI/ASan+UBSan/跨架构)

## 六个 job

| job   | 覆盖                                                     |
|-------|----------------------------------------------------------|
| go    | build + vet + test + **跨平台客户端版本一致性**           |
| race  | 并发核心的竞态检测                                        |
| cross | linux/darwin/windows × amd64/arm64(仅可纯交叉的 3 个 cmd)|
| gui   | Electron 仓的 Node 测试                                   |
| csrc  | C 基础设施门禁                                            |
| docs  | 站点配置可解析                                            |

## 关键事实(都由实测确立,不是推断)

1. **只有 waiter/initconfig/mock-server 能纯交叉编译**。homed、memgc、
   homed-kb-migrate 依赖 cgo(gojieba / onnx),必须原生构建 ⇒ 不进 cross matrix。
2. **CGO 必须为 1**:gojieba 需要 cgo,`CGO_ENABLED=0` 下 internal/memory
   直接编译失败(实测)。
3. **`go test ./...` 不会碰到 cmd/gui**。该目录是纯 Electron(0 个 .go、
   无 go.mod),`./...` 只匹配含 Go 文件的包;只有显式 `go test ./cmd/gui`
   才报 "no Go files"。这不是缺陷,是 Go 的包匹配语义 —— 之前把它当
   [setup failed] 是误读。
4. **cmd/gui 的 npm test 零依赖**:三个 .mjs 只 import node: 内置模块
   (fs/url/path/vm)⇒ 不需要 npm ci、不需要 electron,秒级完成。
5. **测试自足,CI 上不会因缺本地服务而红**:webui 测试用 httptest 与
   `127.0.0.1:0`,真实 LLM 测试带 t.Skip 守卫。
6. **action 版本已核实存在**:checkout/setup-go/setup-node/setup-python 均用
   v7(经 GitHub API 逐个确认 tag 存在,避免「版本不存在 ⇒ 立刻红」)。

## 明确不进 CI(依赖真机/密钥/内网,否则只会变 flaky 噪音)

deploy-*.sh、waiter 真机(192.168.2.x)、`npm run test-live`(需真 Electron
+ Xvfb + 真后端)、scripts/kernel-stress/*、需 DEEPSEEK_API_KEY 的真实 LLM 测试。
2026-09-29 10:23:21 +08:00