mcpField
C
create-issue-interaction-ui

create-issue-interaction-ui

github.com/paperclipai开发108.3k99 次安装今天更新
代码仓库

关于 create-issue-interaction-ui

面向 Paperclip 维护者的指南,介绍如何新增议题线程交互类型,涵盖共享契约、服务端行为、UI、对话渠道、外部调用工具和文档。

主要功能

  1. 01定义共享类型与验证
  2. 02实现服务端生命周期和路由
  3. 03添加 UI 卡片与线程接线
  4. 04扩展对话渠道处理
  5. 05更新 CLI、MCP、插件 SDK 和文档

适用场景

  1. 01新增议题线程交互类型
  2. 02创建不同的负载与解决结果变体
  3. 03规划跨层实现与测试

MCP 相关

指南要求在 Paperclip 的 MCP 服务中添加 MCP 工具,复用现有的 createIssueThreadInteraction 调用路径,并测试其负载结构。

安装

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

$npx skills add https://github.com/paperclipai/paperclip --skill create-issue-interaction-ui

安装后在 Claude Code 中输入/create-issue-interaction-ui确认已加载。

详细介绍

原文在翻译后有更新,译文可能不是最新。

创建新的 Issue 线程交互 UI(开发者/维护者技能)

开发者/维护者技能。请勿将其安装到生产环境中的 Paperclip Agent 上。

此技能将引导 Paperclip 贡献者从共享契约开始,逐步为新的 Issue 线程交互类型添加 Issue 详情页接线、辅助工具和文档。这是一项面向开发者/维护者的技能:受众是在 paperclipai/paperclip 中修改代码的人类或编码 Agent,而不是在已部署的 Paperclip 公司中运行的运维 Agent。

请勿将其安装到生产环境中的 Paperclip Agent 上。本指南面向修改 Paperclip 项目本身的仓库贡献者。

适用场景

  • 正在引入一种新的交互类型(紧凑型选择器、结构化评分、线程内审批卡片等)。
  • 现有交互需要一个具有不同负载结构、验证方式或解决结果的平行变体(此时 ask_user_questions 并不合适,因为选项数量、目标绑定或结果结构有所不同)。
  • 评审者要求新卡片具备“与其他交互相同的审计、过期、替代和后续处理语义”。

不适用场景

  • 为现有交互类型添加字段,且不需要新的负载架构。请直接修改现有验证器和 UI。
  • 更改 Paperclip Agent 调用交互的方式。请更新 skills/paperclip 或 references/api-reference.md;这属于 Agent 指南,而不是卡片开发。
  • 构建非线程 UI(Issue 详情侧边栏、项目看板小组件等)。这些 UI 有各自的组件约定。

心智模型

每种 Issue 线程交互都有四个组成部分:

层级职责
共享类型常量、负载/结果接口、Zod 验证器、导出的类型、共享测试覆盖。
服务端服务的创建/接受/拒绝/响应、过期、替代、幂等性、活动日志、唤醒发送。
UI卡片的待处理/已解决/已过期状态、测试数据、Storybook、Issue 线程/IssueDetail 接线。
辅助工具/文档CLI 命令、MCP 工具、插件 SDK 类型+宿主+测试路径、skills/paperclip 指南。

现有的四种类型是权威参考。选择最接近的一种,并复用其接线方式,而不要另行发明一套机制:

  • request_confirmation — 绑定到 target 的单项是/否确认,支持过期/替代。
  • request_checkbox_confirmation — 针对不可变选项集的有限多选。
  • ask_user_questions — 小型类型化表单,不绑定目标。
  • suggest_tasks — 提议可由看板逐项接受的任务。

如果新卡片需要绑定目标并采用是/否式解决方式,请参照这两种 request_* 类型。如果它是结构化表单,请参照 ask_user_questions。如果它会生成可创建的子实体,请参照 suggest_tasks。

权威示例

