手把手带你实现:飞书 → OpenClaw → Cursor Agent → OpenClaw → 飞书

小编007 正二品 (尚书) 2026-02-15 03:55 20 0
小编007 正二品 (尚书) 楼主
2026-02-15 03:55
第1楼

摘要:本机已安装 Cursor,并且 Cursor CLI 可用 若还没安装 Cursor CLI,按下面步骤操作: Windows(PowerShell):

安装 Cursor CLI

irm 'https://cursor.com/install?win32=true' | iex

📌 提示:如果遇到执行策略报错,先运行: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

然后输入 Y 确认,再重新执行安装命令。macOS / Linux:

安装 Cursor CLI

curl -fsSL https://cursor.com/install | sh

⚠️ 实际踩坑:Cursor CLI 依赖 ripgrep 执行 agent 命令时如果报错:Could not find ripgrep (rg) binary.on("close", (code) => resolve({ success: code === 0, exitCode: code, output }) ); }); }

写一个简单的「调度函数」来更新任务状态 对应第八节错误处理和第七节结果收集

// 调度封装:围绕 runCursorCliTask 更新任务状态(极简版) async function dispatchToCursorCli(task, updateStatus) { await updateStatus({ status: "running" }); try { const result = await runCursorCliTask(task); await updateStatus({ status: result.


🚀 在飞书里 @ 机器人发一句话,让 Cursor 在你指定的项目目录里写代码、改代码、跑测试,执行结果自动回推到飞书。
本文按「手把手」顺序,带你打通这条链路。


在之前的文章中,我已经写过:

前几篇分别解决了:本地部署 OpenClaw、自建 APP 控制 OpenClaw、以及把飞书接到 OpenClaw、在飞书里对话本地 AI

那在飞书里和 OpenClaw 聊上天之后,很多同学会想:能不能直接让 Cursor 在某个项目里干活,比如改代码、加函数、跑测试,然后把执行结果自动推回飞书?这样不用切到 Cursor 界面,在飞书里就能「下任务 → 等结果」。

这篇就带你实现这条链路:飞书机器人下发任务 → OpenClaw 编排 → 调用 Cursor CLI Agent → OpenClaw 收集执行结果 → 通过飞书回推结果

整篇文章的目标只有一个:

让你看完后,能在飞书里发一条消息,让 Cursor 在你指定的项目目录里执行开发任务,并在同一会话里收到执行结果。


一、整体架构:一张图看懂整条链路

先把整条链路看清楚,后面按这个顺序一步步做。

image1.png

关键点

  • 任务统一由 OpenClaw 编排;飞书只负责「发任务」和「收结果」。
  • 执行只依赖 Cursor CLIagent 命令),不需要额外再搭 MCP/HTTP 服务。
  • task_id 把「飞书会话」和「这次执行」绑在一起,结果才能准确回推到对应对话。

二、开始前你需要准备好的东西

动手之前,先确认这几样已经就绪。

  1. OpenClaw 已安装并初始化,且飞书已经接进去、能收发消息。
    若还没做,请先按《手把手教你安装 OpenClaw 并接入飞书》完成。

  2. 飞书侧:已在开放平台创建企业自建应用 + 机器人,并配置好事件订阅 / 消息回调,消息能推到 OpenClaw。

  3. 本机已安装 Cursor,并且 Cursor CLI 可用 若还没安装 Cursor CLI,按下面步骤操作:

    Windows(PowerShell)

# 安装 Cursor CLI
irm 'https://cursor.com/install?win32=true' | iex

image2.png

📌 提示:如果遇到执行策略报错,先运行:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

然后输入 Y 确认,再重新执行安装命令。

macOS / Linux

# 安装 Cursor CLI
curl -fsSL https://cursor.com/install | sh

⚠️ 实际踩坑:Cursor CLI 依赖 ripgrep
执行 agent 命令时如果报错:Could not find ripgrep (rg) binary. Please install ripgrep. Error: rg is not installed
这是因为 Cursor Agent CLI 依赖 ripgrep(简称 rg) 来进行高效的代码搜索和上下文理解,但你的系统中尚未安装它。

解决方案:安装 ripgrep

Windows(手动下载)

  1. 打开 ripgrep GitHub Releases 页面
  2. 下载适用于 Windows 的 .zip 文件,例如:ripgrep-14.1.1-x86_64-pc-windows-msvc.zip
  3. 解压后,将 rg.exe 所在目录添加到系统 PATH 环境变量
  4. 验证安装:(使用CMD.exe)
