mcpField
V
validating-and-publishing-canvases

validating-and-publishing-canvases

github.com/posthog开发95108 次安装今天更新
代码仓库

关于 validating-and-publishing-canvases

这项技能说明如何验证并发布 PostHog canvas,适用于编辑或维护 canvas 的人员。它涵盖能力声明、版本保护、构建检查,以及按需暂存草稿和审核后发布。

主要功能

  1. 01检查源文件与项目依赖
  2. 02声明运行时能力和网络来源
  3. 03运行验证并处理诊断
  4. 04基于版本保护发布或编辑
  5. 05构建完成后检查状态
  6. 06暂存草稿并经审核提升

适用场景

  1. 01发布新建的 canvas 项目
  2. 02在保留并发修改的前提下编辑
  3. 03在上线前预览并审核草稿

MCP 相关

文档指出 PostHog AI(Max)的 MCP 工具可用于 canvas 相关能力声明中的连接器调用;未说明此技能本身通过 MCP 提供操作。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/posthog/ai-plugin --skill validating-and-publishing-canvases

安装后在 Claude Code 中输入/validating-and-publishing-canvases确认已加载。

详细介绍

验证和发布画布

画布的源代码存储在 PostHog 中,每次发布都会创建一个版本。发布受到保护:每次编辑都基于特定版本,服务器会拒绝覆盖更新的内容。每次发布都会将构建任务加入队列,由服务器端执行,画布会呈现最近一次成功构建的结果。

源项目

canvas-source-retrieve 会返回:

  • project — schemaVersion(1)、files(路径 → 内容)、entryHtml("index.html")、 dependencies(平台固定的精确版本)、canvasSdkVersion、capabilities。
  • current_version_id — 编辑所基于的版本。请保留此值;发布时需要用到。对于从未发布过的画布,此值为 null — 首次发布时请传入此 null。

请完整保留返回的 index.html 和 dependencies。你可以向项目添加相对路径的源文件和获准使用的资源。对于独立模块 Worker,请使用 ?worker;二进制资源应作为 base64 条目放在 assets 中。新增 npm 依赖或依赖版本漂移都会导致验证失败。

声明能力

主机会在运行时强制执行 project.capabilities,因此未声明的 ph 调用虽然能成功构建,却会在渲染后的画布中失败。请声明:

  • capabilities.posthog.insights — 画布传给 ph.loadInsight 的所有 insight 短 ID。
  • capabilities.posthog.captureEvents — 画布传给 ph.capture 的所有事件名称。
  • capabilities.posthog.inlineQueries: true — 只要调用了 ph.query,就需要声明。
  • capabilities.posthog.agentRequests: true — 只要调用了 ph.agent.request,就需要声明。
  • capabilities.connectors — 画布通过 ph.connectors.call 读取第三方提供方的数据时,每个提供方都需要一个 { "provider", "tools" } 条目,并列出该提供方下调用的所有工具。提供方可以是原生 ID(github)或 mcp:<server host>(mcp:mcp.calendly.com)。未知提供方、未注册的原生工具和私有 MCP 主机都会导致验证失败;目录中的每个已声明工具都必须满足 is_read_only: true。仅有上游提示并不会授予访问权限。带有连接器的画布不能声明共享状态。
  • capabilities.network.origins — fetch、XMLHttpRequest 或外部样式表、图像、字体、媒体文件或框架所使用的每个 HTTPS 来源(origin)。远程脚本仍会被拦截。不要包含路径、凭据、查询参数、片段或通配符。主机必须是公开的:回环地址和私有 IP、intranet 这类单标签名称,以及 .local、.localhost、.internal 和 .home.arpa 后缀都会被拒绝,因此 https://localhost:8010 这类本地开发主机会因 invalid_network_origin 错误而无法通过验证。发送到已声明来源的数据会离开 PostHog,并在提升前的能力审核中显示。

验证前,请清点每个源文件中的所有字面量外部 URL。将导航链接和 ph.openExternal() URL 归类为导航;它们不需要网络来源。对于每个请求或资源 URL,只声明协议 + 主机 + 可选端口。包括请求重定向到的每个来源,以及样式表引用字体或图像时涉及的每个次级来源。切勿假定一个 CDN 主机名可以覆盖另一个。