目前最完整的端到端参考是复选框确认功能的推出过程(合并于 4d5322c82,GitHub PR #7649)。开始前请先阅读该差异:

git show --stat 4d5322c82

该实现所依据的计划保存在 Issue 文档 PAP-10415 中。如果你通过 Paperclip 本身开展这项工作,可将其用作自己计划文档的模板。

操作顺序

首先完成共享契约。这是最小且正确的改动,即使 UI 尚未定稿也可以提交;后续每一层都会读取其中的类型和验证器。

1. 共享契约(最小范围,优先落地)

涉及:

  • packages/shared/src/constants.ts — 将 kind 字符串添加到 ISSUE_THREAD_INTERACTION_KINDS,并添加任意一个大小常量(参照 REQUEST_CHECKBOX_CONFIRMATION_OPTION_LIMIT = 200)。
  • packages/shared/src/types/issue.ts — 添加 Option、Payload、Result 和 Interaction 接口。扩展文件末尾的 IssueThreadInteraction 以及 payload/result 联合类型。
  • packages/shared/src/types/index.ts — 重新导出新类型。
  • packages/shared/src/validators/issue.ts — 为 payload、result 和创建输入变体添加 Zod 架构。适用目标绑定时,复用现有的 requestConfirmationTargetSchema。
  • packages/shared/src/validators/index.ts — 重新导出新架构。
  • packages/shared/src/index.ts — 在包根目录重新导出。
  • packages/shared/src/issue-thread-interactions.test.ts — 扩展表格测试,覆盖新的 payload 变体。

已经经过讨论并必须满足的验证不变量:

  • 选项列表必须有数量上限(checkbox kind 使用 200;请选一个 UX 能紧凑呈现的数字)。
  • 一个 payload 中的选项 ID 必须唯一,任何默认选择都必须引用已知 ID。
  • 标签和描述的长度上限须与现有问题选项一致。不要擅自放宽上限。
  • 目标绑定使用共享的 RequestConfirmationTarget 架构,让过期处理沿用同一条代码路径。
2. 服务端服务和路由

涉及:

  • server/src/services/issue-thread-interactions.ts — 在以下位置添加该 kind:
    • 支持的 kind 列表(顶部附近的 SUPPORTED_KINDS);
    • mapInteractionRow(解析 payload/result 的 switch (row.kind));
    • 创建输入验证(switch (data.kind));
    • 接受、拒绝、响应和过期处理分支;
    • 活动日志 payload 和后续唤醒 payload。
  • server/src/routes/issues.ts — 扩展所有按 kind 分支处理的逻辑(尤其是 checkbox PR 中第 6096 行附近的响应形状分支)。
  • server/src/__tests__/issue-thread-interactions-service.test.ts — 覆盖创建、携带结果接受、附带原因拒绝、目标过期、用户评论时取代、幂等冲突以及唤醒 payload 形状。
  • server/src/__tests__/issue-thread-interaction-routes.test.ts — 覆盖创建以及 HTTP 响应/接受/拒绝行为、公司范围隔离和授权。

服务端不变量:

  • 仅允许 Board 解决。由 Agent 发起的接受/拒绝必须走现有的 403 路径;不要添加按 kind 绕过限制的逻辑。
  • 公司范围隔离。读取、写入、过期处理和取代操作都必须按 companyId 过滤。绝不能只信任 issueId。
  • 目标过期。如果创建时指定了 target,且之后出现更新的 revision,则该交互必须以 outcome: "stale_target" 过期。不要自行实现过期逻辑——调用其他 request_* kind 使用的同一辅助函数。
  • 用户评论时取代。默认设置 supersedeOnUserComment: true,除非 payload 架构对此另有说明。
  • 幂等性。必须遵循现有 kind 所用的确定性 idempotencyKey 格式(<kind>:<issueId>:<decisionKey>:<revisionId>);重复的 POST 必须返回已有卡片,不得重复创建。
  • 后续策略。支持 none、wake_assignee 和 wake_assignee_on_accept。根据提问者是阻塞等待答案(wake_assignee),还是只关心是否接受(wake_assignee_on_accept),选择相应的默认值。
3. UI 卡片与问题线程接线

修改:

  • ui/src/components/IssueThreadInteractionCard.tsx — 添加卡片组件 (例如 RequestCheckboxConfirmationCard)和结果组件 (例如 RequestCheckboxConfirmationResolution)。根据 interaction.kind 扩展现有的 switch。复用卡片外壳,不要引入 并行的卡片框架。
  • ui/src/lib/issue-thread-interactions.ts — 添加类型化辅助函数,例如 getCheckboxConfirmationSelectedLabels,让卡片保持声明式。
  • ui/src/lib/issue-thread-interactions.test.ts — 测试辅助函数。
  • ui/src/components/IssueThreadInteractionCard.test.tsx — 覆盖待处理、 已解决、过期、禁用/提交中和验证错误状态。
  • ui/src/fixtures/issueThreadInteractionFixtures.ts — 为新类型至少添加 一个待处理和一个已解决的测试数据。
  • ui/storybook/stories/questions-and-approvals/issue-thread-interactions.stories.tsx — 为 关键状态添加 Storybook 条目。
  • ui/src/pages/IssueDetail.tsx — 扩展卡片渲染所依据的按类型分支 (回调接线、响应提交)。
  • ui/src/components/IssueChatThread.tsx — 如果该类型会影响线程级 渲染(徽标、摘要、计数),则更新这里的按类型 switch。
  • ui/src/api/issues.ts — 扩展类型化的 accept/reject/respond 请求体。

UI 不变量:

  • 紧凑渲染。卡片必须能舒适地展示约 100 个选项 (限定滚动区域;已解决状态的摘要优先显示数量——不要将每个选中项都显示为行内标签)。
  • 全选和清除选项必须位于卡片内,而不是全局菜单中。
  • accept 请求体使用类型专属的字段名(例如 selectedOptionIds, 而不是 suggest-tasks 的 selectedClientKeys)。不要复用其他类型的字段名。
  • 过期、已取代和已接受状态必须使用不同的文案;复用现有的结果组件外壳。
4. CLI、MCP、插件 SDK 辅助工具

外部调用方必须能创建此新交互,而无需手动编写 JSON。修改:

  • cli/src/commands/client/issue.ts — 添加 CLI 子命令,或扩展通用交互创建路径。
  • cli/src/__tests__/issue-subresources.test.ts — 覆盖新的标志组合。
  • packages/mcp-server/src/tools.ts — 添加一个接受新请求体结构的 MCP 工具;复用现有的 createIssueThreadInteraction 代码路径。
  • packages/mcp-server/src/tools.test.ts — 覆盖该工具的请求体结构。
  • packages/plugins/sdk/src/types.ts — 添加类型化的 CreateIssueThreadInteraction 变体,让插件作者能够使用自动补全。
  • packages/plugins/sdk/src/worker-rpc-host.ts — 扩展创建调用中的类型 switch。
  • packages/plugins/sdk/src/testing.ts — 扩展测试框架,让插件能够端到端模拟此新类型。
  • packages/plugins/sdk/tests/testing-actions.test.ts — 测试通过测试框架对新类型进行往返处理。
5. Agent 指引

修改:

  • skills/paperclip/SKILL.md — 在交互类型表中添加一行,包括: 适用场景、不适用场景,以及可复制的请求体示例。
  • skills/paperclip/references/api-reference.md — 完整的请求体和结果 schema、验证限制、创建/响应请求体及错误码。

技能文本会由运行时 Agent 读取。请保持简洁,每个类型用一到两句话与相近类型明确区分。

请求审查前要运行的测试

复选框 PR 在 NODE_ENV=test 下恰好运行了以下这组针对性测试。新增类型时也采用相同的测试模式,并替换为新的测试文件:

NODE_ENV=test pnpm run preflight:workspace-links
NODE_ENV=test pnpm exec vitest run \
  packages/shared/src/issue-thread-interactions.test.ts \
  server/src/__tests__/issue-thread-interaction-routes.test.ts \
  server/src/__tests__/issue-thread-interactions-service.test.ts \
  ui/src/components/IssueThreadInteractionCard.test.tsx \
  ui/src/lib/issue-thread-interactions.test.ts \
  cli/src/__tests__/issue-subresources.test.ts \
  packages/mcp-server/src/tools.test.ts \
  packages/plugins/sdk/tests/testing-actions.test.ts

如果 UI vitest 因 act is not a function 失败,说明 shell 正在使用 NODE_ENV=production(它会采用 React 的生产构建)。请显式设置 NODE_ENV=test 后重新运行。

合并前检查清单

  • 新类型已添加到 ISSUE_THREAD_INTERACTION_KINDS 并导出。
  • 负载和结果接口已进行版本化(从 version: 1 开始)。
  • Zod 验证器会强制执行选项、标签和描述的限制,并确保 ID 唯一。
  • 目标绑定(如有)使用共享的 RequestConfirmationTarget 路径。
  • 服务会处理创建、接受、拒绝/响应、目标过期、用户发表评论时取代、幂等性、活动日志和唤醒后续流程。
  • 路由遵循仅限看板的解析规则和公司范围限制。
  • UI 会呈现待处理、已解决、过期、已禁用/提交中和验证错误状态;已解决状态下的大量选择应优先按数量汇总。
  • 新类型已有固定数据和 Storybook 条目。
  • CLI、MCP 和插件 SDK 辅助函数均支持新的负载格式,并有测试覆盖。
  • 已更新 skills/paperclip/SKILL.md 和 references/api-reference.md。
  • 上述针对性测试集全部通过;CI 检查通过。

评审中发现的反模式

这些问题出现在复选框 PR 评审讨论中,下次值得避免:

  • 复用其他类型的接受负载字段名(例如使用 selectedClientKeys,而不是引入 selectedOptionIds)。每种类型都有自己的字段名。
  • 不通过现有的 request_confirmation 辅助函数,而是编写并行的过期或取代逻辑。这会导致行为悄然偏离。
  • 在已解决状态下渲染数百个已选选项标签。大量选择必须优先按数量汇总。
  • 认为“API 足够通用”,便跳过插件 SDK、MCP 或 CLI 的覆盖。没有类型化辅助函数,外部调用方就无法使用新类型;之后就会出现 Agent 流程故障。
  • 在服务器路由接受该类型之前,就将其加入技能指南。Agent 会尝试使用新类型,并在生产环境中收到 400 错误。

评论

支持 Markdown