- AI 应用
- Agent 工作流
- 开发工具
- MCP 服务
【免费下载链接】cc-wf-studio
CC Workflow Studio
本篇技术指南围绕 CC Workflow Studio(VS Code 扩展)中 Slack 集成工作流共享功能的Extension Host 与 Webview 之间的消息传递 API 契约(定义于 extension-host-api-contracts.md)展开,详细讲解 Webview 如何通过 6 个 Command 消息驱动扩展宿主完成 Slack 连接、频道拉取、工作流共享/导入/搜索,以及扩展宿主如何通过 9 个 Event 消息回传结果。读完本文,你将掌握这套双向消息协议的完整字段语义、错误码约定、典型交互时序,并能对照仓库中的 TypeScript 类型定义与命令处理器源码,自行实现或调试基于postMessage的 VS Code 扩展与 Webview 通信层。
背景:这套契约解决什么问题
CC Workflow Studio 允许开发者在 VS Code 画布上以 JSON 形式编排工作流(节点、连线、参数),而 Slack 集成功能(对应功能规格 spec.md)把"创建"延伸到"协作":把工作流直接共享到团队 Slack 频道,以富消息卡片呈现;团队成员点击卡片即可一键导入自己的 VS Code;还支持在 VS Code 内检索历史共享的工作流并复用。
由于 Webview(前端 React 画布)与 Extension Host(Node 侧扩展宿主)运行在不同的 JavaScript 上下文,二者无法共享内存或直接调用函数,只能通过vscode.postMessage()传递可序列化的 JSON 消息。本契约文档正是这一通信层的"协议定稿":它规定了每一条消息的类型名(type)、负载结构(payload)、成功/失败事件以及多步交互的时序。仓库中对应的 TypeScript 实现位于 slack-messages.ts,文件头注释明确标注其依据即本契约文档,二者一一对应,可直接对照阅读。
通用消息格式
所有 Webview 与 Extension Host 之间的消息都遵循统一的信封结构:
export interface WebviewMessage<T = any> { type: string; payload: T; }type:消息类型字符串,是双方路由的唯一依据;payload:携带业务数据的负载对象,随消息类型不同而结构各异。
实际运行时(见 messages.ts 的Message接口),消息还会携带可选的requestId字段用于请求-响应关联:Webview 端每次调用都会生成形如req-${Date.now()}-${Math.random()}的唯一 ID(参见 slack-integration-service.ts),Extension Host 回传事件时原样附带该requestId,Webview 据此把异步事件匹配回对应的 Promise。这套模式贯穿全部 Slack 命令。
Webview → Extension Host:6 个 Command 消息
契约文档定义了 6 条命令,全部由 Webview 发起(例如用户点击共享按钮、选择频道后触发)。
1.SLACK_CONNECT:启动连接
发起 Slack 工作区连接(OAuth 认证流程),payload 为空对象。
interface SlackConnectCommand { type: 'SLACK_CONNECT'; payload: Record<string, never>; // 空对象 }vscode.postMessage({ type: 'SLACK_CONNECT', payload: {} });响应事件:成功SLACK_CONNECT_SUCCESS,失败SLACK_CONNECT_FAILED。
从源码看,Webview 侧的connectToSlack()与reconnectToSlack()(强制重连场景会附加forceReconnect: true)都会发送此命令,并设置 5 分钟超时以容忍完整的 OAuth 浏览器流程。OAuth 的具体实现另有扩展(SLACK_CONNECT_OAUTH/SLACK_OAUTH_*系列事件,见 slack-integration-service.ts),而本契约中的SLACK_CONNECT主要面向手动令牌接入场景——handleConnectSlackManual()(见 slack-connect-manual.ts)会弹出输入框要求用户粘贴以xoxp-开头的 User OAuth Token,随后调用 Slackauth.test接口自动解析出工作区 ID 与名称,最后经 slack-token-manager.ts 的storeManualConnection()存入 VSCode Secret Storage。
2.SLACK_DISCONNECT:断开连接
断开与 Slack 工作区的连接(删除已保存的令牌),payload 为空对象。
interface SlackDisconnectCommand { type: 'SLACK_DISCONNECT'; payload: Record<string, never>; }响应事件:成功SLACK_DISCONNECT_SUCCESS,失败SLACK_DISCONNECT_FAILED。令牌管理器中clearConnection()/clearConnectionByWorkspaceId()会逐工作区删除 Secret Storage 中的令牌与元数据,并同步维护工作区列表。
3.GET_SLACK_CHANNELS:获取频道列表
拉取 Slack 频道列表,供共享目标选择。两个可选过滤参数均有默认值:
interface GetSlackChannelsCommand { type: 'GET_SLACK_CHANNELS'; payload: { includePrivate?: boolean; // 是否包含私密频道 (default: true) onlyMember?: boolean; // 仅返回自己已加入的频道 (default: true) }; }vscode.postMessage({ type: 'GET_SLACK_CHANNELS', payload: { includePrivate: true, onlyMember: true } });响应事件:成功GET_SLACK_CHANNELS_SUCCESS,失败GET_SLACK_CHANNELS_FAILED。
底层实现见 slack-api-service.ts 的getChannels():它通过conversations.listAPI 拉取,includePrivate决定types是否拼接private_channel,onlyMember通过is_member字段在客户端过滤,并以limit: 100+cursor游标循环分页直至取完。注意,实际请求使用的是当前登录用户的 User Token(xoxp-)而非 Bot Token,确保用户只能看到自己有权访问的频道。
4.SHARE_WORKFLOW_TO_SLACK:共享工作流
将工作流共享到指定 Slack 频道,是整套功能的核心命令:
interface ShareWorkflowToSlackCommand { type: 'SHARE_WORKFLOW_TO_SLACK'; payload: { workflowId: string; // 待共享的工作流 ID workflowName: string; // 工作流名称 channelId: string; // 目标频道 ID description?: string; // 工作流描述 (optional) overrideSensitiveWarning?: boolean; // 是否忽略机敏信息警告 (default: false) }; }vscode.postMessage({ type: 'SHARE_WORKFLOW_TO_SLACK', payload: { workflowId: 'uuid-1234-5678', workflowName: 'My Data Processing Workflow', channelId: 'C01234ABCD', description: 'Workflow for daily data processing tasks', overrideSensitiveWarning: false } });响应事件:
- 成功:
SHARE_WORKFLOW_SUCCESS - 检测到机敏信息(警告):
SENSITIVE_DATA_WARNING - 失败:
SHARE_WORKFLOW_FAILED
该命令在扩展宿主的完整处理链路见 slack-share-workflow.ts 的handleShareWorkflowToSlack(),实际执行分为 7 步:先做机敏信息检测(除非overrideSensitiveWarning: true);再提取节点数等元数据;随后调用postWorkflowMessage()用 Block Kit 发布富卡片主消息;接着以线程回复形式用files.uploadV2上传工作流 JSON 文件(文件名会先将非字母数字字符替换为_);再通过chat.update更新消息补全文件 ID 与深链;最后向 Webview 回发SHARE_WORKFLOW_SUCCESS并弹出"View in Slack"原生通知。机敏信息警告采用"警告但不强制阻断"策略(FR-006),用户选择继续后 Webview 会以overrideSensitiveWarning: true重新提交。
5.IMPORT_WORKFLOW_FROM_SLACK:从 Slack 导入工作流
从 Slack 消息导入工作流到本地:
interface ImportWorkflowFromSlackCommand { type: 'IMPORT_WORKFLOW_FROM_SLACK'; payload: { workflowId: string; // 待导入工作流 ID fileId: string; // Slack 文件 ID messageTs: string; // Slack 消息时间戳 channelId: string; // 频道 ID overwriteExisting?: boolean; // 是否覆盖已存在文件 (default: false) }; }vscode.postMessage({ type: 'IMPORT_WORKFLOW_FROM_SLACK', payload: { workflowId: 'uuid-1234-5678', fileId: 'F01234ABCD', messageTs: '1234567890.123456', channelId: 'C01234ABCD', overwriteExisting: false } });响应事件:
- 成功:
IMPORT_WORKFLOW_SUCCESS - 需要确认(文件已存在):
IMPORT_WORKFLOW_CONFIRM_OVERWRITE - 失败:
IMPORT_WORKFLOW_FAILED
扩展宿主侧实现见 slack-import-workflow.ts:先通过files.info+url_private下载文件内容(携带Authorization: Bearer头);再用核心包的validateWorkflowFile()校验 JSON 合法性、migrateWorkflow()做向后兼容迁移;随后选择工作区目录,将文件写入.vscode/workflows/{name}.json(目录不存在时自动创建);若文件已存在且未声明覆盖,则弹出模态确认框,用户拒绝时回发IMPORT_WORKFLOW_CANCELLED中止流程。成功事件 payload 中会附带完整的workflow对象,供 Webview 直接载入画布。
6.SEARCH_SLACK_WORKFLOWS:检索历史共享工作流
在 Slack 中检索过去共享过的工作流,全部过滤条件均为可选:
interface SearchSlackWorkflowsCommand { type: 'SEARCH_SLACK_WORKFLOWS'; payload: { query?: string; // 搜索关键词 (optional) channelId?: string; // 限定某频道内搜索 (optional) authorName?: string; // 按作者名过滤 (optional) fromDate?: string; // 起始日期 (ISO 8601) (optional) toDate?: string; // 结束日期 (ISO 8601) (optional) limit?: number; // 结果数量 (default: 20, max: 100) }; }vscode.postMessage({ type: 'SEARCH_SLACK_WORKFLOWS', payload: { query: 'data processing', channelId: 'C01234ABCD', fromDate: '2025-11-01T00:00:00Z', limit: 20 } });响应事件:成功SEARCH_SLACK_WORKFLOWS_SUCCESS,失败SEARCH_SLACK_WORKFLOWS_FAILED。
底层实现(slack-api-service.ts 的searchWorkflows())调用search.messagesAPI,查询串固定以workflow filename:*.json为基底,追加用户关键词并以in:<#频道ID>限定频道;count通过Math.min(count || 20, 100)钳制在 100 以内,默认按timestamp排序。文档同时提到authorName、fromDate、toDate等过滤维度,它们在 UI 层可组合为更精细的筛选条件。
Extension Host → Webview:9 个 Event 事件
以下事件均由 Extension Host 主动推送给 Webview,用于回报命令执行结果或请求用户确认。
2.1SLACK_CONNECT_SUCCESS
Slack 连接成功时发送,携带工作区与用户信息:
{ "type": "SLACK_CONNECT_SUCCESS", "payload": { "workspaceId": "T01234IJKL", "workspaceName": "My Team Workspace", "userId": "U01234ABCD", "authorizedAt": "2025-11-22T10:00:00Z" } }2.2SLACK_CONNECT_FAILED
连接失败时发送。错误码约定:
| 错误码 | 含义 |
|---|---|
USER_CANCELLED | 用户取消了认证 |
OAUTH_FAILED | OAuth 认证失败 |
NETWORK_ERROR | 网络错误 |
UNKNOWN_ERROR | 其他错误 |
{ "type": "SLACK_CONNECT_FAILED", "payload": { "errorCode": "USER_CANCELLED", "errorMessage": "用户取消了认证。" } }实现说明:仓库实际落地时(slack-messages.ts)将
errorMessage升级为 i18n 体系——用messageKey+ 可选的suggestedActionKey替代硬编码文案,由 Webview 端按语言渲染,这也与扩展的多语言(en/ja/ko/zh-CN/zh-TW)架构一致。
2.3GET_SLACK_CHANNELS_SUCCESS
频道列表获取成功,channels为SlackChannel[]:
{ "type": "GET_SLACK_CHANNELS_SUCCESS", "payload": { "channels": [ { "id": "C01234ABCD", "name": "general", "isPrivate": false, "isMember": true, "memberCount": 25, "purpose": "General discussions", "topic": "Team announcements" }, { "id": "C56789EFGH", "name": "project-alpha", "isPrivate": true, "isMember": true, "memberCount": 5 } ] } }SlackChannel结构定义(字段含义与数据模型文件 slack-integration-types.ts 一致):
interface SlackChannel { id: string; name: string; isPrivate: boolean; isMember: boolean; memberCount?: number; purpose?: string; topic?: string; }2.4SENSITIVE_DATA_WARNING
检测到机敏信息时发送,请求用户确认,是共享流程中最重要的安全关卡:
interface SensitiveDataWarningEvent { type: 'SENSITIVE_DATA_WARNING'; payload: { workflowId: string; findings: SensitiveDataFinding[]; }; } interface SensitiveDataFinding { type: string; // 例如: 'AWS_ACCESS_KEY', 'API_KEY' maskedValue: string; // 例如: 'AKIA...X7Z9' position: number; context?: string; severity: 'low' | 'medium' | 'high'; }{ "type": "SENSITIVE_DATA_WARNING", "payload": { "workflowId": "uuid-1234-5678", "findings": [ { "type": "AWS_ACCESS_KEY", "maskedValue": "AKIA...X7Z9", "position": 1234, "context": "...\"aws_access_key\": \"AKIA1234...\"...", "severity": "high" }, { "type": "API_KEY", "maskedValue": "sk-p...def9", "position": 5678, "severity": "medium" } ] } }用户必须在"继续"与"取消"之间做出选择。检测引擎实现在 sensitive-data-detector.ts:内置 8 类正则模式,包括 AWS Access Key(AKIA+ 16 位)、AWS Secret Key、Slack Token(xox[bpoa]-前缀)、GitHub Token(ghp_前缀)、通用 API Key、通用 Token、私钥(-----BEGIN ... PRIVATE KEY-----)与密码;掩码策略为"仅保留前后各 4 个字符"(maskValue),上下文截取以[REDACTED]标记,且原始值永不落盘或回传。
2.5SHARE_WORKFLOW_SUCCESS
共享成功,返回消息定位信息:
{ "type": "SHARE_WORKFLOW_SUCCESS", "payload": { "workflowId": "uuid-1234-5678", "channelId": "C01234ABCD", "channelName": "general", "messageTs": "1234567890.123456", "fileId": "F01234ABCD", "permalink": "https://myteam.slack.com/archives/C01234ABCD/p1234567890123456" } }permalink为 Slack 消息直链,Webview 收到后可引导用户跳转查看。
2.6SHARE_WORKFLOW_FAILED
共享失败。错误码是排查问题的关键索引:
| 错误码 | 含义 |
|---|---|
NOT_AUTHENTICATED | 未连接 Slack |
CHANNEL_NOT_FOUND | 频道不存在 |
NOT_IN_CHANNEL | Bot 不是频道成员 |
FILE_TOO_LARGE | 文件超过大小限制(1MB) |
RATE_LIMITED | 超过 Slack API Rate Limit |
NETWORK_ERROR | 网络错误 |
UNKNOWN_ERROR | 其他错误 |
{ "type": "SHARE_WORKFLOW_FAILED", "payload": { "workflowId": "uuid-1234-5678", "errorCode": "NOT_IN_CHANNEL", "errorMessage": "Bot 未加入频道。请将 Bot 邀请进频道。" } }实现中这些错误码由 slack-error-handler.ts 的handleSlackError()统一归一化:它把 Slack Web API 返回的invalid_auth、missing_scope、rate_limited、channel_not_found、not_in_channel等原生错误映射为带messageKey/suggestedActionKey/retryAfter的结构化信息,并额外识别自定义的WORKSPACE_NOT_CONNECTED、USER_TOKEN_REQUIRED错误;getRetryDelay()提供带抖动的指数退避算法用于应对限流。
2.7IMPORT_WORKFLOW_CONFIRM_OVERWRITE
目标文件已存在时请求确认覆盖:
{ "type": "IMPORT_WORKFLOW_CONFIRM_OVERWRITE", "payload": { "workflowId": "uuid-1234-5678", "existingFilePath": "/Users/.../workflows/my-workflow.json" } }用户在"覆盖"与"取消"间选择。实际实现(slack-import-workflow.ts)在当前版本使用 VS Code 原生模态警告框完成确认,取消时回发IMPORT_WORKFLOW_CANCELLED让 Webview 关闭加载遮罩。
2.8IMPORT_WORKFLOW_SUCCESS
导入成功:
{ "type": "IMPORT_WORKFLOW_SUCCESS", "payload": { "workflowId": "uuid-1234-5678", "filePath": "/Users/.../workflows/my-workflow.json", "workflowName": "My Data Processing Workflow" } }2.9SEARCH_SLACK_WORKFLOWS_SUCCESS
搜索成功,返回结果元数据列表与总数:
interface SearchSlackWorkflowsSuccessEvent { type: 'SEARCH_SLACK_WORKFLOWS_SUCCESS'; payload: { workflows: SharedWorkflowMetadata[]; total: number; }; } interface SharedWorkflowMetadata { id: string; name: string; description?: string; version: string; authorName: string; sharedAt: string; // ISO 8601 channelId: string; channelName: string; messageTs: string; fileId: string; fileUrl: string; nodeCount: number; tags?: string[]; permalink: string; }{ "type": "SEARCH_SLACK_WORKFLOWS_SUCCESS", "payload": { "total": 5, "workflows": [ { "id": "uuid-1234-5678", "name": "Data Processing Workflow", "description": "Daily data processing tasks", "version": "1.0.0", "authorName": "John Doe", "sharedAt": "2025-11-22T10:00:00Z", "channelId": "C01234ABCD", "channelName": "general", "messageTs": "1234567890.123456", "fileId": "F01234ABCD", "fileUrl": "https://files.slack.com/files-pri/...", "nodeCount": 5, "tags": ["data", "processing"], "permalink": "https://myteam.slack.com/archives/C01234ABCD/p1234567890123456" } ] } }数据模型文件 slack-integration-types.ts 还补充了authorEmail、hasSensitiveData、sensitiveDataOverride等字段,并给出了各字段的约束(如 name 1-100 字符、description 最长 500 字符、tags 最多 10 个且每个不超过 30 字符、version 使用语义化版本号),这些元数据被嵌入 Slack 消息的 Block Kit 中,构成搜索与一键导入的数据基础。
典型消息流程:三个时序示例
契约文档给出了三条最关键的多步交互时序,可视为状态机的权威描述。
3.1 Slack 连接流程
[Webview] SLACK_CONNECT ↓ [Extension Host] OAuth 认证开始 ↓ [Browser] 用户认证 ↓ [Extension Host] 令牌获取并保存 ↓ [Webview] SLACK_CONNECT_SUCCESS3.2 工作流共享流程(含机敏信息)
[Webview] SHARE_WORKFLOW_TO_SLACK ↓ [Extension Host] 机敏信息检测 ↓ [Webview] SENSITIVE_DATA_WARNING ↓ [User] 选择"继续" ↓ [Webview] SHARE_WORKFLOW_TO_SLACK (overrideSensitiveWarning: true) ↓ [Extension Host] Slack API 调用 ↓ [Webview] SHARE_WORKFLOW_SUCCESS这条流程在 UI 上的落地可参考 SlackShareDialog.tsx:首次shareWorkflowToSlack()固定传overrideSensitiveWarning: false,若返回sensitiveDataWarning则切换为警告视图逐条展示type (severity)与maskedValue;用户点"继续"(handleShareOverride)才以overrideSensitiveWarning: true重新提交。成功后会保存"上次共享频道"(SET_LAST_SHARED_CHANNEL),下次打开对话框时自动预选。
3.3 工作流导入流程(覆盖确认)
[Webview] IMPORT_WORKFLOW_FROM_SLACK ↓ [Extension Host] 文件存在性检查 ↓ [Webview] IMPORT_WORKFLOW_CONFIRM_OVERWRITE ↓ [User] 选择"覆盖" ↓ [Webview] IMPORT_WORKFLOW_FROM_SLACK (overwriteExisting: true) ↓ [Extension Host] 文件下载并保存 ↓ [Webview] IMPORT_WORKFLOW_SUCCESS完整 TypeScript 类型定义
契约文档以联合类型收束全部命令与事件,便于在 Webview 端做穷尽式路由(switch/if 判断):
// Commands (Webview → Extension Host) export type WebviewToExtensionCommand = | SlackConnectCommand | SlackDisconnectCommand | GetSlackChannelsCommand | ShareWorkflowToSlackCommand | ImportWorkflowFromSlackCommand | SearchSlackWorkflowsCommand; // Events (Extension Host → Webview) export type ExtensionToWebviewEvent = | SlackConnectSuccessEvent | SlackConnectFailedEvent | GetSlackChannelsSuccessEvent | GetSlackChannelsFailedEvent | SensitiveDataWarningEvent | ShareWorkflowSuccessEvent | ShareWorkflowFailedEvent | ImportWorkflowConfirmOverwriteEvent | ImportWorkflowSuccessEvent | ImportWorkflowFailedEvent | SearchSlackWorkflowsSuccessEvent | SearchSlackWorkflowsFailedEvent; // Message format export interface WebviewMessage<T = any> { type: string; payload: T; }仓库实现(slack-messages.ts 与 slack-messages.ts)在契约基础上还补充了SLACK_DISCONNECT_SUCCESS、SLACK_DISCONNECT_FAILED、IMPORT_WORKFLOW_FAILED事件以及失败事件的 i18n 字段(messageKey、suggestedActionKey、messageParams、workspaceId、workspaceName等),Webview 侧的统一 Promise 封装见 slack-integration-service.ts(含SlackError自定义错误类与 30 秒默认超时)。
消息契约背后的工程要点
- 请求-响应关联:所有命令都通过
requestId与对应事件配对,Webview 用一次性事件监听器实现 Promise 化,规避了多请求并发时的串扰。 - 安全红线:令牌一律存入 VSCode Secret Storage(明文保存被明确禁止,对应数据模型中的
SlackWorkspaceConnection与 slack-token-manager.ts);机敏信息检测结果只回传掩码值与脱敏上下文;Slack 富卡片内嵌的"Import to VS Code"按钮基于自定义 URI scheme(vscode://breaking-brake.cc-wf-studio/import?...,工作区名以 Base64 编码传递),构建逻辑见 slack-message-builder.ts。 - 可扩展性:
ExtensionToWebviewEvent联合类型让 Webview 可以静态穷举所有事件分支;而底层 Slack 调用统一收敛在SlackApiService一个类中,与SlackTokenManager、handleSlackError形成"令牌管理 → 客户端初始化 → API 调用 → 错误归一化"的清晰分层,为后续新增命令(如批量共享、跨频道转发)预留了扩展位。
以上契约与实现共同支撑了功能规格中共享(FR-001~FR-007)、导入(FR-008~FR-014)、搜索(FR-015~FR-018)与令牌管理(FR-019~FR-023)等全部功能需求。若要深入验证某条消息的具体行为,可直接对照 extension-host-api-contracts.md、slack-messages.ts 与对应命令处理器三份材料逐行比对。
- AI 应用
- Agent 工作流
- 开发工具
- MCP 服务
【免费下载链接】cc-wf-studio
CC Workflow Studio
相关推荐
CC Workflow Studio 扩展与 Webview 间 AI 工作流生成消息契约详解
CC Workflow Studio 扩展与 Webview 间 AI 工作流生成消息契约详解 本篇技术指南以 ai generation messages.m
AI 应用Agent 工作流开发工具MCP 服务es-toolkit/compat 的 meanBy:Lodash 兼容的按 iteratee 求平均函数完全指南
es toolkit/compat 的 meanBy:Lodash 兼容的按 iteratee 求平均函数完全指南 es toolkit/compat 提供的
AI 应用Agent 工作流开发工具MCP 服务CC Workflow Studio Slack 集成契约详解:基于 Slack Web API v2 的工作流共享、导入与检索实战指南
CC Workflow Studio Slack 集成契约详解:基于 Slack Web API v2 的工作流共享、导入与检索实战指南 本指南以 CC Wor
AI 应用Agent 工作流开发工具MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考