e256023399
docs+plugindev: README 同步子进程架构,scaffold 修 entry 与 go.sum 死路
...
三类问题,都会让新用户第一次上手就走错:
1. README 仍写 plugin.so
plugin.json 示例的 entry、entry 字段说明、.hmap 包格式三处描述的都是
已退场的 C ABI 产物。改为 plugin.bin,并补 bundle 模式下
plugin.bin.<goos>.<goarch> 的命名与安装时挑平台的行为。
2. cmd_init.go 的 entry := "plugin.so"
scaffold 出来的 plg.json 带着一个已退场的 entry 值。build 实际不看这个
值(只用它区分 Lua),但跟着模板走会误以为自己在做 C ABI 插件。
3. 生成的项目第一次 build 必定失败
go.mod 只 require 一个 gitcode 模块版本号且不生成 go.sum。gitcode 不在
proxy.golang.org 上,于是:
go build → missing go.sum entry
go mod tidy → 去公共 proxy 拉一个不存在的条目,超时
原来 cmdBuild 里那句 `go mod download <mod>` 走的正是这条死路,失败后
只打一行 warn 就继续编译,紧接着死在同一个错误上——用户看到两段无关报错。
修法分两处:
- 生成的 go.mod 直接写指向本机 SDK 的 replace(replace 到目录时 go 不
需要也不校验 go.sum)
- 新增 ensureSDKResolvable:三级策略(已有本地 replace → 探测本机 SDK
并写入 → 兜底 go mod tidy 带 -mod=mod,失败给可操作提示)。存量项目
go.mod 无 replace 时走第二级救回。
bin/ 5 个预编译二进制不再进仓库(改为 release 附件):
5 个平台各 26-28MB,每次重编都在 git 历史里再叠一份,而它们本质是可从源码
复现的产物。README 的下载说明同步改为 release 附件 URL + 从源码编译。
2026-09-03 19:27:03 +08:00
9f844123fe
plugindev: entry 语义收敛 + 删 C ABI 工具链 + Windows 共享内存适配(Part 6.1)
...
## entry 不再是通道开关 —— 外部插件零改动的关键
17 个存量插件的 plg.json 都写着 "entry": "plugin.so"。若把 entry 当通道
开关,迁移就得改 17 个文件,而「外部插件零改动」是本次迁移的硬约束。
改法:Go 插件一律产出 plugin.bin,不看 entry 值。isProcEntry 删除,
resolveBuild 去掉 proc 参数。entry 现在只剩区分 Lua(main.lua)一个用途。
实测:weather 的 plg.json 一行不改(仍写 plugin.so),plugindev build
直接产出三平台 plugin.bin。
## Windows 不再是能力退化的第三套实现(§9.2 的正解)
C ABI 时代 Windows 是独立的第三套 ABI:dynamic_dll_windows.go 的 stage
只下发 3 个字段(raw_message/user_id/phase)且完全没有写回,sanitizer
这类改写型插件在 Windows 上静默失效,且无任何运行时警告。
现在 Windows 与 Unix 共用同一份 RPC 逻辑与同一份共享段布局。平台差异
收敛到三个挂载函数:
- Unix(linux/darwin/freebsd):内核经 ExtraFiles 传继承 fd(3=StageContext
段,4=事件环段,5=eventfd/pipe)
- Windows:没有 fd 继承语义(os/exec 的 ExtraFiles 在 Windows 不支持),
改用命名内核对象——父进程 CreateFileMapping/CreateEvent 建带名字的对象,
子进程 OpenFileMappingW/OpenEventW 按同名打开。名字经环境变量传入而非
硬编码:多个 homed 实例并存时不能撞名。
Windows 绑定用 syscall.NewLazyDLL 而非 golang.org/x/sys/windows:
OpenFileMappingW/OpenEventW 未被标准库 syscall 导出,而引入 x/sys 会给
**每个插件的 go.mod** 加一个新依赖,违反「插件仅依赖公开 SDK」。
LazyDLL 属标准库,零新增依赖。
新增 evtWaiter 接口抽象等待语义:eventfd 是计数器(多事件合并成一次
唤醒),Windows Event 是二元信号。不影响正确性——消费者被唤醒后按
readSeq 追 writeSeq 批量 drain,一次唤醒能处理累积的全部事件。
模板拆成三个文件:
proc_main.go.tmpl 平台无关(RPC + 共享段布局 + stage + 事件环消费)
proc_shm_unix.go.tmpl 继承 fd 挂载
proc_shm_windows.go.tmpl 命名对象挂载
## 删除 C ABI 工具链
templates.go 1296 → 516 行:
- tmplBridge(Windows DLL bridge) -265 行
- tmplLinuxBridge(Linux c-shared) -457 行
- tmplPluginInitC(C 入口) -57 行
另删 generateBridge / detectWindowsCC(MinGW 探测)/ tmplCABIHeader /
InitData.CABIVersion+CABIHeader。
交叉编译不再需要目标平台 C 工具链——这是 -buildmode=c-shared 退场的
连带收益(§3.1)。
## 测试
15 项全过,新增 4 项守护迁移不变量:
- AllPlatformsProduceBin:6 个 GOOS/GOARCH 组合统一产出 plugin.bin
- LuaIsSeparatePath:Lua 仍走解释器路径
- UnsupportedOSErrors:不支持平台明确报错,不静默产出错误产物
- NoCABIResiduals:代码中不得再出现 c-shared / CGO_ENABLED=1 /
detectWindowsCC / tmplLinuxBridge / tmplPluginInitC(注释除外)
- IgnoresEntryForGoPlugins:isProcEntry 必须已删除
验证:go build/vet/test 全通过;三平台交叉编译产出 plugin.bin;
git diff sdk/ 为空(接口冻结)。
Ref: docs/zh/架构迁移评估.md §3.1/§9.2、docs/zh/plugin-migration-plan.md Part 6
2026-09-02 18:39:02 +08:00
ef0e58ee23
plugindev: 模板支持事件环消费(Part 5 子进程侧)
...
handleHandshake 额外挂载 fd 4(事件环段)+ fd 5(eventfd),启动
evtConsumerLoop goroutine 消费事件。
HandshakeParams 新增 evt_ring_size 字段(0 = 不支持事件环)。
events.subscribe:按类型列表在本地注册 handler,evtConsumerLoop 从
共享段读 slot 后按位索引分发。events.unsubscribe 清空全部 handler。
事件环布局常量与内核 internal/plugin/proc/evtring.go 一一对应。
验证:weather.bin 零改动编译通过;E2E 测试全通过。
Ref: docs/zh/架构迁移评估.md §3.6
2026-09-02 17:05:01 +08:00
09b64dcb53
plugindev: 支持子进程插件构建(entry=plugin.bin,零 cgo)
...
Part 3 工具链改造。插件业务代码零改动,只需把 plg.json 的 entry
从 plugin.so 换成 plugin.bin。
新增 templates/proc_main.go.tmpl(1113 行)——子进程运行时:
- 51 个 core method 的插件侧 RPC 实现(procIO/procMemory/procSettings/
procSocial/procLLM/procKnowledge/procDocMemory/procTextMemory/procPluginMgr)
- 共享段访问(fd 3 = 内核经 ExtraFiles 传入的 memfd)+ 16 字段
StageContext 编解码,布局常量与 internal/plugin/proc/shm.go 逐一对齐
- handleStageInvoke:拿锁 → 读段 → handler → **只写脏字段** → 放锁。
只读插件脏字段集为空 → 零写入 → 不可能覆盖他人改写
(对照 C ABI 副本模型实测 35.8~36.8% lost update)
- 主循环每请求独立 goroutine:handler 内会反向调用内核并等应答,
在读循环里同步处理会死锁
- plugin.start 后显式上报 AutoRestart:公开 SDK 的 SetAutoRestart 是纯
setter 无 hook,隔着进程边界内核读不到(内核侧 corehandler.go:145 已就绪)
模板选择真实 .go 源文件 + //go:embed 而非 raw string:900+ 行代码塞在
字符串里写错只能等生成插件时才炸,作为源文件可被 parser/gofmt/vet 检查。
cmd_build.go:resolveBuild(target, proc) 分派;proc 走 go build -trimpath
+ CGO_ENABLED=0,交叉编译不再需要目标平台 C 工具链。bundle 模式各平台
产物同名故 zip 内加平台后缀(plugin.bin.linux.amd64)。
proc_runtime.go 生成时清理残留 z_bridge_gen.go/z_entry.c——同目录两套
main 会编译冲突,这让 .so → .bin 切换无需人工清理。
proc_runtime_test.go 16 项静态检查,防内核/插件两侧漂移:
method 名清单、7 个内核调用、共享段常量与字段枚举顺序、stage 加锁顺序、
快照必须存序列化字符串(切片共享底层数组的坑在 11.3 已踩过)、
arena 不足须报错、日志走 stderr、版本不匹配须拒绝、零 cgo。
验证:真实 plugindev 构建 example/weather,plugin.go 逐字节未改,
产出静态链接 ELF;git diff sdk/ 为空(接口冻结)。
Ref: docs/zh/架构迁移评估.md §3、docs/zh/plugin-migration-plan.md Part 3
2026-09-02 12:13:45 +08:00
56485194df
fix(plugindev): stage 回传改 diff,只回传变更字段,修复 lost update(plan 11.3)
...
根因:go_invoke_stage 无条件回传 stageContextWritable 全部字段(含插件从内核收到
的旧快照),sanitizer(改ToolResults)+weather(只读) 并发时,只读插件把自己收到的
旧快照覆盖回清洗结果(实验13 实测丢失率 1.6~4.3%,脏数据进LLM)。
改动:
- templates.go: 新增 snapshotWritable(handler 前的序列化快照)+ changedFieldsOnly(只回传差异字段)
go_invoke_stage 改为 before 快照 → handler → diff 回传,无变更零回传
- ❗ 关键陷阱(第一版踩坑):stageContextWritable 的切片字段与 sc 共享底层数组,
handler 原地改元素时 before 快照跟着变,diff 失效——故 before 必须序列化成字符串
- stagediff_test.go: 6 用例(只读零回传/原地改切片/标量改/新response/清空切片/现网场景复刻)
⚠️ 需用新 plugindev 重编全部 17 个外部插件(bridge 模板变更)
2026-08-31 12:29:57 +08:00
59c6e1844c
fix(plugindev): bridge 模板补 dispatchIO.SetToolBlocks,修复外部插件无法编译
...
SDK v0.9.2(68497b4)给 IOInjector 加了 SetToolBlocks,但 plugindev 的
C ABI bridge 模板(tmplLinuxBridge)未同步,导致任何外部插件在当前 SDK 下
编译失败:
z_bridge_gen.go:97: cannot use dispatchIO{} as sdk.IOInjector value in
argument to base.SetIOInjector: dispatchIO does not implement
sdk.IOInjector (missing method SetToolBlocks)
补空实现满足接口。SetToolBlocks 是 Go 原生(进程内 IOManager)的多模态注入,
跨 ABI 无对应 method id 与内核桥接,故不做 callVoid 转发。
实测:example/qq 用重建后的 plugindev build --target linux/amd64 构建通过,
产出 .hmap 经 plugin_install 安装、重启后 20 个工具全部注册成功。
2026-08-30 17:11:20 +08:00
130f805b6e
feat(sdk): SettingsAPI.DataDir() + plugindev dispatchSettings 补 DataDir
...
SDK SettingsAPI 新增 DataDir() 插件专属数据目录;
plugindev 工具链 dispatchSettings 模板补 DataDir 实现(callString 51)。
ai_image example 改用 DataDir + 本地交付。详见 TrueAgent 仓库。
2026-08-26 21:41:28 +08:00
fc876c5554
feat: 单插件重载等 PluginMgr 能力导出到外部 SDK
...
- meta: CORE_PLUGIN_RELOAD_ONE(48) / LIST_LOADED(49) / IS_DISABLED(50)
- sdk: PluginMgrAPI 接口(ReloadOne/ListLoadedPlugins/IsPluginDisabled) +
PluginSDK.SetPluginMgrAPI/PluginMgr() 访问器
- plugindev 模板: dispatchPluginMgr 桥接注入,走 C ABI 48/49/50
2026-08-23 19:47:55 +08:00
392f391f68
v0.9.0: C ABI v2 stage 写回 + ABI 版本对齐核心版本号
...
- meta: ABI 标识版本改为字符串 semver(ABIVersion=CoreVersion="0.9.0"),
C 层协商用派生整数 CABINum=900(major*100+minor),不再用独立数字编码
- plugindev 模板: invoke_stage 增加 result out 参数(stage 写回),
插件在 OnInput/AfterToolcall/PostAction 修改 StageContext 后回传内核
- cmd_init: CABIVersion 改用 CABINum
- example/sanitizer: 增强为全链路清洗(坏 UTF-8/U+FFFD/ANSI 转义),
挂载 OnInput/AfterToolcall/PostAction 三阶段(依赖 stage 写回能力)
2026-08-15 15:52:10 +08:00
cca9fdce9c
example: 新增 acp(ACP 代理通信)、vanblog(VanBlog 博客管理) 插件; 多插件工具调用检测与清理改进; weather 移除 onRemove/文本记忆; plugindev 精简
2026-08-15 09:03:05 +08:00
b6e30f9279
tools: plugindev 工具链支持公共 IOInjector.InjectInputSync(CORE_INJECT_INPUT_SYNC=47,z_bridge dispatchIO 桥接),重建 bin 预编译二进制;example/memo: plg.json 修复(name_en 去斜杠、去 BOM);sdk/plugin.go 注释精简
2026-08-02 16:24:59 +08:00
f3d87ec35f
docs: 生命周期文档补全 onRemove(删除清理)说明
...
- README.md/README_EN.md:新增删除清理(onRemove)小节——语义(仅卸载
触发、重载/禁用不触发,Stop 之后执行)、内核配套清理(工具注册/disabled/
配置项定义 plugin.<name>.*/配置表 config_<name>)、示例清单与代码片段
- plugindev 模板 README.md.tmpl:新增 Lifecycle 段(RegisterStopHandler 每次
停止、RegisterOnRemoveHandler 仅卸载)
2026-08-02 15:23:22 +08:00
fb07081929
插件删除回调(onRemove)与模板/示例同步
...
- sdk: RegisterOnRemoveHandler/RunOnRemoveHandlers(仅卸载时触发,重载不触发;
后注册先执行、幂等),与 RegisterStopHandler/RunStopHandlers 并存
- plugindev: 模板 main.go.tmpl 新增 onRemove 演示(删配置键),templates.go 同步
- example/calendar: RegisterOnRemoveHandler(p.cleanupData) 卸载时清理 events.json
- README/README_EN: 生命周期文档补充 onRemove
- example/calendar/plg.json: 版本对齐
2026-08-02 13:33:25 +08:00
62447e3952
plugindev: generate go.mod without local absolute replace; auto-download SDK module on first build
...
- init 生成的 go.mod 只 require SDK 线上版本(gitcode.com/JianFeeeee/homeagent-sdk v0.8.0),不再写本地绝对路径 replace
- build 仅在显式指定(plg.json sdk_path 或 --sdk-path)时写入 replace
- 首次构建自动执行 go mod download <sdk_module> 生成 go.sum(修复无 go.sum 构建失败)
- 修正 ensureGoMod 模块名解析(支持 require 行与 require 块)
2026-07-31 13:12:48 +08:00
bc1a005885
docs: fix plugindev install endpoint and build output; examples table; fix NewPluginFactory in bridge template
...
- README 构建与安装:输出目录为 dist/,安装端点为 pluginmgr POST /plugins(JSON 或 raw body),删除不存在的 /api/plugins/install
- 示例表:weather/luademo 新增、qq 更新 17 工具(补入 2b54814 未提交部分)
- templates.go: go_init_plugin 调用 NewPluginFactory(模板插件仅导出该函数)
2026-07-31 13:00:09 +08:00
429fe9e1b9
plugindev: fall back to git clone when SDK archive download unavailable
2026-07-31 10:32:46 +08:00
87136057b1
plugindev: align Lua SDK mock with external plugin surface, refactor debug
2026-07-31 10:28:08 +08:00
c7c66b8d39
docs: 修正 plugindev 工具链描述 + 补充入口函数/Lua 插件说明 + 补全示例插件列表
2026-07-28 21:56:54 +08:00
04837f237d
plugindev: 全面 plg.json 持久化 + --replace 支持 + 文档
2026-07-25 15:47:49 +08:00
1fa3c843ab
refactor: centralize ABI metadata into meta/meta.go
...
- meta/meta.go: add ABIVersion, ABIVersionMin, 45 dispatch method IDs
- tools/plugindev/cmd_init.go: cabiVersion -> meta.ABIVersion
- tools/plugindev/templates.go: C header comments reference meta.go
2026-07-25 14:42:32 +08:00
cb7999ca71
feat: sdk NoMemory/Cleaner + example build fixes
...
- sdk/plugin.go: ToolDef adds NoMemory/Cleaner fields
- sdk/plugin_test.go: unit tests for NoMemory/Cleaner
- all example plugins: NoMemory/Cleaner annotated for each tool
- plugindev/templates.go: template shows NoMemory/Cleaner pattern
- plugindev/cmd_build.go: fix ensureGoMod, buildBundle/buildTarget sdkPath param, NewPluginFactory
- example/go.mod: add external dependency declarations (chromedp, gofeed)
- add main.go stubs for all example plugins
2026-07-25 11:17:21 +08:00
95dad649a8
feat: sdk install downloads from Release archive instead of git clone
...
- Replace git clone --branch with HTTP download from GitCode archive URL
- No git dependency needed for SDK installation
- Extracts tar.gz archive in-memory, strips top-level directory
- Fallback for 'latest' still uses git ls-remote (lightweight)
2026-07-20 11:50:55 +08:00
1834a66bff
feat: plugindev build --bundle for multi-platform .hmap
...
- resolveBuild: use plugin.dylib for darwin (was plugin.so)
- --bundle flag: build linux/amd64 + darwin/amd64 + windows/amd64,
package all binaries into a single .hmap with platforms field
- writePluginJSON: accept platforms []string for bundle manifest
- add createBundleHmap for zip entries with custom names
- add PlgConfig.IsLua() helper
2026-07-19 12:05:42 +08:00
4f9e064721
fix: read SDK version from meta/meta.go for plugin go.mod
...
- detectSDKInfo now returns SDK version from meta/meta.go
- Generated plugin go.mod uses real version (v0.7.1) instead of v0.0.0
- Tag v0.7.1 created for SDK version management
2026-07-19 11:17:42 +08:00
49d19fb13c
feat: plugindev sdk version management subcommand
...
- Add 'plugindev sdk' subcommand with list/install/use/path/current/latest
- Replace runtime.Caller(0) path detection with managed SDK store
- SDK stored at ~/.homeagent/plugindev/sdk/<version>/
- Active version tracked via current file
- Lazy initialization to avoid blocking other subcommands
2026-07-19 11:14:27 +08:00
1762f0c34b
docs: 修正全部文档使其与源码实现一致
...
- Plugin.Start(sdk *PluginSDK) 接口签名改为指针
- 方法表重写: 移除 CallLLM/QueryKnowledge/SetMemory 等不存在方法
- IOInjector 参数顺序修正为 (source, channel, text)
- 删除虚构 SDKConfig, 替换为实际 New() 构造函数签名
- .hmap 内容描述一致化 (plugin.so + plugin.dll + main.lua)
- 添加 meta/ 包元数据文件
2026-07-18 20:47:17 +08:00