验证会拒绝未声明的字面量调用和资源 URL(capability_missing_* 诊断),让你能在发布前修复问题。动态 URL 和重定向目标无法推断,因此即使验证通过,仍必须进行清点。

验证直至无问题

canvas-validate-create 不会产生副作用;可根据需要随时调用。 诊断信息包含 severity、稳定的 code、message,以及(针对文件相关问题的) path 和 line:

  • error 诊断会阻止发布 — 请全部修复。常见问题:import_not_allowed (裸导入仅限源项目返回的依赖), forbidden_dynamic_import / forbidden_require / forbidden_inline_script、 invalid_path、capability_missing_insight / capability_missing_capture_event / capability_missing_inline_queries / capability_missing_agent_requests / capability_missing_network_origin、 dependency_not_admitted / dependency_version_mismatch、platform_token_redeclared(CSS 变量名称与 Quill 令牌相同,而平台样式表会在每个元素上设置该变量,因此该值不会生效;请为自定义变量添加前缀),以及路径/大小违规。
  • warning 诊断不会阻止发布,但请留意:network_fetch / network_xhr 表示代码会直接访问网络。请声明准确的 HTTPS 源,或使用 ph 桥接接口。

发布防护

发布会立即上线,并且是保存更改的默认方式,适用于画布的第一个版本和之后的每次编辑。每个版本都会记录发布者以及完成这项工作的任务,因此事后仍可查看历史记录。只有当用户要求草稿、预览或审核步骤时,才暂存草稿——请参阅下文“先创建草稿,再提升”。

两种发布方式,均带防护:

  • 编辑 — 使用 canvas-edit-create 和 operations。对于任何已有源代码的画布更改,这是默认方式。 此处必须使用防护,因为编辑的含义取决于其基础版本。
  • 整个项目 — 使用 canvas-publish-create 和完整的 project,适用于发布第一个版本或替换全部内容。

使用 canvas-edit-create 编辑时:

  • 在文件中修改内容时使用 str_replace:old_string 是从你读取的文件中复制的文本,需包含几行上下文,以确保它只匹配一个位置。 设置 replace_all: true 可更改所有匹配项,例如重命名。
  • 对于新文件或完整重写,使用带有完整 content 的 write;使用 delete 删除文件;使用带有 new_path 的 rename 移动文件。
  • 如果更改需要新增功能(例如 ph.state 作用域),还要在同一次编辑中发送完整的新 capabilities(即当前项加上新增项)。 不要因此改用 canvas-publish-create。
  • 将一次更改的所有操作放在同一个调用中。操作会按顺序应用;任何操作失败,整个编辑都会被拒绝。
  • 400 响应会按索引列出每个失败的操作。edit_no_match 会显示文件中最接近的几行,edit_ambiguous_match 会列出匹配的行。 根据诊断结果修正这些操作,然后重新发送编辑请求。如果同一项替换连续失败两次,就改用 write 重写整个文件。
  • 响应会返回新的 current_version_id。将它传给下一次编辑。 如果你在本次会话中已经发布或编辑过该画布,在下一次编辑前不要调用 canvas-source-retrieve:你已经知道源代码;画布发生变化时,409 version_conflict 会告知你。

使用 canvas-publish-create 发布整个项目时:

  • 始终传入 expected_current_version_id——你读取到的 current_version_id(首次发布时明确传入 null)。不带防护的发布可能会悄悄覆盖并发编辑。
  • 添加简短的 prompt 描述更改;它会成为版本历史记录的标签。
  • 仅在重命名画布时传入 name(例如,为未命名画布首次构建时)。
  • 每项用户要求的更改发布一次。如果用户之后又要求编辑,请重新读取源代码(头部版本可能已变化)并再次发布——不要将无关更改合并到一个版本中,也不要在每次微小编辑后发布尚未完成的工作。
  • 429 表示团队的构建容量暂时已满。等待约 30 秒,然后重试相同的发布操作;不会有任何内容被保存。

响应会返回新的 current_version_id。

发布后:等待构建完成