rg --version

如果显示版本号,说明安装成功。

image3.png

在终端里运行:

# 启动交互式会话(首次运行会提示登录)
agent

如果看到 Cursor 的交互界面或提示登录,说明 CLI 已安装成功。完成登录后,后续 OpenClaw 调用时就能复用认证信息。


三、飞书 → OpenClaw:任务怎么进来

用户在飞书里向「机器人」发一条消息,就是一次「任务描述」。飞书会把这条消息通过事件订阅 / 消息回调 POST 到你配置的 OpenClaw HTTP 接口。

OpenClaw 这边要做的

  • 解析请求体,取出:发送人、会话 ID(群 ID 或私聊 ID)、消息 ID、以及消息正文(用户写的任务描述)。
  • 为这次请求生成一个内部 task_id,后面从「调用 Cursor」到「把结果推回飞书」都靠这个 task_id 关联。

任务描述怎么写
建议包含「项目路径 + 你想让 Cursor 做的事」,例如:「在 F:\cursor_work\ 里,写一个冒泡排序算法,写入py文件中。」这样方便你在 OpenClaw 里拼成给 Cursor 的 prompt。

⚠️ 实际踩坑 1:消息格式问题

飞书的消息回调是 JSON,但 content 可能是「JSON 字符串」而不是直接的对象;另外富文本(卡片)和普通文本的格式不一样,解析时要区分。
建议:优先支持纯文本消息msg_type: text),先跑通链路,再考虑卡片等复杂格式。


四、OpenClaw 内部:统一任务模型

不管用户从飞书发来的是哪一句话,在 OpenClaw 里都先转成同一套任务对象。这样后面无论是调 Cursor CLI 还是以后扩展别的执行端,逻辑都一致。

任务对象里至少要有

  • task_id:本次任务唯一 ID
  • from_chat:飞书会话信息(群 ID / 私聊 ID、消息 ID、发送人 ID),用于结果回推
  • project.root:项目本地路径,例如 D:\projects\my-app
  • payload:自然语言描述、可选的文件列表或约束条件

一个最小可用的任务对象大概长这样:

{
  "task_id": "task_1739356123456",
  "from_chat": {
    "chat_id": "oc_1234567890",
    "message_id": "om_abcdefg123456",
    "user_id": "ou_999999999"
  },
  "project": {
    "root": "D:\\\\projects\\\\my-app"
  },
  "payload": {
    "natural_language": "在 README 里新增一段 100 字以内的项目简介。",
    "files": ["README.md"],
    "constraints": {
      "language": "markdown"
    }
  }
}

飞书只是入口,真正驱动 Cursor 的是这份统一模型。


五、OpenClaw → Cursor Agent:在项目目录里调用 CLI

核心思路:不依赖 Cursor 桌面端界面,只通过 Cursor CLIagent 命令(非交互、带 -p 的 prompt)在指定目录执行。

流程

  1. 根据任务模型里的 project.root 确定工作目录。
  2. 在该目录下以非交互方式调用 Cursor CLI,例如:
    agent -p "<由任务生成的 Prompt>" --mode agent
  3. 子进程方式启动这条命令,并等待进程退出。

Prompt 从哪来
用任务里的 payload(自然语言、文件、约束)拼成一段清晰指令;如果需要,可以把任务 JSON 的关键字段也塞进 prompt,方便 Agent 理解上下文。

代码层面
在 OpenClaw 里用类似 spawn('agent', args, { cwd: projectRoot }) 的方式调用,并收集 stdout / stderr;用 exit code === 0 判断成功或失败。后文会给一个 Node.js 伪代码示例,演示如何在项目目录中拉起 Cursor CLI 并收集结果。

⚠️ 实际踩坑 2:Cursor CLI 路径问题

agent 可能不在系统 PATH 里,OpenClaw 子进程找不到。
解决:在配置里写 完整路径,例如 Windows 下 C:\Users\你的用户名\.cursor\agent.exe,Linux/Mac 下 ~/.cursor/agent;或把 Cursor CLI 所在目录加到 OpenClaw 进程的 PATH 环境变量里。

⚠️ 实际踩坑 3:Cursor 需要登录

Cursor CLI 执行前会做登录校验,没登录会报错。
解决:在本机至少用终端跑过一次 agent 并完成登录,认证信息会持久化,之后 OpenClaw 调用的子进程就能复用。

⚠️ 实际踩坑 4:子进程超时

