编写 Marketplace Plugin
Craft Hub Marketplace Plugin 是纯声明式 npm 包。Craft Hub 读取 package.json#craftHub 并校验每项贡献,不会导入插件 JavaScript。只有嵌入应用确实需要加载可信可执行代码时,才应选择 Host Plugin。
插件市场契约说明了 Manifest 与 Catalog 的全部字段。在 API 仍处于 Alpha 阶段时,runtime 导出的 pluginManifestV1Schema 是唯一事实来源。
创建插件包
交互式初始化会询问包身份、展示名称、许可证和贡献类型:
craft-hub plugin:init ./my-pluginAgent 和 CI 应使用确定性的非交互形式:
craft-hub plugin:init ./my-plugin \
--non-interactive \
--package @example/craft-hub-plugin-tools \
--display-name "Example tools" \
--license MIT \
--with-command \
--with-skill \
--with-project-template目标目录必须不存在或为空;初始化不会覆盖现有内容。包名必须采用带 scope 的 craft-hub-plugin-* 或 plugin-* 格式。包身份和许可证必须由作者明确提供,不能从 Git 或 npm 登录信息推断。
第一版作者工作流为三种贡献提供脚手架:
commands:结构化的command与args;不支持 shell 插值,执行前仍要求 Project Trust。skills:带稳定id的插件包内 Agent Skill 文件。新插件应显式声明;旧版 v1 条目未声明 ID 时保留按路径生成的标识。内容只安装一次,再按项目启用;可选的受限activation表达式用于自动匹配。projectTemplates:插件包内的项目模板目录。
发布前需要修改生成的占位内容。其他高级贡献类型暂时直接按照插件市场契约编辑,等出现真实需求后再增加专用脚手架。
声明技能自动启用条件
没有 activation 的技能只能手动启用,适合通用技能。框架或工具专用技能可以声明相关的项目事实:
{
"id": "widget-assistant",
"path": "skills/widget-assistant/SKILL.md",
"activation": {
"all": [
{ "dependency": "@example/widget" },
{ "any": [{ "file": "widget.config.ts" }, { "file": "widget.config.js" }] }
]
}
}匹配器支持 file、dependency、packageManager、all、any 和 not,且只在项目根目录和 Craft Hub 已发现的 pnpm package 中求值。自动匹配需要插件声明 read-project-files 权限;整个过程只读,不执行插件或项目代码。
添加工作项原生状态流转
Host Plugin 可以实现 workItems.transitions 与 workItems.updateStatus,Marketplace Plugin 则声明对应的 work-items.transitions 和 work-items.update-status action。当同一集成通过 work-items.get、work-items.search 或 work-items.list 展示实体时,Craft Hub 会自动提供通用状态流转控件。
Renderer 会把实体的标量 metadata 连同 itemId、标题和当前状态传回 Provider。状态候选结果负责提供 Provider 原生目标状态及必填字段名。每次更新始终属于 remote-write:Craft Hub 会展示确认对话框、拒绝未经确认的调用,并通过 context.confirmed 把宿主确认结果传给可信 Provider。
校验
校验过程只读:
craft-hub plugin:validate ./my-plugin它会检查 npm 身份与版本、当前 Manifest Schema、权限关系、包内相对路径、禁止的运行时依赖与安装生命周期脚本、Craft Hub 最低版本兼容性,以及 npm 实际会收入 tarball 的文件。命令使用 npm pack --dry-run --ignore-scripts,不会执行插件脚本。
本地测试
先通过校验,再检查绝对路径并明确执行关联:
craft-hub plugin:link /插件目录的绝对路径
craft-hub plugin:refresh @example/craft-hub-plugin-tools关联状态会持久化到操作系统的 Craft Hub 数据目录,并覆盖同名的 Marketplace 安装版本。测试结束后移除覆盖:
craft-hub plugin:unlink @example/craft-hub-plugin-tools打包并生成 Catalog Entry
Publisher 身份必须显式提供:
craft-hub plugin:pack ./my-plugin --publisher example通过校验后,Craft Hub 会在禁用脚本的情况下打包,根据真实产物计算 SHA-512 integrity,并将 tarball 和经过校验的 Catalog Entry 草稿写入 dist/。命令不会覆盖已有产物,并会打印用于审查的绝对路径;它不会发布 npm 包,也不会修改 Plugin Catalog。
Catalog 维护者仍需在合并前审查 Publisher 身份、分类、兼容范围、权限和不可变版本。npm 发布与 Catalog 签名不属于该作者命令的职责。
可运行示例
examples/marketplace-plugin 是参与仓库测试的完整参考包。插件包不得包含运行时依赖、可选依赖或 npm 安装生命周期脚本。
安装本地宿主扩展
公开与内部插件都使用同一个 Craft Hub 主程序。宿主扩展提供可执行的 provider,市场插件声明页面与操作。独立品牌的发行包只是可选的打包方式,安装内部能力不需要另装一个应用。
桌面端插件市场提供「宿主扩展」页签。选择作者提供的 distribution.json,核对将运行的模块并点击「信任并添加」,重启后生效。此后从 Finder 或 Dock 直接打开 Craft Hub 就会自动加载,无需专用启动器或环境变量。应用品牌、更新配置和项目执行信任不受影响。
连接或启用包含集成声明的本地市场插件时,桌面端也会查找其所在目录中的 distribution.json,提供同样的安装流程。发现和确认阶段不执行模块代码;浏览器端不能安装可执行宿主模块。
安装记录保存在操作系统 Craft Hub 数据目录的 host-extensions.json,其中保存已确认的模块路径。修改原始清单不会静默增加模块。请保留本地扩展及其依赖的稳定路径;移动目录或调整模块列表后,重新添加即可。在页签中停用或移除后,重启应用以卸载运行中的能力。移除保留源码文件和市场插件;对应宿主扩展停用时,市场插件可能提示提供者不可用。
craft-hub ui、craft-hub app 的浏览器模式(包括桌面启动失败后的回退)和 pnpm dev:web 会在启动时恢复同一份已批准的扩展。ui --host-plugin 仍可为当次会话显式加载一个额外的可信模块,不修改安装记录,也不会重复注册同一个模块。CLI 帮助和独立的发现命令不导入已保存扩展;传入自定义 runtime 的嵌入式应用仍自行决定加载哪些 provider。