发布会将该版本的服务端构建加入队列。构建就绪前,画布不会更新,而且没有其他人会关注结果——你需要负责到底。 发布或编辑响应中已包含 build.build_status。如果状态为 ready 或 failed,无需再次调用即可据此处理。只有在状态为 queued 或 building 时,才每隔几秒轮询一次 canvas-builds-retrieve(最多约 2 分钟),直到你加入队列的构建进入终态:

  • queued/building — 正在进行;稍后再次轮询。
  • ready — 画布的 published_build_id 会更新为此构建(除非有更新的发布先将其取代)。该画布任务已完成。
  • failed — 阅读构建的错误诊断信息,修复项目,然后重新发布。失败的构建绝不会取代上一个成功构建,因此画布会继续渲染之前的版本——如果此时就结束任务,用户看到的仍是过时的画布,而且失败不会有任何提示。

渲染后的画布发生错误时,系统会在创作任务上记录运行时错误报告,并注明其来源构建。来自较旧构建 ID 的报告只是历史记录,不能作为当前代码存在问题的证据——采取行动前,请核对它与刚发布的构建是否相符。尤其是,如果报告指出文档中记载的 ph API 未定义(例如 ph.state),说明该产物由较旧的宿主运行时生成:重新发布,让当前构建替换它。切勿通过移除该 API 或其能力声明来“修复”此问题。

先创建草稿,再发布上线

构建就绪后,发布会立即上线,这是默认行为。只有用户要求时才使用草稿:例如先预览、上线前先审核,或明确要求“暂时不要发布”。草稿是一个真实且可构建的版本,但不会成为当前版本:有人将草稿提升为当前版本之前,线上画布会继续渲染当前版本。这与 canvas-validate-create 不同;后者只进行编译检查,不会生成构建或预览。

  1. 暂存 — 使用完整的 project 调用 canvas-draft-create(形状、能力和验证要求均与发布相同)。无需提供 expected_current_version_id:草稿不基于任何版本,也不会与任何版本冲突。响应会返回草稿的 version_id、排队中的 build,以及 capability_widening——草稿声明的、超出当前线上版本范围的洞察、捕获事件、内联查询和网络来源。在提升草稿之前,向用户说明所有非空的扩展权限;这些是变更将新增授予的访问权限。
  2. 等待构建 — 轮询 canvas-builds-retrieve,直到草稿的构建进入终态,方式与发布后相同。草稿构建失败时,应通过暂存新草稿来修复,而不是提升失败的草稿。
  3. 预览 — 调用 canvas-source-retrieve 并传入草稿的 version_id,读取草稿文件;构建就绪后,打开该版本时,应用会渲染此草稿。草稿不会出现在 canvas-versions-retrieve 中(该接口仅列出已发布的历史版本),也不能回退到草稿——使用 canvas-drafts-retrieve 列出待处理的草稿。
  4. 提升 — 用户批准草稿或要求上线时再执行;如果用户要求先审核,就应继续暂存草稿,直到用户明确同意。canvas-promote-create 会将草稿设为线上当前版本。传入 expected_current_version_id(从 canvas-source-retrieve 获取的线上 current_version_id);其保护机制与发布完全相同,如果当前版本已变更就会返回 409(按下文说明处理)。如果草稿的构建仍为 ready,则无需重新构建即可上线;否则会将新构建加入队列,因此需按照步骤 2 等待。提升是将草稿上线的唯一途径。

从 409 version_conflict 中恢复

409 表示画布已超出你的基准版本——发生了并发发布或回退。响应中包含当前的 current_version_id。切勿在不加保护的情况下重试,强行发布你的版本:

  1. 使用 canvas-source-retrieve 重新读取源内容。
  2. 将你的修改重新应用到最新源内容上(新的头版本可能包含用户自己的修改——请保留这些修改,不要在回复中提及)。
  3. 使用新的 current_version_id 再次发布。

版本历史语义

每次发布都会追加一个完整的源版本并移动头指针;用户可以在应用中回退到较早的版本(这会重新发布并重新构建这些版本)。版本保护很重要,因为以你实际读取的版本为基础进行发布,才能避免用户的回退、其他 Agent 的发布和你的修改在不知不觉中互相覆盖。

评论

支持 Markdown