简单任务几秒,复杂任务可能几分钟,超时设太短会把任务误杀。
解决:建议超时设得偏长(例如 30~60 分钟),或做成可配置项,方便按场景调整。


六、任务完成信号与结果收集

什么时候算「完成」
不需要轮询 Cursor 服务,Cursor CLI 子进程退出就表示这次执行结束。

结果内容
stdout + stderr 当作「执行日志 / 结果摘要」;退出码 0 视为成功,非 0 视为失败。OpenClaw 把结果和状态(done / failed)写入任务记录,供下一步回推飞书。

存储时注意
输出可能很长,建议做长度截断(例如最多保留 2 万字符),避免占满存储;回推飞书时也要考虑单条消息长度限制(见下文踩坑 7)。

若将来需要更结构化的结果,可以约定:让 Cursor 在输出里带一段特定标记(如 RESULT_JSON: {...}),OpenClaw 再解析。

⚠️ 实际踩坑 5:输出截断

Agent 的输出可能非常长(尤其是 diff),全存会占空间,全推飞书也会超长。
解决:做智能截断(例如保留前 1000 字 + 后 500 字),或把完整日志存成文件,在飞书里只推摘要 + 「完整日志见 xxx 路径」。

⚠️ 实际踩坑 6:编码问题

Windows 下子进程的 stdout/stderr 可能是 GBK,直接读会中文乱码。
解决:子进程里指定 encoding: 'utf-8',或在调用前用 chcp 65001 把控制台切到 UTF-8。


七、OpenClaw → 飞书:把结果推回去

任务状态更新后,根据 task_id 找到对应的飞书上下文(群 ID / 私聊 ID、原消息 ID、发送人),调用飞书开放平台的「发消息」接口,把执行结果推回去。

推什么
简明摘要(成功 / 失败)、关键日志或「详细日志见附件/文件路径」。这样用户在同一会话里就能看到「任务已完成 + 结果」。

体验闭环
用户在飞书发一条「让 Cursor 干活」的消息 → 过一段时间在同一会话收到机器人回复「任务已完成 + 结果」。

建议在任务一开始就先发一条「已接收任务,正在执行中」的快速回复(见踩坑 9),避免用户以为没收到。

⚠️ 实际踩坑 7:飞书消息长度限制

单条消息有长度上限(通常约 2 万字符),过长会被拒绝。
解决:分多条发送(先发摘要,再分段发日志),或用飞书富文本卡片做折叠。

⚠️ 实际踩坑 8:Markdown 格式

