排障速查
按你看到的症状查。每条给最可能原因 → 验证方法 → 修法。
插件根本没出现(图标/菜单/类型都没有)
Section titled “插件根本没出现(图标/菜单/类型都没有)”- manifest 不合法(最常见)。宿主对坏 manifest 的策略是跳过并打日志,不报错弹窗:
校验规则:
Terminal window # 打包应用日志在 ~/.XH-Editor/logs/;源码 dev 直接看终端输出tail -F ~/.XH-Editor/logs/*.log | grep -i "skip.*plugin.json"id/name/version必填;runtime只认node/static;node 必须有entry;static 必须有ui;capabilities必须是数组。JSON 语法错误(尾逗号!)同样中招。 - 目录位置不对——插件目录(含 plugin.json 的那层)要直接位于
~/xinghan/plugins/下,别多套一层。 - 同 id 被抢——源码根优先于安装目录,同 id”先见者胜”。日志里会有一行”重复…跳过”。
- 改完 manifest 没重启/reload —— manifest 只在加载时读。
iframe 白屏
Section titled “iframe 白屏”- entry 路径错:
entry相对插件根,检查文件真实存在(ui/index.htmlvsui/dist/index.html是高频笔误); - 构建产物用了绝对路径资源:iframe 服务在
/plugins/<id>/ui/下,vite 构建记得base: './'(相对引用),否则 JS/CSS 404; - 页面自己抛错了 —— 开发者工具 Console 选中你的 iframe 上下文看报错;
devUiUrl指着一个没起的 dev server —— 反代 502。删掉该字段或把 vite 起起来。
context 一直不到(getContext() 全 null)
Section titled “context 一直不到(getContext() 全 null)”- 忘了
installContextBridge()—— 必须在监听之前装(幂等,入口顶部调一次); - 只在启动时读了一次 —— context 是 iframe load 后宿主 rAF 异步推送的,首次读很可能是空。正确姿势:
onContextChange(init)+ 立即调一次init(),在 init 里判字段就绪(参照 json-field 的waitForContext封装); - 后台窗口打开的页面 rAF 可能延迟 —— 同样由 ②的写法覆盖。
capability 调用被拒
Section titled “capability 调用被拒”- 访问卫星项目 403 → 需要
satellite:<kind>声明(如 Agent 会话库要satellite:agent)—— 这是当前唯一按 manifest 声明强制拦截的面; - 表视图里写数据被拒 →
tableViews声明里没开对应writes档,或写的不是本视图挂载的表(宿主锁表,传别的 tableNodeId 一律拒); - skill 工具里写数据 → v1 跨进程工具只放行 readonly,这是能力层强制,改声明也没用。
写入报错/不生效
Section titled “写入报错/不生效”- 值形状错:单选写了选项文字而不是选项 id;日期写了 ISO 串而不是毫秒时间戳。先
getFields看目标字段type与properties; - 超尺寸护栏:单值默认 256KB 上限(cell/表视图写入)。大内容走资产库存引用;
- 自动化节点返回值超 256KB → 用
ctx.uploadResultAsset传引用。
右键菜单点了没反应
Section titled “右键菜单点了没反应”- 插件视图打开了但没收到消息 —— 检查 message 监听的
msg.type === 'command'与commandId拼写是否和 manifest 的id一致; - 声明的
points和实际右键的位置不匹配(table.rows≠table.cells); - modal 形态:context 走上下文桥(
getContext()里有modalId与选区),不是 command 消息 —— 两种打开方式的接收通道不同。
主题/语言不跟随
Section titled “主题/语言不跟随”- 颜色不变:忘装
installThemeBridge(),或 CSS 写死了 hex; - 首帧闪白/闪黑:语义变量没给 fallback(
var(--background, #fff)); - 语言不对:用了
navigator.language(那是操作系统语言)—— 改读getContext().locale,并在onContextChange里响应切换。
自动化节点不出现/执行失败
Section titled “自动化节点不出现/执行失败”- 面板里没有你的节点:manifest 校验失败(回到第一节查日志),或
configSchema里dependsOn指向了不存在的字段 key; - 执行分类为 plugin_error:
execute抛错了,错误文案在跑历史里 —— 写人话,用户和你都靠它排障; - dryRun 没进来:没声明
execution.supportsDryRun(缺省宿主直接跳过你)。
还查不出来?
Section titled “还查不出来?”curl http://127.0.0.1:<port>/_internal/reload?id=<你的id>(POST)看对账结果里你的插件在 added/reloaded 还是没出现;- node 插件加
/healthz端点自检进程活没活; - 对照完整示例做二分:把示例原样放进去能跑,说明环境没问题,问题在你的插件里。