mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-01 23:07:30 +00:00
## 为什么必须做
SDK 仓(独立仓库)已把 module 从 `github.com/JianFeeeee/homeagentsdk`
改名为 `hologramagentsdk`。主仓通过 `replace` 直接引用它的**物理目录**:
replace github.com/JianFeeeee/homeagentsdk => ./third_party/homeagent-sdk
一旦 SDK 侧改成新 module 名,主仓立刻炸:
go: ./third_party/homeagent-sdk@ used for two different module paths
(github.com/JianFeeeee/hologramagentsdk and github.com/JianFeeeee/homeagentsdk)
Go **不允许**同一目录被两个 module 路径 replace。所以不能"新旧并存",
只能把主仓 59 个文件的 import 全部改到新名,并删掉旧 replace。
## 一个被证伪的前提
我最初按"third_party/homeagent-sdk 是独立仓库,不能在此仓修改其源码"
来处理,并因此判断两个仓的改动可以隔离。实际上主仓是靠 `replace` 指向
该目录的物理副本 —— **两个仓的改动不可能真正隔离**:SDK 侧改 module 名,
主仓必然跟着改 import。
这个前提应该在做任何改动之前用 `go list -m` 验证,而不是假设。
## 连带修掉两处
| 缺陷 | 性质 |
|---|---|
| `TestLuaSDKMockSingleSource` 失败 | SDK 的 `sdk/lua/sdk.lua` 变了,主仓内嵌副本未同步(跑 `scripts/sync-lua-sdk.sh` 修复) |
| `sdkModuleNames` 分散两处 | 已在 SDK 仓合并为单一数据源(见 SDK 仓 725732b) |
第一条是**副本一致性判据抓到的**,不是我自己发现的 —— 这类判据的价值在此:
两个仓必然有副本,靠人记住"改了 A 要同步 B"是做不到的。
## 验证
- `go build ./...` / `go vet ./...` 干净
- `go test ./... -count=1`:**58 包 0 失败**
- `internal/plugin`(Lua SDK 副本一致性)+ `internal/sdk` 全绿
- 主仓 `third_party/homeagent-sdk/` 与 SDK 仓 `main` 无差异
120 lines
3.2 KiB
Go
120 lines
3.2 KiB
Go
package proc
|
||
|
||
// 变量库的 proc 桥(内核侧)。
|
||
//
|
||
// ## 与 settings 的分工
|
||
//
|
||
// settings —— **每个插件自己的**配置(各自的 config_<name> 表)
|
||
// secrets —— **全进程共享的**变量库(security.Global() 单例)
|
||
//
|
||
// 这个区别是本质的:变量库全局唯一(设计 S10),主/子/驻留子 agent
|
||
// 与全部插件共用同一套别名。所以它不该走 settings 的命名空间机制。
|
||
//
|
||
// ## 为何需要这层桥
|
||
//
|
||
// 外部插件是**子进程**,它的 `sdk.Secrets()` 拿到的是模板里的
|
||
// `procSecrets`(见 templates/proc_main.go.tmpl),它把调用转成 RPC
|
||
// 发到这里。这条链路有 4 个地方要同时改(协议常量 / 路由 / 分发 / 能力表),
|
||
// 少一处就报 "未知 method" —— 真机 e2e 会立刻发现(本次已踩过一次)。
|
||
|
||
import (
|
||
"encoding/base64"
|
||
"encoding/json"
|
||
"fmt"
|
||
|
||
pubsdk "github.com/JianFeeeee/hologramagentsdk/sdk"
|
||
)
|
||
|
||
func (h *coreHandler) secrets(method string, params json.RawMessage) (interface{}, error) {
|
||
sec := h.sdk.Secrets()
|
||
if sec == nil {
|
||
return nil, errUnavailable("secrets")
|
||
}
|
||
|
||
switch method {
|
||
case MethodSecretsAvailable:
|
||
// 明确的可用性查询(不靠 List 推断 —— 见 secrets_impl 的注释)
|
||
return map[string]interface{}{"available": sec.Available()}, nil
|
||
|
||
case MethodSecretsStore:
|
||
var p struct {
|
||
Value string `json:"value"`
|
||
Note string `json:"note"`
|
||
}
|
||
if err := unmarshal(params, &p); err != nil {
|
||
return nil, err
|
||
}
|
||
alias, err := sec.Store(p.Value, p.Note)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// ★ 只回别名,不回显明文(与 SDK 的契约一致)
|
||
return map[string]interface{}{"alias": alias}, nil
|
||
|
||
case MethodSecretsList:
|
||
infos := sec.List()
|
||
if infos == nil {
|
||
infos = []pubsdk.SecretInfo{}
|
||
}
|
||
return map[string]interface{}{"infos": infos}, nil
|
||
|
||
case MethodSecretsForget:
|
||
var p struct {
|
||
Alias string `json:"alias"`
|
||
}
|
||
if err := unmarshal(params, &p); err != nil {
|
||
return nil, err
|
||
}
|
||
return nil, sec.Forget(p.Alias)
|
||
|
||
case MethodSecretsFill:
|
||
var p struct {
|
||
Text string `json:"text"`
|
||
}
|
||
if err := unmarshal(params, &p); err != nil {
|
||
return nil, err
|
||
}
|
||
out, n, aliases := sec.Fill(p.Text)
|
||
if aliases == nil {
|
||
aliases = []string{}
|
||
}
|
||
return map[string]interface{}{
|
||
"text": out, "replaced": n, "aliases": aliases,
|
||
}, nil
|
||
|
||
case MethodSecretsEncrypt:
|
||
// 二进制负载经 base64 过 RPC(JSON 不能直接带 bytes)
|
||
var p struct {
|
||
PlainB64 string `json:"plain_b64"`
|
||
}
|
||
if err := unmarshal(params, &p); err != nil {
|
||
return nil, err
|
||
}
|
||
raw, err := base64.StdEncoding.DecodeString(p.PlainB64)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("secrets.encrypt: base64 解码失败: %w", err)
|
||
}
|
||
enc, err := sec.Encrypt(raw)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return map[string]interface{}{"encrypted": enc}, nil
|
||
|
||
case MethodSecretsDecrypt:
|
||
var p struct {
|
||
Stored string `json:"stored"`
|
||
}
|
||
if err := unmarshal(params, &p); err != nil {
|
||
return nil, err
|
||
}
|
||
plain, err := sec.Decrypt(p.Stored)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return map[string]interface{}{
|
||
"plain_b64": base64.StdEncoding.EncodeToString(plain),
|
||
}, nil
|
||
}
|
||
return nil, fmt.Errorf("未知 secrets method: %s", method)
|
||
}
|