飞书支持的 Markdown 有限,部分语法或特殊字符会显示异常。
解决:用简化的 Markdown,代码块用标准 ``` 语法,避免飞书不支持的特性。


八、错误处理与可落地的细节

  • Cursor CLI 未安装 / 找不到:任务标记失败,在飞书里提示「请在本机配置 Cursor CLI」。
  • 执行超时:子进程设超时(具体策略见第五节踩坑 4),超时则终止进程,任务标记失败,原因写 timeout
  • 退出码非 0:标记失败,结果里附带 stderr/stdout 摘要,方便用户在飞书里看到报错。

可选:对网络抖动等临时异常做有限次数重试(如 1~2 次)。

⚠️ 实际踩坑 10:网络问题

Cursor Agent 会访问远程 API,网络不稳定可能导致任务失败。
解决:识别常见错误(如 ECONNRESET、ETIMEDOUT),在飞书里给友好提示,并可选做重试。

⚠️ 实际踩坑 11:项目路径不存在或无权限

用户填的项目路径可能不存在,或 OpenClaw 运行用户没有读写权限。
解决:在执行前检查路径存在性 + 权限,不通过则直接返回明确错误,不发起 Cursor 子进程。


九、实战插件:feishu-cursor-cli 是怎么把这些步骤拼在一起的

我在本地写了一个简单的 OpenClaw 插件 feishu-cursor-cli,基本就是把上面这几节的思路串成了一段代码,方便你参考(这里只保留关键片段,完整实现可以联系作者获取):

  1. 先定义一个和文中任务模型对应的数据结构
// cursor_cli_agent.js 中的核心结构(只示意关键字段)
const task = {
  id: taskId,
  task_type: taskType,
  project: { root: projectRoot },
  payload: {
    natural_language: text.trim(),
    // files / constraints 等可按需补充
  },
};
  1. 把这个任务对象转成给 Cursor CLI 的 Prompt 文本
    对应第五节里的「Prompt 从哪来」
// 根据任务模型构造给 Cursor CLI 的 Prompt(核心思路)
function buildPromptFromTask(task) {
  return [
    "你是一个代码开发 Agent,请在当前仓库完成下面任务。",
    "",
    `任务 ID: ${task.id}`,
    `任务类型: ${task.task_type}`,
    "",
    "自然语言需求:",
    task.payload.natural_language,
    // 如需,可在此追加 files / constraints 等信息
  ].join("\n");
}
  1. 在项目目录里真正执行 Cursor CLI
    对应第五、六节里的子进程调用 + 结果收集(省略了一些样板代码,只保留关键逻辑)。下面示例以 Windows 环境为例,使用 cmd.exe 作为 shell,在 macOS / Linux 上可以去掉 shell 参数或改用 /bin/bash
// 在指定项目目录下调用 Cursor CLI(只保留核心结构)
async function runCursorCliTask(task, options = {}) {
  const cwd = path.resolve(task.project.root);
  const prompt = buildPromptFromTask(task);

  return new Promise((resolve, reject) => {
    const child = spawn("agent", [], {
      cwd,
      shell: "cmd.exe", // Windows 示例;在 macOS / Linux 上可改为 "/bin/bash" 或直接省略
      env: { ...process.env, ...(options.env || {}) },
    });

    let output = "";
    child.stdin.write(prompt);
    child.stdin.end();

    child.stdout.on("data", (data) => (output += data.toString()));
    child.stderr.on("data", (data) => (output += data.toString()));

    child.on("error", (err) => reject(err));
    child.on("close", (code) =>
      resolve({ success: code === 0, exitCode: code, output })
    );
  });
}
  1. 写一个简单的「调度函数」来更新任务状态
    对应第八节错误处理和第七节结果收集
// 调度封装:围绕 runCursorCliTask 更新任务状态(极简版)
async function dispatchToCursorCli(task, updateStatus) {
  await updateStatus({ status: "running" });
  try {
    const result = await runCursorCliTask(task);
    await updateStatus({
      status: result.success ? "done" : "failed",
      result_summary: result.success ? "执行成功" : "执行失败",
      result_output: (result.output || "").slice(0, 20000),
    });
  } catch (err) {
    await updateStatus({
      status: "failed",
      result_summary: "调用 Cursor CLI 出错",
      result_output: String(err),
    });
  }
}
  1. 最后,用一个 Feishu 文本解析器把「自然语言消息」转成上面的任务对象
    对应第三、四节「飞书 → OpenClaw」+「统一任务模型」(这里给简化版示例)
// 简单 Feishu 文本解析器(只保留思路示意)
function buildTaskFromFeishuText(text, { taskId, defaultProjectRoot }) {
  const projectRoot =
    text.match(/项目[::]\s*([A-Za-z]:[^\s,。;;]*)/)?.[1]?.trim() ||
    defaultProjectRoot;

  const payload = { natural_language: text.trim() };
  // 这里可按需解析文件名 / 语言约束 / 任务类型等

  return {
    id: taskId,
    task_type: "code_edit",
    project: { root: projectRoot },
    payload,
  };
}
  1. 在插件入口里,把这些拼成一个真正能跑的 OpenClaw 插件
// index.js(入口极简示意)
const { buildTaskFromFeishuText, dispatchToCursorCli } =
  require("./cursor_cli_agent.js");

module.exports = {
  id: "feishu-cursor-cli",
  async handleFeishuMessage({ text, chatId, messageId, userId, sendReply, saveTask, updateTask }) {
    const taskId = `task_${Date.now()}`;
    const task = buildTaskFromFeishuText(text, {
      taskId,
      defaultProjectRoot: "F:\\cursor_work",
    });

    await saveTask(taskId, { from_chat: { chatId, messageId, userId }, task });

    await dispatchToCursorCli(task, async (partial) => {
      await updateTask(taskId, partial);
      if (partial.status === "done" || partial.status === "failed") {
        await sendReply(chatId, messageId, partial.result_summary);
      }
    });
  },
};

可以看到,这个插件本质上就是把本文讲的几步——「解析 Feishu 文本 → 构造任务对象 → 在项目目录中调用 Cursor CLI → 更新任务状态并截断输出 → 通过 Feishu 回推结果」用代码完整串起来,方便你参考或直接改成自己的版本。


十、手把手实操:一条消息让 Cursor CLI 写出冒泡排序

下面用一个完整例子,把整个流程串起来。

示例需求:请使用 Cursor CLI,在项目 F:\cursor_work\ 里,帮我写一个冒泡排序算法,使用 Python 编写,写入到 .py 文件中。


步骤 1:在飞书里发出任务指令

step1.png

此时飞书会把这条消息通过事件订阅 / 消息回调推送到你的 OpenClaw HTTP 接口。


步骤 2:OpenClaw 收到消息并生成内部任务

OpenClaw 的 Feishu 插件会解析这条文本,提取出:

  • 项目路径:F:\cursor_work\
  • 核心需求:用 Python 写冒泡排序,输出到 bubble_sort.py

然后包装成统一的任务对象,例如(简化示意):

{
  "id": "task_xxx",
  "task_type": "code_edit",
  "project": { "root": "F:\\\\cursor_work" },
  "payload": {
    "natural_language": "在项目 F:\\cursor_work 里,用 Python 写一个冒泡排序算法,写入到 bubble_sort.py 中。"
  }
}

步骤 3:OpenClaw 在 F:\cursor_work 目录里调用 Cursor CLI

OpenClaw 根据任务里的 project.root,在该目录下通过子进程执行 agent 命令,并把上一步构造好的 Prompt 写入到标准输入中,大致等价于:

cd F:\cursor_work
agent

然后由插件代码把「冒泡排序需求」作为一整段 Prompt 喂给 Cursor CLI。

step2.png


步骤 4:Cursor CLI 在仓库中创建 / 更新 bubble_sort.py

Cursor CLI 接收到 Prompt 后,会自动在当前仓库中:

  • 搜索现有文件,看是否已经有相关实现;
  • 若没有,则新建 bubble_sort.py

步骤 5:OpenClaw 收集 Cursor CLI 的执行结果

当这次 agent 调用结束、子进程退出时,OpenClaw 会拿到:

  • 标准输出 / 标准错误(stdout/stderr)拼成的执行日志;
  • 退出码(0 表示成功,非 0 视为失败)。

插件会把这些信息写回任务记录中,例如:

  • status: "done""failed"
  • result_summary: "执行成功,已在 bubble_sort.py 中写入冒泡排序示例"
  • result_output: 截断后的部分 CLI 输出内容

步骤 6:通过飞书把结果回推给用户

最后,OpenClaw 根据任务里保存的 chat_id / message_id,调用飞书开放平台的发送消息接口,在同一会话里给用户回一条结果消息,例如:

step3.jpg

到这里,一个完整闭环就跑通了:飞书发指令 → OpenClaw 编排 → Cursor CLI 落地写码 → OpenClaw 收集结果 → 飞书回推摘要


十一、(可选)扩展这个示例:再让 Cursor CLI 跑一遍测试

在前面的冒泡排序例子基础上,你还可以:

  • 让用户再发一条指令:「在同一个项目下,给 bubble_sort.py 补充简单的单元测试,并运行一次。」
  • OpenClaw 将其识别为 task_type: "run_tests",在 F:\cursor_work 中调用 Cursor CLI,让它自动补充测试文件并执行。
  • 执行完毕后,同样把「测试结果摘要 + 关键日志」通过飞书发回给用户。

这样,一个非常贴近真实工作的「写功能 → 补测试 → 看结果」闭环,就完全建立在飞书 + OpenClaw + Cursor CLI 之上了。

十二、总结:飞书是入口,OpenClaw 是编排,Cursor CLI 是执行体

通过以上步骤,你已经完成了:

  1. 理清整条链路:从飞书发任务到 Cursor 执行再回推飞书
  2. 统一任务模型:飞书消息转成内部任务,用 task_id 串联
  3. 在项目目录中调用 Cursor CLI:子进程 + 超时 + 结果收集
  4. 把结果推回飞书:在飞书里看到每个任务的执行结果(可先「执行中」,再发详情)
  5. 处理常见踩坑:路径、登录、编码、长度、网络、权限等

接下来可以在此基础上继续扩展,例如:多项目配置、权限控制、结果结构化(RESULT_JSON)、任务取消等。若以后 Cursor 提供更强的集成方式,当前以 CLI 为核心的设计也便于平滑升级。

🌟 飞书只是你发任务、收结果的入口;
真正的编排中枢是你本地的 OpenClaw,执行体是 Cursor CLI。
现在,就在飞书里发一条消息,让 Cursor 在你项目里干一票吧。🦞💬

  • 1 / 1 页
敬请注意:文中内容观点和各种评论不代表本网立场!若有违规侵权,请联系我们.