JJianFeeeeefeat(sdk): 22 个示例插件配齐 skill + 三态启动声明 + 打包期校验
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) (#3) * feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) ## 是什么 agent 统筹开发流程的插件:登记项目 → 开工程线(每条线一个隔离工作目录 + 一个 sidecar 子进程 + 一对通道)→ 投递任务 → 同会话续投 → 评审/合入。 38 个工具:project_*/branch_*/workdir_*/job_*/review_*/test_*/ endpoint_*/agent_*/pi_*/conflict_check。 ## sidecar 后端抽象(本轮核心) 传输层(local/ssh)与后端(pi/zcode/自定义)**正交**,四个自由组合: driver.json 描述一个后端:script / cliPath / env / args / llmConfig 三级查找:插件数据目录 → **随包 rawfile** → 内置 pi 描述 占位符:{workdir} {dataDir} {pluginDir} {rawfile} {sessionId} ★ 内置 pi 回退**与默认后端解耦**(2026-10-17 修):原实现写 if cli == defaultAgentCLI { return builtinPiDriver() },把"给谁兜底" 和"默认选谁"耦合到同一常量 —— 一旦有人改默认,pi 当场失去兜底, 显式 cli="pi" 开始报「驱动不存在」。现在判断字面 "pi"。 默认后端保持 **pi**(我们本地主用);交付方用 zcode 走两种局部开关: · 单线:commondev_branch_open(cli="zcode") · 按机器:commondev_endpoint_set(host=..., cli="zcode") ## zcode 接入(三条真机判据,全部要求真改工程文件) · TestZcodeFullPipeline(29-34s):随包 driver + 真实 ZCode CLI · TestZcodeOverSSH(39s):真 ssh + scp,远端 node 跑 zcode · TestZcodeOverSSHWithPerHostEndpoints(68s):两个 host 别名配不同 cli_path,走端点表而不是全局 settings ★ 会话库必须隔离到工作区(sidecar.mjs 的 ensureWorkspaceSessionStore): 实测 ZCode 的会话库路径**硬编码 homedir()**,ZCODE_DATA_BASE_DIR 对它 完全无效(26 个会话全落全局库)。但 <workdir>/.zcode/config.json 的 storage.sessionDbPath **确实生效**。所以启动前写一份工作区配置, 一举解决:多线不共用历史 / 不污染全局 ~/.zcode / 删线不留孤儿会话。 只在不存在时写 —— 用户手工放的要尊重。 ## 其他 · rawfile:项目根 rawfile/ 默认全收,解到 <插件目录>/rawfile/,绝对路径拒绝 · 凭证:命名引用 + ${ENV_VAR},独立 0600 文件,绝不进 config.db(0644) · secretshell:给不受信 agent 用的安全 shell(ackey + safeshell) · 冲突检查 / 评审判据 / 镜像 / 每条线独立 workdir(hash 命名,合并后删除) 判据 30+ 条,含 4 条「判据本身的判据」(防止判据假绿)。 * fix(sdk): 协议通道纪律 + hmapdev 模板升级 + 示例插件 stdout 污染 ## 核心缺陷:插件往 stdout 打日志 = 污染 JSON-RPC 协议通道 子进程插件与内核用 stdout 传 NDJSON 帧,stderr 才是日志通道。 脚手架模板(及 4 个示例插件)用 fmt.Printf 打日志 ⇒ 内核收到非 JSON 文本: [proc] weather 收到非法 JSON 帧(21 字节): invalid character 'i' **生产实测 1038 条**(huawei_smarthome 720 / weather 113 / rss 103 / calendar 102)。 后果不只是日志噪音:那一行日志被**丢弃**,插件看起来"没启动"。 修法: - hmapdev 模板 fmt.Printf → log.Printf(9 处) - 示例插件 4 个 14 处:ai_image(2) calendar(5) rss(4) weather(3) + 补 "log" import - 内核侧(主仓)同步让报错可定位:内容摘要 + 可能原因 + 修法 判别法:package main = 子进程(协议通道,禁用 stdout 打日志); 普通库包 = 进程内插件(编译进内核,写真实终端,**不是**缺陷)—— internal/plugins/cli 的 fmt.Println 属后者。 ## hmapdev - cmd_build.go +136:平台产物精确匹配(--target 是**append** 语义, 原脚本 ls dist/*.hmap | head -1 会按字典序抓到 amd64, **导致 arm64 包里装的是 x86-64 二进制**,且退出码 0、校验和通过) - cmd_init.go +46:脚手架 stdio 纪律 - templates/proc_main.go.tmpl:补齐 mgrStop/mgrStart/mgrIsRuntimeStopped 三态能力(插件管理器运行态停启) - templates/plg.json.tmpl 删除(合并进 cmd_init) ## 判据 - scaffold_stdout_test.go(3 条):扫模板生成的代码不得写 stdout。 ★ 判据自身先假红过一次:**模板的注释里就写了 fmt.Printf** ⇒ 必须 stripTemplateComments() 之后才判 - example_stdout_test.go(2 条):扫全部 20 个子进程示例插件, 报错给**文件:行号**;变异咬住并给出准确行号 - package_examples_test.go(2 条):**执行真实打包脚本** (第一版测的是 hmapdev 而不是脚本 ⇒ 变异不咬) - cmd_build / cmd_init 新判据 ## 其他 - sdk/settings.go +15(三态能力透传) - docs/versions.md +§示例插件协议通道纪律(含生产 1038 条实测表格) - skills/homeagent-plugin-dev/SKILL.md +§协议通道纪律(正误代码对比) * fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红) CI 上 Examples (linux/amd64) 与 (darwin/arm64) 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 git add -A,把本机 go build **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 "sdk": "1.4.0"** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · TestExampleGoModHasNoAbsoluteReplace:任何示例 go.mod 不得含 /root/、/home/、/Users/、C:\ · TestExampleGoModUsesRelativeSDKReplace:replace 必须是相对路径 ../../ · TestExamplePlgJsonDoesNotPinSDKVersion:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 package/build-examples.sh: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, proxy.golang.org 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 git add -A 会把「构建工具自动改写的文件」一起提交。 提交前必须 git status 逐个看,尤其 go.mod / go.sum。 --------- Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com> | 10 天前 | |
feat(sdk): 22 个示例插件配齐 skill + 三态启动声明 + 打包期校验 ## 用户的三条要求 1. 「所有插件都默认自启会占启动时间,还在 llms 上下文塞大量工具」 ⇒ 纯工具型改为按需加载,靠 skill 让 agent 知道要先拉起。 2. 「会向 agent 注入输入的部分插件不能这样做」 ⇒ 9 个必须常驻,其余 13 个按需。 3. 「sdk 是不是没有暴露插件声明自身行为的方案」 ⇒ 对:auto_start 只在 internal/plugin/manifest.go 有,SDK 零命中。 ## 定级依据(代码证据,不是猜描述) 注入 / 钩子 ⇒ 必须常驻(9 个): qq HTTP 监听 NapCat 推送,消息到达要立刻注入 rss 轮询订阅源,新文章主动推送 calendar 30s ticker 检查提醒 memo 5min ticker 检查待办到期 a2a TCP 监听外部 Agent 请求 acp TCP 监听 ACP 客户端 browser ticker + 长命令完成回调 sanitizer 注册 stage 钩子(无工具,要每轮生效) luademo 注册 stage 钩子做示范 纯工具型 ⇒ 按需(13 个): weather ocr music bili ai_image files editdoc deepsearch plugindev recoverydiag vanblog vikunja commondev ★ commondev 值得单独说:它虽然有 6 处 Inject 调用,但**注入源是自己的 sidecar 完成回投**,而 sidecar 只在 commondev_agent_up 时才拉起 (Start() 里不启 sidecar,通道也在 agent_up 时才注册)。所以没有 agent 调用它时,它不需要做任何事 —— 可以按需。44 个工具 ≈726 tokens 省下来可观。 ## 改动 · 22 个插件各配一个 skill,写明:何时用、先 plugin_start、 工具清单、**用 plugin_stop 而不是 plugin_disable** · 13 个 plg.json 加 auto_start: false · sdk/autostart.go:把三态语义与"按需插件必须有 skill"的理由写进公开 SDK · hmapdev 打包期校验:auto_start=false 但无 skill/ 目录 ⇒ 直接 exit 1 (理由:缺 skill 的按需插件**等价于没装**,比没装更糟 —— 占着磁盘让人以为可用) · 修 Lua 打包路径:它**完全不走** rawfile/skill 收集,luademo 的 skill 永远打不进去 · 修 build-examples.sh:原来 [ ! -x ] 判"二进制在不在",改了 hmapdev 源码后 重新打包**仍用旧工具链**(实测:luademo 的 skill 一直是 0) · 补 mocksdk.ToolDef.Timeout(上一轮加 ToolDef.Timeout 时漏了镜像) ## 判据 · TestHasSkillDirRequiresRealSkillMd(空目录/.gitkeep/无 SKILL.md 都不算) · TestBuildRejectsOnDemandWithoutSkill(打包期必须真拦住 + exit 1) · TestLuaPackagingCollectsSkillAndRawfiles(**验代码行**,不验注释 —— 第一版 只查符号存在,把 createHmapWithRaw 换回 createHmap 判据照样通过) ## 踩过的坑 · Lua 分支的结束边界原是 // Resolve build config,但那个注释在文件里 **出现多次**(Go 路径里也有),用它截取会把 Go 分支一起包进来 ⇒ 变异测不出。改成截到 Lua 分支自己的 return + }。 | 9 天前 | |
feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) (#3) * feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) ## 是什么 agent 统筹开发流程的插件:登记项目 → 开工程线(每条线一个隔离工作目录 + 一个 sidecar 子进程 + 一对通道)→ 投递任务 → 同会话续投 → 评审/合入。 38 个工具:project_*/branch_*/workdir_*/job_*/review_*/test_*/ endpoint_*/agent_*/pi_*/conflict_check。 ## sidecar 后端抽象(本轮核心) 传输层(local/ssh)与后端(pi/zcode/自定义)**正交**,四个自由组合: driver.json 描述一个后端:script / cliPath / env / args / llmConfig 三级查找:插件数据目录 → **随包 rawfile** → 内置 pi 描述 占位符:{workdir} {dataDir} {pluginDir} {rawfile} {sessionId} ★ 内置 pi 回退**与默认后端解耦**(2026-10-17 修):原实现写 if cli == defaultAgentCLI { return builtinPiDriver() },把"给谁兜底" 和"默认选谁"耦合到同一常量 —— 一旦有人改默认,pi 当场失去兜底, 显式 cli="pi" 开始报「驱动不存在」。现在判断字面 "pi"。 默认后端保持 **pi**(我们本地主用);交付方用 zcode 走两种局部开关: · 单线:commondev_branch_open(cli="zcode") · 按机器:commondev_endpoint_set(host=..., cli="zcode") ## zcode 接入(三条真机判据,全部要求真改工程文件) · TestZcodeFullPipeline(29-34s):随包 driver + 真实 ZCode CLI · TestZcodeOverSSH(39s):真 ssh + scp,远端 node 跑 zcode · TestZcodeOverSSHWithPerHostEndpoints(68s):两个 host 别名配不同 cli_path,走端点表而不是全局 settings ★ 会话库必须隔离到工作区(sidecar.mjs 的 ensureWorkspaceSessionStore): 实测 ZCode 的会话库路径**硬编码 homedir()**,ZCODE_DATA_BASE_DIR 对它 完全无效(26 个会话全落全局库)。但 <workdir>/.zcode/config.json 的 storage.sessionDbPath **确实生效**。所以启动前写一份工作区配置, 一举解决:多线不共用历史 / 不污染全局 ~/.zcode / 删线不留孤儿会话。 只在不存在时写 —— 用户手工放的要尊重。 ## 其他 · rawfile:项目根 rawfile/ 默认全收,解到 <插件目录>/rawfile/,绝对路径拒绝 · 凭证:命名引用 + ${ENV_VAR},独立 0600 文件,绝不进 config.db(0644) · secretshell:给不受信 agent 用的安全 shell(ackey + safeshell) · 冲突检查 / 评审判据 / 镜像 / 每条线独立 workdir(hash 命名,合并后删除) 判据 30+ 条,含 4 条「判据本身的判据」(防止判据假绿)。 * fix(sdk): 协议通道纪律 + hmapdev 模板升级 + 示例插件 stdout 污染 ## 核心缺陷:插件往 stdout 打日志 = 污染 JSON-RPC 协议通道 子进程插件与内核用 stdout 传 NDJSON 帧,stderr 才是日志通道。 脚手架模板(及 4 个示例插件)用 fmt.Printf 打日志 ⇒ 内核收到非 JSON 文本: [proc] weather 收到非法 JSON 帧(21 字节): invalid character 'i' **生产实测 1038 条**(huawei_smarthome 720 / weather 113 / rss 103 / calendar 102)。 后果不只是日志噪音:那一行日志被**丢弃**,插件看起来"没启动"。 修法: - hmapdev 模板 fmt.Printf → log.Printf(9 处) - 示例插件 4 个 14 处:ai_image(2) calendar(5) rss(4) weather(3) + 补 "log" import - 内核侧(主仓)同步让报错可定位:内容摘要 + 可能原因 + 修法 判别法:package main = 子进程(协议通道,禁用 stdout 打日志); 普通库包 = 进程内插件(编译进内核,写真实终端,**不是**缺陷)—— internal/plugins/cli 的 fmt.Println 属后者。 ## hmapdev - cmd_build.go +136:平台产物精确匹配(--target 是**append** 语义, 原脚本 ls dist/*.hmap | head -1 会按字典序抓到 amd64, **导致 arm64 包里装的是 x86-64 二进制**,且退出码 0、校验和通过) - cmd_init.go +46:脚手架 stdio 纪律 - templates/proc_main.go.tmpl:补齐 mgrStop/mgrStart/mgrIsRuntimeStopped 三态能力(插件管理器运行态停启) - templates/plg.json.tmpl 删除(合并进 cmd_init) ## 判据 - scaffold_stdout_test.go(3 条):扫模板生成的代码不得写 stdout。 ★ 判据自身先假红过一次:**模板的注释里就写了 fmt.Printf** ⇒ 必须 stripTemplateComments() 之后才判 - example_stdout_test.go(2 条):扫全部 20 个子进程示例插件, 报错给**文件:行号**;变异咬住并给出准确行号 - package_examples_test.go(2 条):**执行真实打包脚本** (第一版测的是 hmapdev 而不是脚本 ⇒ 变异不咬) - cmd_build / cmd_init 新判据 ## 其他 - sdk/settings.go +15(三态能力透传) - docs/versions.md +§示例插件协议通道纪律(含生产 1038 条实测表格) - skills/homeagent-plugin-dev/SKILL.md +§协议通道纪律(正误代码对比) * fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红) CI 上 Examples (linux/amd64) 与 (darwin/arm64) 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 git add -A,把本机 go build **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 "sdk": "1.4.0"** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · TestExampleGoModHasNoAbsoluteReplace:任何示例 go.mod 不得含 /root/、/home/、/Users/、C:\ · TestExampleGoModUsesRelativeSDKReplace:replace 必须是相对路径 ../../ · TestExamplePlgJsonDoesNotPinSDKVersion:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 package/build-examples.sh: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, proxy.golang.org 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 git add -A 会把「构建工具自动改写的文件」一起提交。 提交前必须 git status 逐个看,尤其 go.mod / go.sum。 --------- Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com> | 10 天前 | |
chore(module)!: module 路径随托管地迁移 gitcode → github 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 产物 | 18 天前 | |
feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) (#3) * feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) ## 是什么 agent 统筹开发流程的插件:登记项目 → 开工程线(每条线一个隔离工作目录 + 一个 sidecar 子进程 + 一对通道)→ 投递任务 → 同会话续投 → 评审/合入。 38 个工具:project_*/branch_*/workdir_*/job_*/review_*/test_*/ endpoint_*/agent_*/pi_*/conflict_check。 ## sidecar 后端抽象(本轮核心) 传输层(local/ssh)与后端(pi/zcode/自定义)**正交**,四个自由组合: driver.json 描述一个后端:script / cliPath / env / args / llmConfig 三级查找:插件数据目录 → **随包 rawfile** → 内置 pi 描述 占位符:{workdir} {dataDir} {pluginDir} {rawfile} {sessionId} ★ 内置 pi 回退**与默认后端解耦**(2026-10-17 修):原实现写 if cli == defaultAgentCLI { return builtinPiDriver() },把"给谁兜底" 和"默认选谁"耦合到同一常量 —— 一旦有人改默认,pi 当场失去兜底, 显式 cli="pi" 开始报「驱动不存在」。现在判断字面 "pi"。 默认后端保持 **pi**(我们本地主用);交付方用 zcode 走两种局部开关: · 单线:commondev_branch_open(cli="zcode") · 按机器:commondev_endpoint_set(host=..., cli="zcode") ## zcode 接入(三条真机判据,全部要求真改工程文件) · TestZcodeFullPipeline(29-34s):随包 driver + 真实 ZCode CLI · TestZcodeOverSSH(39s):真 ssh + scp,远端 node 跑 zcode · TestZcodeOverSSHWithPerHostEndpoints(68s):两个 host 别名配不同 cli_path,走端点表而不是全局 settings ★ 会话库必须隔离到工作区(sidecar.mjs 的 ensureWorkspaceSessionStore): 实测 ZCode 的会话库路径**硬编码 homedir()**,ZCODE_DATA_BASE_DIR 对它 完全无效(26 个会话全落全局库)。但 <workdir>/.zcode/config.json 的 storage.sessionDbPath **确实生效**。所以启动前写一份工作区配置, 一举解决:多线不共用历史 / 不污染全局 ~/.zcode / 删线不留孤儿会话。 只在不存在时写 —— 用户手工放的要尊重。 ## 其他 · rawfile:项目根 rawfile/ 默认全收,解到 <插件目录>/rawfile/,绝对路径拒绝 · 凭证:命名引用 + ${ENV_VAR},独立 0600 文件,绝不进 config.db(0644) · secretshell:给不受信 agent 用的安全 shell(ackey + safeshell) · 冲突检查 / 评审判据 / 镜像 / 每条线独立 workdir(hash 命名,合并后删除) 判据 30+ 条,含 4 条「判据本身的判据」(防止判据假绿)。 * fix(sdk): 协议通道纪律 + hmapdev 模板升级 + 示例插件 stdout 污染 ## 核心缺陷:插件往 stdout 打日志 = 污染 JSON-RPC 协议通道 子进程插件与内核用 stdout 传 NDJSON 帧,stderr 才是日志通道。 脚手架模板(及 4 个示例插件)用 fmt.Printf 打日志 ⇒ 内核收到非 JSON 文本: [proc] weather 收到非法 JSON 帧(21 字节): invalid character 'i' **生产实测 1038 条**(huawei_smarthome 720 / weather 113 / rss 103 / calendar 102)。 后果不只是日志噪音:那一行日志被**丢弃**,插件看起来"没启动"。 修法: - hmapdev 模板 fmt.Printf → log.Printf(9 处) - 示例插件 4 个 14 处:ai_image(2) calendar(5) rss(4) weather(3) + 补 "log" import - 内核侧(主仓)同步让报错可定位:内容摘要 + 可能原因 + 修法 判别法:package main = 子进程(协议通道,禁用 stdout 打日志); 普通库包 = 进程内插件(编译进内核,写真实终端,**不是**缺陷)—— internal/plugins/cli 的 fmt.Println 属后者。 ## hmapdev - cmd_build.go +136:平台产物精确匹配(--target 是**append** 语义, 原脚本 ls dist/*.hmap | head -1 会按字典序抓到 amd64, **导致 arm64 包里装的是 x86-64 二进制**,且退出码 0、校验和通过) - cmd_init.go +46:脚手架 stdio 纪律 - templates/proc_main.go.tmpl:补齐 mgrStop/mgrStart/mgrIsRuntimeStopped 三态能力(插件管理器运行态停启) - templates/plg.json.tmpl 删除(合并进 cmd_init) ## 判据 - scaffold_stdout_test.go(3 条):扫模板生成的代码不得写 stdout。 ★ 判据自身先假红过一次:**模板的注释里就写了 fmt.Printf** ⇒ 必须 stripTemplateComments() 之后才判 - example_stdout_test.go(2 条):扫全部 20 个子进程示例插件, 报错给**文件:行号**;变异咬住并给出准确行号 - package_examples_test.go(2 条):**执行真实打包脚本** (第一版测的是 hmapdev 而不是脚本 ⇒ 变异不咬) - cmd_build / cmd_init 新判据 ## 其他 - sdk/settings.go +15(三态能力透传) - docs/versions.md +§示例插件协议通道纪律(含生产 1038 条实测表格) - skills/homeagent-plugin-dev/SKILL.md +§协议通道纪律(正误代码对比) * fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红) CI 上 Examples (linux/amd64) 与 (darwin/arm64) 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 git add -A,把本机 go build **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 "sdk": "1.4.0"** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · TestExampleGoModHasNoAbsoluteReplace:任何示例 go.mod 不得含 /root/、/home/、/Users/、C:\ · TestExampleGoModUsesRelativeSDKReplace:replace 必须是相对路径 ../../ · TestExamplePlgJsonDoesNotPinSDKVersion:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 package/build-examples.sh: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, proxy.golang.org 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 git add -A 会把「构建工具自动改写的文件」一起提交。 提交前必须 git status 逐个看,尤其 go.mod / go.sum。 --------- Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com> | 10 天前 | |
feat(sdk): 22 个示例插件配齐 skill + 三态启动声明 + 打包期校验 ## 用户的三条要求 1. 「所有插件都默认自启会占启动时间,还在 llms 上下文塞大量工具」 ⇒ 纯工具型改为按需加载,靠 skill 让 agent 知道要先拉起。 2. 「会向 agent 注入输入的部分插件不能这样做」 ⇒ 9 个必须常驻,其余 13 个按需。 3. 「sdk 是不是没有暴露插件声明自身行为的方案」 ⇒ 对:auto_start 只在 internal/plugin/manifest.go 有,SDK 零命中。 ## 定级依据(代码证据,不是猜描述) 注入 / 钩子 ⇒ 必须常驻(9 个): qq HTTP 监听 NapCat 推送,消息到达要立刻注入 rss 轮询订阅源,新文章主动推送 calendar 30s ticker 检查提醒 memo 5min ticker 检查待办到期 a2a TCP 监听外部 Agent 请求 acp TCP 监听 ACP 客户端 browser ticker + 长命令完成回调 sanitizer 注册 stage 钩子(无工具,要每轮生效) luademo 注册 stage 钩子做示范 纯工具型 ⇒ 按需(13 个): weather ocr music bili ai_image files editdoc deepsearch plugindev recoverydiag vanblog vikunja commondev ★ commondev 值得单独说:它虽然有 6 处 Inject 调用,但**注入源是自己的 sidecar 完成回投**,而 sidecar 只在 commondev_agent_up 时才拉起 (Start() 里不启 sidecar,通道也在 agent_up 时才注册)。所以没有 agent 调用它时,它不需要做任何事 —— 可以按需。44 个工具 ≈726 tokens 省下来可观。 ## 改动 · 22 个插件各配一个 skill,写明:何时用、先 plugin_start、 工具清单、**用 plugin_stop 而不是 plugin_disable** · 13 个 plg.json 加 auto_start: false · sdk/autostart.go:把三态语义与"按需插件必须有 skill"的理由写进公开 SDK · hmapdev 打包期校验:auto_start=false 但无 skill/ 目录 ⇒ 直接 exit 1 (理由:缺 skill 的按需插件**等价于没装**,比没装更糟 —— 占着磁盘让人以为可用) · 修 Lua 打包路径:它**完全不走** rawfile/skill 收集,luademo 的 skill 永远打不进去 · 修 build-examples.sh:原来 [ ! -x ] 判"二进制在不在",改了 hmapdev 源码后 重新打包**仍用旧工具链**(实测:luademo 的 skill 一直是 0) · 补 mocksdk.ToolDef.Timeout(上一轮加 ToolDef.Timeout 时漏了镜像) ## 判据 · TestHasSkillDirRequiresRealSkillMd(空目录/.gitkeep/无 SKILL.md 都不算) · TestBuildRejectsOnDemandWithoutSkill(打包期必须真拦住 + exit 1) · TestLuaPackagingCollectsSkillAndRawfiles(**验代码行**,不验注释 —— 第一版 只查符号存在,把 createHmapWithRaw 换回 createHmap 判据照样通过) ## 踩过的坑 · Lua 分支的结束边界原是 // Resolve build config,但那个注释在文件里 **出现多次**(Go 路径里也有),用它截取会把 Go 分支一起包进来 ⇒ 变异测不出。改成截到 Lua 分支自己的 return + }。 | 9 天前 | |
feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) (#3) * feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) ## 是什么 agent 统筹开发流程的插件:登记项目 → 开工程线(每条线一个隔离工作目录 + 一个 sidecar 子进程 + 一对通道)→ 投递任务 → 同会话续投 → 评审/合入。 38 个工具:project_*/branch_*/workdir_*/job_*/review_*/test_*/ endpoint_*/agent_*/pi_*/conflict_check。 ## sidecar 后端抽象(本轮核心) 传输层(local/ssh)与后端(pi/zcode/自定义)**正交**,四个自由组合: driver.json 描述一个后端:script / cliPath / env / args / llmConfig 三级查找:插件数据目录 → **随包 rawfile** → 内置 pi 描述 占位符:{workdir} {dataDir} {pluginDir} {rawfile} {sessionId} ★ 内置 pi 回退**与默认后端解耦**(2026-10-17 修):原实现写 if cli == defaultAgentCLI { return builtinPiDriver() },把"给谁兜底" 和"默认选谁"耦合到同一常量 —— 一旦有人改默认,pi 当场失去兜底, 显式 cli="pi" 开始报「驱动不存在」。现在判断字面 "pi"。 默认后端保持 **pi**(我们本地主用);交付方用 zcode 走两种局部开关: · 单线:commondev_branch_open(cli="zcode") · 按机器:commondev_endpoint_set(host=..., cli="zcode") ## zcode 接入(三条真机判据,全部要求真改工程文件) · TestZcodeFullPipeline(29-34s):随包 driver + 真实 ZCode CLI · TestZcodeOverSSH(39s):真 ssh + scp,远端 node 跑 zcode · TestZcodeOverSSHWithPerHostEndpoints(68s):两个 host 别名配不同 cli_path,走端点表而不是全局 settings ★ 会话库必须隔离到工作区(sidecar.mjs 的 ensureWorkspaceSessionStore): 实测 ZCode 的会话库路径**硬编码 homedir()**,ZCODE_DATA_BASE_DIR 对它 完全无效(26 个会话全落全局库)。但 <workdir>/.zcode/config.json 的 storage.sessionDbPath **确实生效**。所以启动前写一份工作区配置, 一举解决:多线不共用历史 / 不污染全局 ~/.zcode / 删线不留孤儿会话。 只在不存在时写 —— 用户手工放的要尊重。 ## 其他 · rawfile:项目根 rawfile/ 默认全收,解到 <插件目录>/rawfile/,绝对路径拒绝 · 凭证:命名引用 + ${ENV_VAR},独立 0600 文件,绝不进 config.db(0644) · secretshell:给不受信 agent 用的安全 shell(ackey + safeshell) · 冲突检查 / 评审判据 / 镜像 / 每条线独立 workdir(hash 命名,合并后删除) 判据 30+ 条,含 4 条「判据本身的判据」(防止判据假绿)。 * fix(sdk): 协议通道纪律 + hmapdev 模板升级 + 示例插件 stdout 污染 ## 核心缺陷:插件往 stdout 打日志 = 污染 JSON-RPC 协议通道 子进程插件与内核用 stdout 传 NDJSON 帧,stderr 才是日志通道。 脚手架模板(及 4 个示例插件)用 fmt.Printf 打日志 ⇒ 内核收到非 JSON 文本: [proc] weather 收到非法 JSON 帧(21 字节): invalid character 'i' **生产实测 1038 条**(huawei_smarthome 720 / weather 113 / rss 103 / calendar 102)。 后果不只是日志噪音:那一行日志被**丢弃**,插件看起来"没启动"。 修法: - hmapdev 模板 fmt.Printf → log.Printf(9 处) - 示例插件 4 个 14 处:ai_image(2) calendar(5) rss(4) weather(3) + 补 "log" import - 内核侧(主仓)同步让报错可定位:内容摘要 + 可能原因 + 修法 判别法:package main = 子进程(协议通道,禁用 stdout 打日志); 普通库包 = 进程内插件(编译进内核,写真实终端,**不是**缺陷)—— internal/plugins/cli 的 fmt.Println 属后者。 ## hmapdev - cmd_build.go +136:平台产物精确匹配(--target 是**append** 语义, 原脚本 ls dist/*.hmap | head -1 会按字典序抓到 amd64, **导致 arm64 包里装的是 x86-64 二进制**,且退出码 0、校验和通过) - cmd_init.go +46:脚手架 stdio 纪律 - templates/proc_main.go.tmpl:补齐 mgrStop/mgrStart/mgrIsRuntimeStopped 三态能力(插件管理器运行态停启) - templates/plg.json.tmpl 删除(合并进 cmd_init) ## 判据 - scaffold_stdout_test.go(3 条):扫模板生成的代码不得写 stdout。 ★ 判据自身先假红过一次:**模板的注释里就写了 fmt.Printf** ⇒ 必须 stripTemplateComments() 之后才判 - example_stdout_test.go(2 条):扫全部 20 个子进程示例插件, 报错给**文件:行号**;变异咬住并给出准确行号 - package_examples_test.go(2 条):**执行真实打包脚本** (第一版测的是 hmapdev 而不是脚本 ⇒ 变异不咬) - cmd_build / cmd_init 新判据 ## 其他 - sdk/settings.go +15(三态能力透传) - docs/versions.md +§示例插件协议通道纪律(含生产 1038 条实测表格) - skills/homeagent-plugin-dev/SKILL.md +§协议通道纪律(正误代码对比) * fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红) CI 上 Examples (linux/amd64) 与 (darwin/arm64) 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 git add -A,把本机 go build **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 "sdk": "1.4.0"** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · TestExampleGoModHasNoAbsoluteReplace:任何示例 go.mod 不得含 /root/、/home/、/Users/、C:\ · TestExampleGoModUsesRelativeSDKReplace:replace 必须是相对路径 ../../ · TestExamplePlgJsonDoesNotPinSDKVersion:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 package/build-examples.sh: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, proxy.golang.org 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 git add -A 会把「构建工具自动改写的文件」一起提交。 提交前必须 git status 逐个看,尤其 go.mod / go.sum。 --------- Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com> | 10 天前 | |
feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) (#3) * feat(commondev): 主管式多仓库开发流水线 + sidecar 后端抽象(pi/zcode) ## 是什么 agent 统筹开发流程的插件:登记项目 → 开工程线(每条线一个隔离工作目录 + 一个 sidecar 子进程 + 一对通道)→ 投递任务 → 同会话续投 → 评审/合入。 38 个工具:project_*/branch_*/workdir_*/job_*/review_*/test_*/ endpoint_*/agent_*/pi_*/conflict_check。 ## sidecar 后端抽象(本轮核心) 传输层(local/ssh)与后端(pi/zcode/自定义)**正交**,四个自由组合: driver.json 描述一个后端:script / cliPath / env / args / llmConfig 三级查找:插件数据目录 → **随包 rawfile** → 内置 pi 描述 占位符:{workdir} {dataDir} {pluginDir} {rawfile} {sessionId} ★ 内置 pi 回退**与默认后端解耦**(2026-10-17 修):原实现写 if cli == defaultAgentCLI { return builtinPiDriver() },把"给谁兜底" 和"默认选谁"耦合到同一常量 —— 一旦有人改默认,pi 当场失去兜底, 显式 cli="pi" 开始报「驱动不存在」。现在判断字面 "pi"。 默认后端保持 **pi**(我们本地主用);交付方用 zcode 走两种局部开关: · 单线:commondev_branch_open(cli="zcode") · 按机器:commondev_endpoint_set(host=..., cli="zcode") ## zcode 接入(三条真机判据,全部要求真改工程文件) · TestZcodeFullPipeline(29-34s):随包 driver + 真实 ZCode CLI · TestZcodeOverSSH(39s):真 ssh + scp,远端 node 跑 zcode · TestZcodeOverSSHWithPerHostEndpoints(68s):两个 host 别名配不同 cli_path,走端点表而不是全局 settings ★ 会话库必须隔离到工作区(sidecar.mjs 的 ensureWorkspaceSessionStore): 实测 ZCode 的会话库路径**硬编码 homedir()**,ZCODE_DATA_BASE_DIR 对它 完全无效(26 个会话全落全局库)。但 <workdir>/.zcode/config.json 的 storage.sessionDbPath **确实生效**。所以启动前写一份工作区配置, 一举解决:多线不共用历史 / 不污染全局 ~/.zcode / 删线不留孤儿会话。 只在不存在时写 —— 用户手工放的要尊重。 ## 其他 · rawfile:项目根 rawfile/ 默认全收,解到 <插件目录>/rawfile/,绝对路径拒绝 · 凭证:命名引用 + ${ENV_VAR},独立 0600 文件,绝不进 config.db(0644) · secretshell:给不受信 agent 用的安全 shell(ackey + safeshell) · 冲突检查 / 评审判据 / 镜像 / 每条线独立 workdir(hash 命名,合并后删除) 判据 30+ 条,含 4 条「判据本身的判据」(防止判据假绿)。 * fix(sdk): 协议通道纪律 + hmapdev 模板升级 + 示例插件 stdout 污染 ## 核心缺陷:插件往 stdout 打日志 = 污染 JSON-RPC 协议通道 子进程插件与内核用 stdout 传 NDJSON 帧,stderr 才是日志通道。 脚手架模板(及 4 个示例插件)用 fmt.Printf 打日志 ⇒ 内核收到非 JSON 文本: [proc] weather 收到非法 JSON 帧(21 字节): invalid character 'i' **生产实测 1038 条**(huawei_smarthome 720 / weather 113 / rss 103 / calendar 102)。 后果不只是日志噪音:那一行日志被**丢弃**,插件看起来"没启动"。 修法: - hmapdev 模板 fmt.Printf → log.Printf(9 处) - 示例插件 4 个 14 处:ai_image(2) calendar(5) rss(4) weather(3) + 补 "log" import - 内核侧(主仓)同步让报错可定位:内容摘要 + 可能原因 + 修法 判别法:package main = 子进程(协议通道,禁用 stdout 打日志); 普通库包 = 进程内插件(编译进内核,写真实终端,**不是**缺陷)—— internal/plugins/cli 的 fmt.Println 属后者。 ## hmapdev - cmd_build.go +136:平台产物精确匹配(--target 是**append** 语义, 原脚本 ls dist/*.hmap | head -1 会按字典序抓到 amd64, **导致 arm64 包里装的是 x86-64 二进制**,且退出码 0、校验和通过) - cmd_init.go +46:脚手架 stdio 纪律 - templates/proc_main.go.tmpl:补齐 mgrStop/mgrStart/mgrIsRuntimeStopped 三态能力(插件管理器运行态停启) - templates/plg.json.tmpl 删除(合并进 cmd_init) ## 判据 - scaffold_stdout_test.go(3 条):扫模板生成的代码不得写 stdout。 ★ 判据自身先假红过一次:**模板的注释里就写了 fmt.Printf** ⇒ 必须 stripTemplateComments() 之后才判 - example_stdout_test.go(2 条):扫全部 20 个子进程示例插件, 报错给**文件:行号**;变异咬住并给出准确行号 - package_examples_test.go(2 条):**执行真实打包脚本** (第一版测的是 hmapdev 而不是脚本 ⇒ 变异不咬) - cmd_build / cmd_init 新判据 ## 其他 - sdk/settings.go +15(三态能力透传) - docs/versions.md +§示例插件协议通道纪律(含生产 1038 条实测表格) - skills/homeagent-plugin-dev/SKILL.md +§协议通道纪律(正误代码对比) * fix(examples): 恢复 go.mod 相对路径 + 移除 plg.json 的 sdk 固定(修 CI 红) CI 上 Examples (linux/amd64) 与 (darwin/arm64) 双红,只有两个失败: ✗ commondev 构建失败 ✗ editdoc 构建失败 error: 项目声明 sdk=1.4.0,但本地 SDK 存储里没有这个版本 其余 20 个示例全部成功 —— 说明不是通用问题,而是这两个被改坏了。 ## 根因(两个叠加) **① go.mod 被本机绝对路径污染** 我在上一个提交里用 git add -A,把本机 go build **自动改写**过的 go.mod 一并提交了: require github.com/JianFeeeee/homeagentsdk v1.4.0 replace github.com/JianFeeeee/homeagentsdk => /root/.homeagent/hmapdev/sdk/v1.4.0 基线(origin/main)是: require github.com/JianFeeeee/homeagentsdk v0.0.0 replace github.com/JianFeeeee/homeagentsdk => ../../ 本机那个目录真的存在 ⇒ 本地全绿;CI 没有 ⇒ 必红。 **② plg.json 声明了 "sdk": "1.4.0"** 一声明版本,hmapdev 就去**本地 SDK store** 找它,找不到直接拒绝构建。 全仓 20+ 示例**都不声明**,只有我改过的这两个声明了。 示例的正确依赖表达是 go.mod 的 v0.0.0 + replace ../../。 ## 修法 两个文件都恢复到与其余示例一致的写法。 ## 判据(3 条,都是新加的) · TestExampleGoModHasNoAbsoluteReplace:任何示例 go.mod 不得含 /root/、/home/、/Users/、C:\ · TestExampleGoModUsesRelativeSDKReplace:replace 必须是相对路径 ../../ · TestExamplePlgJsonDoesNotPinSDKVersion:plg.json 不得声明 sdk 变异 2/2 咬住(重新引入绝对路径 / 重新声明 sdk,都准确报出文件路径)。 ## 本地验证(模拟 CI 干净环境) 用干净 HOME 跑 package/build-examples.sh: · 修复前:成功 18 / 失败 4(commondev, editdoc, browser, rss) · 修复后:成功 20 / 失败 2(browser, rss —— **本机代理不通**, proxy.golang.org 超时;用本地 modcache 验证这两个可正常构建) 即 22/22 源码都能构建,CI 有网络不受影响。 ## 教训 git add -A 会把「构建工具自动改写的文件」一起提交。 提交前必须 git status 逐个看,尤其 go.mod / go.sum。 --------- Co-authored-by: JianFeeeee <JianFeeeee@users.noreply.gitcode.com> | 10 天前 |
editdoc · 全能办公
对 .docx / .xlsx / .pptx / .xls / .csv / .md / .txt 做新建、读取、编辑、转换。
版本:v2.0.0(全能办公)。较 v1.0.0 新增
read_document、create_document、create_from_template、convert_document、office_check五个工具;edit_document的名字与全部 v1 参数保持不变,老调用不会破。
工具
| 工具 | 作用 |
|---|---|
read_document |
读为结构化 JSON(docx 段落+表格+页眉页脚 / xlsx 逐表逐格含公式与计算值 / pptx 逐页 / xls / csv / md / txt),大文件可 offset/limit 分段 |
create_document |
从零新建。docx 支持 Markdown 正文;xlsx 支持多表(表名+表头+行);pptx 用 ## 分页 |
create_from_template |
复制模板再套用替换 |
edit_document |
编辑既有文件(v1 八参数 + 查找替换/正则大小写/第 N 处/表格与单元格/图片/样式/幻灯片/dry_run) |
convert_document |
格式转换(docx↔md/pdf、xlsx↔csv 等,借助 soffice / pandoc) |
office_check |
自检:依赖库可用性与版本、外部工具、格式×能力矩阵 |
配置项
| 键 | 默认 | 说明 |
|---|---|---|
script_path |
空 | edit_doc.py 的绝对路径。留空即推荐值 —— 用内嵌脚本;仅当该文件含 v2 协议标记时才被采用,否则自动忽略并回退内嵌 |
venv_python |
空 | 执行脚本的 Python 解释器(需装 python-docx / openpyxl / python-pptx)。必须配置 |
timeout_sec |
60 | 单次调用超时;大文件或格式转换(soffice 首次启动慢)建议调到 180 |
工作原理
Go 侧只做参数编排与结构化返回,全部业务逻辑在 Python 脚本 edit_doc.py 里。
脚本是内嵌的(//go:embed embed/edit_doc.py),原因:hmapdev 打包器只把
plugin.json + plugin.bin 放进 .hmap,不打包任何资源文件。若让脚本单独
存在于 plugin_data/,就会出现「Go 侧升级了、脚本忘了换」的版本漂移。
内嵌 + 内容指纹校验使两侧永远同版本:
- 首次调用时把内嵌脚本释放到
DataDir()/runtime/edit_doc.py,并写.stamp指纹; - 插件升级后指纹变化 → 自动重新释放;
script_path显式指向的文件仅当含EDITDOC_PROTOCOL = "v2"标记时才被采用 (便于运维临时覆盖调试);否则忽略并在返回体里带script_path_ignored,让降级可见。
业务脚本只有一份:embed/edit_doc.py。不要再添加同名的顶层副本 ——
它不会被 embed,改了不生效,而两份同名文件是典型的漂移源(见
TestOnlyOneBusinessScript)。
依赖
Python 侧:python-docx、openpyxl、python-pptx(.xls 另需 xlrd)。
外部工具(可选,转换能力用):soffice(LibreOffice)、pandoc。
用 office_check 随时查看本机实际可用的能力矩阵。
构建
hmapdev build
测试
go test ./...