把 AI 编码 Agent 桥接到飞书(Claude / Codex / MiMo / OpenHuman)
基于 francize/agents-to-im 二次开发,支持多 Runtime、多实例部署、动态模型显示。
Claude Code 和 Codex 都是好用的终端 AI 编码工具,但有几个痛点:
- 只能在终端用:团队协作在飞书,但 AI 编码只能在本地终端,来回切换麻烦
- 单实例限制:原版只能运行一个实例,无法同时跑 Claude 和 Codex
- 命令误判:原版把
/opt/xxx这类路径识别为命令,导致工作目录设置失败 - 部署不持久:手动启动容易丢失,重启后需要重新配置
本项目解决这些问题:
- ✅ 双实例同时运行(Claude + Codex 各自独立配置和状态)
- ✅ systemd 用户服务自动启动,重启不丢失
- ✅ 命令白名单机制,路径不再被误判为命令
- ✅ 独立工作目录,互不干扰
- ✅ 飞书用户身份发送消息(OAuth 授权,以用户而非机器人身份发消息)
- ✅ 多 Agent 路由(GLM / Gemini / Opencode 通过 MiMo 网关统一调度)
用户 (飞书)
│
├─ feishu-mimo ──→ LiteLLM ──→ MiMo-Go / DsV4go / codex-model
│ (独立配置) (代理层)
│
├─ feishu-claude ──→ LiteLLM ──→ claude-model / MiMo-Anthropic
│ (独立配置) (代理层)
│
├─ feishu-codex ──→ LiteLLM ──→ codex-model
│ (独立配置) (代理层)
│
└─ feishu-openhuman ──→ LiteLLM ──→ claude-model
(独立配置) (代理层)
每个实例独立运行,有自己的:
- 飞书应用配置(APP_ID / APP_SECRET)
- 端口(Dashboard 互不冲突)
- 工作目录
- 会话状态
- 模型配置(通过 LiteLLM 代理)
原版问题: 把所有 / 开头的文本当作命令,导致 /opt/.openclaw/workspace 这类路径被误判为命令。
修改: 加入命令白名单,只有这些命令才触发处理:
/new /new:claude /new:codex /new:glm /new:gemini /new:opencode
/reset /stop /start /help /status /cwd /mode /bind /sessions
其他 / 开头的文本(如路径)都当作普通消息处理。
原版问题: /new:claude 和 /new:codex 的处理逻辑分散,容易出错。
修改: 统一到一个处理函数,根据命令后缀自动选择运行时:
/new→ 用默认运行时/new:claude→ 强制 Claude/new:codex→ 强制 Codex
新增配置模板和服务文件,支持同时部署 Claude 和 Codex 两个实例。
支持以飞书用户身份(而非机器人身份)发送消息,让 AI 回复显示为用户自己发出,适用于 OpenHuman 等场景。
工作原理:
- 通过飞书 OAuth 2.0 授权流程获取
user_access_token - Dashboard 提供
/api/auth/url生成授权链接,/oauth/callback处理回调 lark-client.ts中withUserAccessToken方法自动附加用户令牌adapter.ts中shouldUseUserToken()判断是否使用用户身份
新增配置项:
| 变量 | 说明 |
|---|---|
CTI_OAUTH_REDIRECT_URI |
OAuth 回调地址 |
CTI_ENABLE_USER_MODE |
启用用户身份模式 |
支持多种 AI 编码工具作为 Runtime:
| Runtime | 说明 | 命令 |
|---|---|---|
| claude | Claude Code CLI | /new:claude |
| codex | Codex CLI | /new:codex |
| mimo | MiMo 通过 LiteLLM | /new:mimo |
| openhuman | OpenHuman Agent | /new:openhuman |
- 每个 Runtime 独立配置模型和 Provider
- 通过 LiteLLM 代理层统一管理模型路由
- 支持动态切换模型(修改配置后重启服务)
每条消息底部自动显示 Agent 信息:
Agent: feishu-mimo | Model: MiMogo | Provider: LiteLLM
配置项:
| 变量 | 说明 | 示例 |
|---|---|---|
CTI_FEISHU_SHOW_AGENT_DIVIDER |
是否显示消息底部 divider | true |
CTI_AGENT_NAME |
Agent 名称(显示在 divider) | feishu-mimo |
CTI_MODEL_GROUP |
模型组名(显示在 divider) | MiMogo |
CTI_MODEL_PROVIDER |
服务商名(显示在 divider) | LiteLLM |
特点:
- 所有 Runtime 统一配置方式
- 修改配置后重启服务即生效
- 支持动态切换模型,divider 自动更新
- Node.js 20.6+
- 已安装 Claude Code CLI 和/或 Codex CLI
- 两个飞书应用(分别给 Claude 和 Codex 用)
# 安装原版包
npm install -g agents-to-im
# 克隆本仓库
git clone https://github.com/oadank/agents-to-im.git
cd agents-to-im# 创建实例目录
mkdir -p ~/.agents-to-im-claude
# 复制配置模板
cp instances/feishu-claude/config.env.example ~/.agents-to-im-claude/config.env
# 编辑配置,填写飞书应用密钥
$EDITOR ~/.agents-to-im-claude/config.env
# 安装 systemd 服务
cp systemd/feishu-claude.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now feishu-claude.servicemkdir -p ~/.agents-to-im-codex
cp instances/feishu-codex/config.env.example ~/.agents-to-im-codex/config.env
$EDITOR ~/.agents-to-im-codex/config.env
cp systemd/feishu-codex.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now feishu-codex.service# 查看服务状态
systemctl --user status feishu-claude.service
systemctl --user status feishu-codex.service
# 查看日志
journalctl --user -u feishu-claude.service -fCTI_DEFAULT_WORKDIR=/opt # 默认工作目录
CTI_FEISHU_APP_ID=cli_XXXXXXXXXXXXX # 飞书应用 ID
CTI_FEISHU_APP_SECRET=XXXXXXXXX # 飞书应用密钥
CTI_FEISHU_SHOW_TOOL_CALL_CARDS=false # 不显示工具调用卡片
CTI_DEFAULT_RUNTIME=claude # 默认运行时
CTI_DASHBOARD_PORT=13579 # Dashboard 端口
CTI_DISABLE_PERMISSION_CHECK=true # 禁用权限检查CTI_DEFAULT_WORKDIR=/opt
CTI_FEISHU_APP_ID=cli_YYYYYYYYYYYYYYYY # 另一个飞书应用
CTI_FEISHU_APP_SECRET=YYYYYYYYY
CTI_FEISHU_SHOW_TOOL_CALL_CARDS=false
CTI_DEFAULT_RUNTIME=codex # 默认运行时改为 codex
CTI_DASHBOARD_PORT=13580 # 端口与 Claude 不同
CTI_DISABLE_PERMISSION_CHECK=true| 变量 | 说明 |
|---|---|
CTI_FEISHU_APP_ID |
飞书开放平台的应用 ID |
CTI_FEISHU_APP_SECRET |
飞书应用密钥 |
CTI_DEFAULT_RUNTIME |
claude、codex、mimo 或 openhuman |
CTI_DASHBOARD_PORT |
控制面板端口,每个实例必须不同 |
CTI_DEFAULT_WORKDIR |
默认工作目录 |
CTI_FEISHU_SHOW_AGENT_DIVIDER |
是否显示消息底部 divider(默认 true) |
CTI_AGENT_NAME |
Agent 名称,显示在 divider |
CTI_MODEL_GROUP |
模型组名,显示在 divider |
CTI_MODEL_PROVIDER |
服务商名,显示在 divider |
每个实例需要一个独立的飞书应用:
- 在 飞书开放平台 创建自定义应用
- 启用 机器人 能力
- 添加权限:
im:message、im:chat、im:chat.group等 - 事件订阅:
im.message.receive_v1 - 长连接模式:启用 WebSocket
- 发布应用
详细步骤参考:原项目 Setup Guide
在飞书里直接对话:
/new:claude # 创建 Claude 会话
/new:codex # 创建 Codex 会话
/new:mimo # 创建 MiMo 会话
/new:openhuman # 创建 OpenHuman 会话
/reset # 重置当前会话
/stop # 停止当前输出
/status # 查看状态
/help # 帮助
⚠️ 这是生产环境部署的核心文档。我们花了整整 3 天踩坑调试,每一步都是血泪教训,照着做可以节省你至少 20 小时。
在 Windows 上部署后台服务有几种方式:
- pm2: 不适用(Node.js 应用,但我们的 ACP 子进程需要 Windows Session 0 特殊处理)
- winsw: XML 配置复杂,Debug 困难
- nssm: Windows 原生服务管理器,C 编写,轻量可靠,调试信息完整 → 推荐
# 安装 NSSM(用 scoop 或 chocolatey)
scoop install nssm
# 或
choco install nssm
# 验证安装
nssm version必须在 config.env 里明确设置以下变量,不要依赖系统环境变量:
# 工作目录要用绝对路径,不要用 ~ 或 %USERPROFILE%
CTI_DEFAULT_WORKDIR=C:\D\opt
# 飞书配置
CTI_FEISHU_APP_ID=cli_XXXXXXXXXXXXX
CTI_FEISHU_APP_SECRET=XXXXXXXXXXXXXX
# 必须禁用工具调用卡片(NSSM Session 0 下有问题)
CTI_FEISHU_SHOW_TOOL_CALL_CARDS=false
# Dashboard 端口(每个 Provider 不同)
CTI_DASHBOARD_PORT=13581
# ACP 子进程环境配置(关键!)
APPDATA=C:\Users\你的用户名\AppData\Roaming
USERPROFILE=C:\Users\你的用户名Windows 上有两种部署方式。Codex 必须使用计划任务,其他 Provider 可用 NSSM。
Codex CLI 内置的 node-pty 调用 CreateFileMappingW 创建 ConPTY,在 Session 0 下必然失败(os error 5)。NSSM 服务无论怎么配置都无法解决这个问题,因此 Codex 必须在用户交互式会话(Session 1+)中运行。
原理:通过 Windows 计划任务,以 InteractiveToken 在用户登录时启动,daemon 和子进程都跑在用户 Session 中,ConPTY 正常工作。
创建 C:\Users\你的用户名\.agents-to-im\start-codex-task.bat:
@echo off
set "CTI_BOT=codex"
set "CTI_HOME=C:\Users\你的用户名\.agents-to-im"
set "CTI_DASHBOARD_PORT=13581"
set "CTI_LOG_LEVEL=debug"
set "CTI_DEFAULT_WORKDIR=C:\D\opt"
set "CTI_DISABLE_PERMISSION_CHECK=true"
set "CTI_FEISHU_ALLOWED_USERS=*"
set "CTI_DEFAULT_RUNTIME=codex"
set "CTI_FEISHU_APP_ID=<从 config.env 读取>"
set "CTI_FEISHU_APP_SECRET=<从 config.env 读取>"
set "CTI_FEISHU_SHOW_TOOL_CALL_CARDS=true"
set "CTI_FEISHU_SHOW_AGENT_DIVIDER=true"
set "CTI_BOT_CODEX_APP_ID=<从 config.env 读取>"
set "CTI_BOT_CODEX_APP_SECRET=<从 config.env 读取>"
set "CTI_BOT_CODEX_RUNTIME=codex"
set "CTI_BOT_CODEX_AGENT_NAME=codex"
set "CTI_BOT_CODEX_MODEL_GROUP=codex-model"
set "CTI_BOT_CODEX_MODEL_PROVIDER=LiteLLM"
set "CTI_BOT_CODEX_SHOW_TOOL_CALL_CARDS=true"
set "CTI_BOT_CODEX_SHOW_AGENT_DIVIDER=true"
set "OPENAI_API_KEY=<从 config.env 读取>"
set "CODEX_CLI_PATH=C:\Users\你的用户名\AppData\Roaming\npm\codex.exe"
set "CODEX_HOME=C:\Users\你的用户名\.codex"
set "HOME=C:\Users\你的用户名"
set "USERPROFILE=C:\Users\你的用户名"
set "APPDATA=C:\Users\你的用户名\AppData\Roaming"
set "PATH=C:\Program Files\Git\bin;C:\Program Files\Git\usr\bin;C:\Users\你的用户名\AppData\Roaming\npm;C:\Program Files\nodejs;C:\Windows\System32;C:\Windows;C:\Windows\System32\WindowsPowerShell\v1.0;%PATH%"
set LOG_DIR="C:\Users\你的用户名\.agents-to-im\logs"
mkdir "%LOG_DIR%" 2>nul
:LOOP
"C:\Program Files\nodejs\node.exe" "C:\D\opt\agents-to-im\dist\daemon.mjs" >> "%LOG_DIR%\codex-task.stdout.log" 2>> "%LOG_DIR%\codex-task.stderr.log"
timeout /t 5 /nobreak >nul
goto LOOP注意:bat 中不要直接写真实密钥。建议从
config.env读取或用环境变量覆盖。
创建 C:\Users\你的用户名\.agents-to-im\start-codex-task.vbs:
Set shell = CreateObject("WScript.Shell")
result = shell.Run("""C:\Users\你的用户名\.agents-to-im\start-codex-task.bat""", 0, True)
WScript.Quit result$taskName = 'agents-codex'
$vbs = 'C:\Users\你的用户名\.agents-to-im\start-codex-task.vbs'
# 停止并禁用 NSSM 服务(如果之前用过 NSSM)
Stop-Service -Name $taskName -Force -ErrorAction SilentlyContinue
Set-Service -Name $taskName -StartupType Disabled
# 创建计划任务
$action = New-ScheduledTaskAction -Execute 'C:\Windows\System32\wscript.exe' -Argument "`"$vbs`""
$trigger = New-ScheduledTaskTrigger -AtLogOn -User 'LECOO\oadan'
$principal = New-ScheduledTaskPrincipal -UserId 'LECOO\oadan' -LogonType Interactive -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-ExecutionTimeLimit ([TimeSpan]::Zero) `
-MultipleInstances IgnoreNew `
-RestartCount 999 `
-RestartInterval (New-TimeSpan -Minutes 1) `
-StartWhenAvailable
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings | Out-Null
# 立即启动
Start-ScheduledTask -TaskName $taskName# 确认任务状态
Get-ScheduledTask -TaskName 'agents-codex' | Select-Object TaskName, State
# 确认进程在 Session 1(不是 Session 0)
Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object {
$_.CommandLine -match 'agents-to-im\\dist\\daemon.mjs' -and $_.SessionId -eq 1
} | Select-Object ProcessId, SessionId
# 确认 Dashboard 端口
Test-NetConnection -ComputerName 127.0.0.1 -Port 13581 -InformationLevel Quiet# 杀掉 daemon 进程,确认 bat 的 :LOOP 会在 5 秒内重启
Stop-Process -Id <PID> -Force
# 等待新 PID 出现,端口恢复对于 Hermes、MiMo、Gemini 等不需要原生 ConPTY 的 Provider,NSSM 服务更合适(24/7 运行,不依赖用户登录)。
环境变量必须用 REG_MULTI_SZ,不能用 nssm set AppEnvironment 拼接空格分隔字符串,否则会破坏环境变量导致服务崩溃。
日志路径必须先存在,否则服务启动即退出。
这是这次调试 3 天的核心发现:
现象:
- 手动
node dist/daemon.mjs运行一切正常 - NSSM 服务启动后,发飞书消息永远卡死在
conversation turn: - 没有报错,没有超时,进程状态正常,就是不响应
根因:
Windows Session 0(服务运行的隔离环境)没有真实的 conhost.exe。当 Python/Node.js 子进程做以下操作时会永久死锁:
git status/git rev-parse等 git 命令(Hermes 的coding_system_blocks())subprocess.run()捕获 stdout/stderr 时,句柄继承失败- Windows API
GetConsoleWindow()返回NULL导致无限等待 - Codex CLI 内置的
node-pty调用CreateFileMappingW创建 ConPTY 失败(os error 5)
解决方案:
- ✅ 服务账户使用
.\oadan,并显式设置APPDATA、USERPROFILE和PATH - ✅ 环境变量必须以
REG_MULTI_SZ写入AppEnvironmentExtra - ✅ 代码层对
platform == "acp"跳过不必要的 git/filesystem 探测(见下文) - ✅ Codex 必须使用 Task Scheduler 的
InteractiveToken在用户 Session 中启动(见第二步) - ❌ NSSM 的
SERVICE_INTERACTIVE_PROCESS(Type=0x110) 在 Windows 11 实测不能把子进程移出 Session 0,ConPTY 仍失败
现象:加了 PYTHONUNBUFFERED=1 还是卡死。
根因:这个环境变量只解决 Python 的 stdout 缓冲问题,不解决 git 子进程的 Windows API 级死锁。
现象:一开始以为是 SQLite 数据库锁。加了 WAL、加了 timeout、试了内存模式,全部无效。
根因:卡死发生在 build_system_prompt() 的 git 探测阶段,根本还没到 SQLite 写入的 _ensure_db_session()。
现象:Hermes 启动后提示找不到 .hermes 目录。
根因:Session 0 下 os.homedir() 返回 C:\Windows\System32\config\systemprofile 而非用户目录。
解决方案:AppEnvironment 中必须显式设置 USERPROFILE 和 APPDATA。
Hermes 是唯一用 Python ACP 的,Session 0 死锁最严重。
修复位置:C:\Users\oadan\AppData\Local\hermes\hermes-agent\agent\system_prompt.py
# 在 coding_system_blocks() 调用前加条件(约 350 行)
# NOTE: Skip for ACP platform — non-interactive service (NSSM/Session 0)
# can hang in git/filesystem probes; ACP clients don't need workspace context.
if agent.valid_tool_names and agent.platform != "acp":
# ... 原来的 coding_system_blocks() 代码 ...
# 在 env_probe 调用前加同样条件(约 380 行)
if getattr(agent, "_environment_probe", True) and agent.platform != "acp":
# ... 原来的 env_probe 代码 ...同时:hermes-app-server-client.ts spawn 时必须传正确的 env:
const proc = spawn(this.executable, args, {
stdio: ['pipe', 'pipe', 'pipe'],
env: {
...process.env,
HOME: os.homedir(),
HERMES_HOME: resolveHermesHome(),
USERPROFILE: os.homedir(),
APPDATA: process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'),
PYTHONUNBUFFERED: '1', // 虽然解决不了死锁,但还是要加
},
windowsHide: true, // 只隐藏窗口,不影响句柄
});修复位置:src/providers/codex/codex-provider.ts
// execSync → exec(异步),避免阻塞事件循环
import { exec } from 'node:child_process'; // 不要用 execSync
// fs 同步 → fs/promises
import fs from 'node:fs/promises';
// running 事件必须在 try 之前 emit
emitCanonicalTurnEvent(controller, { type: 'status', data: { status: 'running' } });
try {
// ... 工具执行 ...
} catch (e) {
// ...
}修复位置:src/providers/mimo/mimo-provider.ts
// 必须先声明 env,再传给 spawn
function buildSpawnEnv(): NodeJS.ProcessEnv {
return { ... };
}
const env = buildSpawnEnv(); // 不要漏掉这行!
const child = spawn(command, ['acp', ...], {
env, // 用声明的变量,不要直接写 buildSpawnEnv()
// ...
});
// streamChat 入口必须加 async try/catch,防止 void runAcp 吞掉错误
async streamChat(params: StreamChatParams): ReadableStream<string> {
try {
// ...
} catch (e) {
console.error('[mimo-provider] Error:', e);
throw e;
}
}修复位置:src/providers/gemini/gemini-provider.ts
// drain 等待必须加超时,否则 wakeQueue 永远不 resolve
const MAX_DRAIN_WAIT_MS = 3000;
const drainStart = Date.now();
// 在 drain 循环里
() => {
const elapsed = Date.now() - drainStart;
if (elapsed >= MAX_DRAIN_WAIT_MS || queue.length > 0) {
if (queue.length === 0) return Promise.reject(new Error('drain-done'));
return;
}
const remainingMs = MAX_DRAIN_WAIT_MS - elapsed;
return new Promise<void>((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('drain-done')), remainingMs);
wakeQueue = () => {
clearTimeout(timer);
resolve();
};
});
}# 启动服务
Start-Service agents-hermes
# 查看状态
Get-Service agents-hermes
# Status 应该是 Running
# 查看进程(应该有 2 个:node daemon.mjs + hermes acp 子进程)
Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like "*hermes*" } | Select-Object ProcessId, CommandLine
# 查看日志
Get-Content C:\Users\你的用户名\.agents-to-im\logs\hermes-stderr.log -Tail 50 -Wait- 去飞书找到对应的 Bot
- 发消息 "测试"
- 如果 10 秒内有回复,成功了!
- 如果超过 30 秒没回复:
- 看日志有没有
conversation turn:— 有说明走到了 Python 层 - 如果卡在
conversation turn:后面不动,说明还是 Session 0 死锁 - 回查 NSSM 的
Allow service to interact with desktop和Create console window是否勾选 - 回查 Python
system_prompt.py里platform != "acp"是否正确
- 看日志有没有
| Provider | 服务名 | Dashboard 端口 |
|---|---|---|
| Claude | agents-claude | 13580 |
| Codex | agents-codex | 13581 |
| Gemini | agents-gemini | 13582 |
| MiMo | agents-mimo | 13583 |
| Hermes | agents-hermes | 13584 |
| 问题 | 排查方向 | 解决方案 |
|---|---|---|
| 服务启动后立即退出 | 日志文件路径是否存在、Node 路径是否正确、环境变量是否正确 | nssm edit agents-xxx 检查 I/O 标签页路径是否有写入权限 |
| 能建立 session,但发消息卡死 | Python 层 Session 0 死锁 | 检查 coding_system_blocks() 跳过逻辑 + NSSM 的两个 checkbox |
| 回复很慢(90秒) | drain 等待超时 | 检查 MAX_DRAIN_WAIT_MS setTimeout 逻辑(Gemini/MiMo) |
| 能建立 session,但不发消息 | ReferenceError 被 void 吞掉 | 检查 spawn env 变量是否先声明(MiMo/Hermes) |
| 工具调用不显示卡片 | 事件循环阻塞 | 检查是否用了 execSync 或同步 fs 调用(Codex) |
这些都是实际生产环境遇到的问题,每一个都导致服务至少 1 小时不可用。
时间: 2026-07-14
现象: 手动运行正常,NSSM 服务发消息永久卡死在 conversation turn:
根因: Windows Session 0 下 coding_system_blocks() 的 git 探测导致子进程死锁
修复文件:
C:\Users\oadan\AppData\Local\hermes\hermes-agent\agent\system_prompt.py(核心 Python 修复)src/providers/hermes/hermes-app-server-client.ts(TypeScript spawn env 修复)
Commit: 9372bda
时间: 2026-07-14
现象: session/new 返回成功,但后续 session/prompt 永远不执行,锁 90 秒超时
根因: createCacheEntry() 引用未声明的 env 变量,抛 ReferenceError 被 void runAcp 静默吞掉
修复文件: src/providers/mimo/mimo-provider.ts
Commit: cd8893b
时间: 2026-07-14
现象: LLM 2-3 秒生成完,但要等 90 秒才在飞书显示
根因: drain 等待逻辑中 wakeQueue = resolve 没有新通知唤醒,永久等待直到全局 90 秒超时
修复文件: src/providers/gemini/gemini-provider.ts
Commit: ac36b89
时间: 2026-07-12
现象: 工具执行正常,但三栏预览的"正在运行"卡片永远不显示
根因: execSync() 阻塞 Node.js 事件循环,running 事件无法 emit
修复文件: src/providers/codex/codex-provider.ts
Commit: cf7fd2e
时间: 2026-07-15
现象: 自动创建会话失败:Claude CLI preflight check failed: claude CLI at "xxx" failed to execute
根因: claude-sidecar-x86_64-pc-windows-msvc.exe(Tauri 应用)内部 spawn Node.js v24,在 Windows Session 0 中触发 ncrypto::CSPRNG(nullptr, 0) 断言崩溃,BCryptGenRandom 不可用。
修复:
- CLI 路径改用
C:\Windows\System32\claude.bat(基于bun运行,不触发 Node.js CSPRNG) multiplex.ts中getClaudeProvider()预检失败时 warn 而非 throw(容错设计)bridge-manager.ts中空错误对象{}降为 debug 日志(SDK 传输层 teardown 噪声)
修复文件:
config.env:CTI_CLAUDE_CODE_EXECUTABLE=C:\Windows\System32\claude.batsrc/providers/multiplex.ts:预检失败 warn(line 90-93)src/providers/claude/cli-support.ts:getCliVersion 增加错误日志src/bridge/bridge-manager.ts:空错误对象降为 debug
注意事项: claude.bat 依赖 bun 和 C:\D\opt\cc-haha 源码目录,非编译二进制。
MIT License
- 原项目:francize/agents-to-im
- Claude Code:Anthropic
- Codex:OpenAI
- NSSM:Non-Sucking Service Manager