<div align="center">
  <img src="assets/ccd-icon.png" width="180" alt="cc-ding logo">
  <h1>cc-ding</h1>
</div>

[![npm version](https://img.shields.io/npm/v/cc-ding.svg?style=flat-square)](https://www.npmjs.com/package/cc-ding)
[![npm downloads](https://img.shields.io/npm/dm/cc-ding.svg?style=flat-square)](https://www.npmjs.com/package/cc-ding)
[![License](https://img.shields.io/npm/l/cc-ding.svg?style=flat-square)](LICENSE)
[![Node.js](https://img.shields.io/node/v/cc-ding.svg?style=flat-square)](https://nodejs.org)
[![GitHub stars](https://img.shields.io/github/stars/yihuineng/cc-ding.svg?style=flat-square)](https://github.com/yihuineng/cc-ding/stargazers)

> 将 Claude Code 接入钉钉，构建企业级 AI 协作工作流。
>
> Connect Claude Code to DingTalk for enterprise-grade AI collaboration.

**[中文](#中文--简体中文)** | **[English](#english)**

---

## 中文 | 简体中文

将 Claude Code 接入钉钉，实现双向通信。支持多轮对话、任务队列、定时任务、图片识别，帮助团队以最低成本构建可私有化部署的 AI 助手。

### 交流群

扫码加入钉钉或微信交流群：

<p align="center">
  <img src="assets/qrcode-dingtalk.jpg" alt="钉钉交流群二维码" width="250">
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  <img src="assets/qrcode-wechat.jpg" alt="微信交流群二维码" width="250">
</p>

### 目录

- [快速开始](#快速开始)
- [命令参考](#命令参考)
- [Web Console](#web-console)
- [配置说明](#配置说明)
- [数据存储](#数据存储)
- [开发](#开发)

### 快速开始

#### 安装

```bash
npm i cc-ding -g
```

#### 初始化

```bash
cc-ding init -ci {clientId} -cs {clientSecret} -u {手机号或工号} -dt {defaultDingToken}
```

| 参数 | 说明 |
|------|------|
| `-ci, --clientId` | 钉钉应用 ClientId |
| `-cs, --clientSecret` | 钉钉 Stream 连接密钥 |
| `-u, --user` | 管理员手机号或工号（自动设为 owner 并加入白名单） |
| `-dt, --defaultDingToken` | 兜底钉钉机器人 Token（必填） |
| `-cn, --clientName` | 机器人名称（可选，默认 "cc助手"） |

#### 编辑配置

配置文件位于 `~/.cc-ding/{clientId}/config.json`，参考下方 [配置文件示例](#配置文件示例)。

#### 启动

```bash
# 直接启动
cc-ding run -ci {clientId}

# 推荐：PM2 守护进程
pm2 start --name "cc-ding-{clientId}" npx -- -p cc-ding cc-ding run -ci {clientId}
```

### 命令参考

#### 会话

| 命令 | 说明 |
|------|------|
| `/help` | 查看所有命令 |
| `/log [行数]` | 查看会话日志 |
| `/new [消息]` | 开始新对话 |
| `/resume [ID]` | 恢复历史会话（不指定则恢复最近一个） |
| `/end` | 结束当前会话 |

> 会话自动持久化到 `active.json`，重启后无缝恢复。群内所有白名单用户均可参与。

#### 任务

```
/task <描述>       # 提交任务（自动排队顺序执行）
/task cancel       # 取消任务
```

#### 定时任务

```
/cron <自然语言>             # Claude 自动生成 cron 表达式
/cron 0 9 * * * <描述>       # 直接指定 cron
/cron list                   # 查看列表
/cron pause <id> | resume <id>   # 暂停 / 恢复
/cron delete <id>            # 删除
```

#### 文件操作

| 命令 | 说明 |
|------|------|
| `/ls [目录] [层数]` | 查看目录结构 |
| `/bash <命令>` | 执行任意命令（仅 owner/管理员，执行记录审计日志 `bash-audit.log`） |

#### 管理命令（仅 owner）

| 命令 | 说明 |
|------|------|
| `/info [robot\|session\|task]` | 查看配置/会话/任务信息 |
| `/version` | 版本信息 |
| `/open [shell]` | 打开工作目录 |
| `/clean [all]` | 清除历史和缓存 |
| `/reset-apikeycfg` | 重置 API Key 配置 |
| `/cfg` | 注册当前群到配置（支持 `--permissionMode` 设置权限模式） |
| `/auth [add\|del <用户>]` | 管理群级白名单 |
| `/destroy` | 注销当前群机器人，删除工作目录和配置 |
| `/freedom` | 自由模式：开启后所有群成员均可使用机器人（跳过白名单限制，60s 内回复"确认"即可开启） |
| `/recorder [on\|exit]` | Recorder 模式：记录所有消息到本地（仅 owner 单聊） |
| `/reboot [--update]` | 重启 cc-ding 应用 |

### Web Console

cc-ding 提供了一个 Web 管理界面，用于可视化管理客户端配置、API Key、辅助文件等。

#### 启动 Console

```bash
cc-ding console [--port 8080] [--host 0.0.0.0] [--open]
```

| 参数 | 说明 |
|------|------|
| `--port` | HTTP 监听端口（默认 8080） |
| `--host` | HTTP 监听地址（默认 0.0.0.0） |
| `--open` / `--browser` | 启动后自动打开浏览器 |
| `--no-browser` | 禁止自动打开浏览器 |

也可以通过聊天命令 `/open console` 在本地自动打开 Console 页面。

#### 登录

- 默认账号：`admin` / `admin`
- 首次登录时会强制要求修改密码
- Bearer Token 认证，24 小时过期

#### 功能

- **客户端管理** — 查看所有客户端的在线状态、会话数、API Key 数量
- **配置编辑** — 查看脱敏后的配置、通过 dot-path 语法修改嵌套值、原始 JSON 编辑（写前自动备份）
- **API Key 管理** — 列表 / 添加 / 编辑 / 删除 / 重置，支持切换有效状态
- **文件管理** — 读写辅助 JSON 文件（`menu.json`、`model.json`、`cron.json`、`todo.json`、`user-map.json`、`active.json`）
- **环境变量查看** — 扫描配置中的 `$ENV:` 引用，显示当前进程环境变量值
- **全局配置** — 修改 Console 端口 / 监听地址、编辑 `settings-tpl.json` 模板
- **系统状态** — 版本、平台、运行时间、在线客户端数
- **热重载** — 向客户端进程发送 SIGUSR2 信号触发配置重载

#### URL 深度链接

`/open console` 命令会自动构建深度链接，例如：

```
http://localhost:8080?client=dingiexxdy25itrcuwtb&tab=config
```

- `client` — 自动跳转到指定客户端详情页
- `tab` — 自动切换到指定标签页（`config` / `keys` / `files` / `env` / `raw`）

### 配置说明

#### 配置文件示例

```json
{
  "clientName": "cc助手",
  "owner": "你的手机号",
  "whiteUserList": ["你的手机号"],
  "clientSecret": "钉钉Stream连接密钥",
  "defaultDingToken": "兜底钉钉机器人Token",
  "conversations": [
    {
      "conversationId": "群ID",
      "conversationTitle": "群名称",
      "dingToken": "群机器人Token",
      "whiteUserList": ["工号1", "工号2"],
      "agent": "指定agent（可选）",
      "useLocalOcr": true,
      "permissionMode": "bypassPermissions",
      "taskCfg": { "skill": "指定技能（可选）" },
      "freedomMode": false
    }
  ],
  "taskQueueSize": 50,
  "taskHandlerCount": 1,
  "sessionMaxConcurrency": 20,
  "includeThinking": false,
  "resultOnly": true,
  "debug": false
}
```

#### 配置项速查

| 配置 | 说明 |
|------|------|
| `whiteUserList` | 全局白名单（手机号、工号或 userId） |
| `conversations[].whiteUserList` | 群级白名单，优先级高于全局（手机号、工号或 userId） |
| `apiKeyCfg` | API Key 池化：429 自动切换、每日 0 点重置 |
| `useLocalOcr` | 图片本地 OCR（默认 `true`），模型支持图片时可设 `false` |
| `linkConversationId` | 关联群 ID，多群共享同一 Claude 会话上下文 |
| `permissionMode` | Claude 进程权限模式（默认 `acceptEdits`；`bypassPermissions` 需显式配置，启动时会告警），可选: `default`、`acceptEdits`、`plan`、`auto`、`bypassPermissions`、`dontAsk` |
| `freedomMode` | 自由模式开关（默认 `false`，开启后跳过群用户白名单限制） |
| `preBash` | 全局 `/bash` 前置命令 |
| `agent` | AI 执行引擎：`claude`（默认）或 `codex`（OpenAI Codex CLI） |

### 多 Agent 架构（v1.1.0）

cc-ding 引入了多 Agent 抽象层，支持在不同 AI 执行引擎之间切换。通过在群配置中设置 `agent` 字段，可以为不同群指定不同的执行引擎：

```json
{
  "conversationId": "群ID",
  "agent": "claude"  // 或 "codex"
}
```

- **`claude`**（默认）：使用 Claude Code CLI，支持 `--resume` 会话恢复、API Key 轮换、上下文压缩等完整功能
- **`codex`**：使用 OpenAI Codex CLI，支持线程恢复（`thread_id`）、沙箱模式（`full-auto`）、自动超时恢复等

所有命令（`/goon`、`/!`、`/new`、`/cc` 等）均支持多 Agent 路由，无需额外配置。

#### 安全说明

- 敏感字段（`clientSecret`、`dingToken`、`defaultDingToken`、`apiKeyCfg[].apiKey`）支持 `$ENV:VAR_NAME` 形式引用环境变量，避免明文落盘，例如 `"clientSecret": "$ENV:DING_SECRET"`
- `config.json` 与 `settings-ding.json` 写入时自动收紧为 `600` 权限
- `/bash` 仅限 owner/管理员执行，所有命令记录到 `~/.cc-ding/{clientId}/bash-audit.log`

### 数据存储

所有数据存储在 `~/.cc-ding/{clientId}/` 目录下：

| 类型 | 路径 |
|------|------|
| 会话 | `{MD5}/.sessions/{claudeSessionId|agentSessionId}/session.{json,log}` |
| 任务 | `{MD5}/.tasks/{时间戳}/task.{json,log}` |
| 定时任务 | `cron.json` |
| 图片缓存 | `{MD5}/.images/` |
| 用户映射 | `user-map.json` |

### 开发

```bash
pnpm install
pnpm run lint
pnpm run test
pnpm run build
```

---

## English

Connect Claude Code to DingTalk for bidirectional communication. Supports multi-turn conversations, task queues, scheduled jobs, and image recognition — helping teams build privately deployable AI assistants at minimal cost.

### Community

Scan the QR code to join our DingTalk or WeChat group:

<p align="center">
  <img src="assets/qrcode-dingtalk.jpg" alt="DingTalk Group QR Code" width="250">
  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  <img src="assets/qrcode-wechat.jpg" alt="WeChat Group QR Code" width="250">
</p>

### Table of Contents

- [Quick Start](#quick-start)
- [Commands](#commands)
- [Web Console](#web-console-1)
- [Configuration](#configuration)
- [Data Storage](#data-storage)
- [Development](#development)

### Quick Start

#### Install

```bash
npm i cc-ding -g
```

#### Initialize

```bash
cc-ding init -ci {clientId} -cs {clientSecret} -u {phone_or_emp_id} -dt {defaultDingToken}
```

| Parameter | Description |
|-----------|-------------|
| `-ci, --clientId` | DingTalk app ClientId |
| `-cs, --clientSecret` | DingTalk Stream connection secret |
| `-u, --user` | Admin phone number or employee ID (set as owner and added to whitelist) |
| `-dt, --defaultDingToken` | Fallback DingTalk bot Token (required) |
| `-cn, --clientName` | Bot name (optional, default "cc助手") |

#### Edit Config

Config file is at `~/.cc-ding/{clientId}/config.json`. See [config example](#configuration-example) below.

#### Start

```bash
# Direct start
cc-ding run -ci {clientId}

# Recommended: PM2 daemon
pm2 start --name "cc-ding-{clientId}" npx -- -p cc-ding cc-ding run -ci {clientId}
```

### Commands

#### Session

| Command | Description |
|---------|-------------|
| `/help` | View all commands |
| `/log [lines]` | View session logs |
| `/new [msg]` | Start a new conversation |
| `/resume [ID]` | Resume a previous session (latest if omitted) |
| `/end` | End the current session |

> Sessions are auto-persisted to `active.json` and restored on restart. All whitelisted users in the group can participate.

#### Task

```
/task <description>     # Submit task (auto-queued, sequential execution)
/task cancel            # Cancel a task
```

#### Scheduled

```
/cron <natural language>        # Claude auto-generates cron expression
/cron 0 9 * * * <description>   # Specify cron directly
/cron list                      # View all
/cron pause <id> | resume <id>  # Pause / resume
/cron delete <id>               # Delete
```

#### File Operations

| Command | Description |
|---------|-------------|
| `/ls [dir] [depth]` | View directory structure |
| `/bash <cmd>` | Execute arbitrary commands (owner/admin only, audited in `bash-audit.log`) |

#### Admin (owner only)

| Command | Description |
|---------|-------------|
| `/info [robot\|session\|task]` | View config/session/task info |
| `/version` | Version info |
| `/open [shell]` | Open working directory |
| `/clean [all]` | Clear history and cache |
| `/reset-apikeycfg` | Reset API Key configuration |
| `/cfg` | Register current group to config (supports `--permissionMode` to set permission mode) |
| `/auth [add\|del <user>]` | Manage group whitelist |
| `/destroy` | Unregister group bot, delete working directory and config |
| `/freedom` | Freedom mode: all group members can use the bot (skip whitelist, reply "confirm" within 60s to activate) |
| `/recorder [on\|exit]` | Recorder mode: log all messages locally (owner single-chat only) |
| `/reboot [--update]` | Restart cc-ding application |

### Web Console

cc-ding provides a web administration interface for visual management of client configs, API keys, auxiliary files, and more.

#### Start Console

```bash
cc-ding console [--port 8080] [--host 0.0.0.0] [--open]
```

| Parameter | Description |
|-----------|-------------|
| `--port` | HTTP listen port (default 8080) |
| `--host` | HTTP listen address (default 0.0.0.0) |
| `--open` / `--browser` | Auto-open browser on start |
| `--no-browser` | Disable auto-opening browser |

You can also use the chat command `/open console` to open the Console page locally.

#### Login

- Default credentials: `admin` / `admin`
- Password change is required on first login
- Bearer Token authentication, 24-hour expiry

#### Features

- **Client Management** — View online status, conversation counts, API Key counts for all clients
- **Config Editing** — View masked configs, patch nested values via dot-path syntax, raw JSON editing (auto-backup before write)
- **API Key Management** — List / add / edit / delete / reset, toggle validity
- **File Management** — Read/write auxiliary JSON files (`menu.json`, `model.json`, `cron.json`, `todo.json`, `user-map.json`, `active.json`)
- **Environment Variables** — Scan config for `$ENV:` references and display current process.env values
- **Global Config** — Change Console port / host, edit `settings-tpl.json` template
- **System Status** — Version, platform, uptime, online client count
- **Hot Reload** — Send SIGUSR2 signal to client processes to trigger config reload

#### URL Deep Links

The `/open console` command auto-builds deep links like:

```
http://localhost:8080?client=dingiexxdy25itrcuwtb&tab=config
```

- `client` — Auto-navigate to the specified client detail page
- `tab` — Auto-switch to the specified tab (`config` / `keys` / `files` / `env` / `raw`)

### Configuration

#### Configuration Example

```json
{
  "clientName": "cc助手",
  "owner": "your_phone_number",
  "whiteUserList": ["your_phone_number"],
  "clientSecret": "dingtalk_stream_secret",
  "defaultDingToken": "fallback_dingtalk_bot_token",
  "conversations": [
    {
      "conversationId": "group_id",
      "conversationTitle": "group_name",
      "dingToken": "group_bot_token",
      "whiteUserList": ["emp_id_1", "emp_id_2"],
      "agent": "specified_agent (optional)",
      "useLocalOcr": true,
      "permissionMode": "bypassPermissions",
      "taskCfg": { "skill": "specified_skill (optional)" },
      "freedomMode": false
    }
  ],
  "taskQueueSize": 50,
  "taskHandlerCount": 1,
  "sessionMaxConcurrency": 20,
  "includeThinking": false,
  "resultOnly": true,
  "debug": false
}
```

#### Config Quick Reference

| Config | Description |
|--------|-------------|
| `whiteUserList` | Global whitelist (phone, employee ID, or userId) |
| `conversations[].whiteUserList` | Group-level whitelist, higher priority than global (phone, employee ID, or userId) |
| `apiKeyCfg` | API Key pooling: auto-switch on 429, daily reset at midnight |
| `useLocalOcr` | Local image OCR (default `true`); set `false` if model supports images natively |
| `linkConversationId` | Link groups to share one Claude session context |
| `permissionMode` | Claude process permission mode (default `acceptEdits`; `bypassPermissions` must be set explicitly and warns at startup), options: `default`, `acceptEdits`, `plan`, `auto`, `bypassPermissions`, `dontAsk` |
| `freedomMode` | Freedom mode toggle (default `false`; when enabled, skips group whitelist check) |
| `preBash` | Global pre-bash command for `/bash` |
| `agent` | AI execution engine: `claude` (default) or `codex` (OpenAI Codex CLI) |

### Multi-Agent Architecture (v1.1.0)

cc-ding introduces a multi-Agent abstraction layer, allowing different AI execution engines to be switched per group. Set the `agent` field in group config to choose the engine:

```json
{
  "conversationId": "group_id",
  "agent": "claude"  // or "codex"
}
```

- **`claude`** (default): Uses Claude Code CLI, supports `--resume` session recovery, API Key rotation, context compaction, and full feature set
- **`codex`**: Uses OpenAI Codex CLI, supports thread recovery (`thread_id`), sandbox mode (`full-auto`), auto-timeout recovery, etc.

All commands (`/goon`, `/!`, `/new`, `/cc`, etc.) support multi-Agent routing without additional configuration.

#### Security Notes

- Sensitive fields (`clientSecret`, `dingToken`, `defaultDingToken`, `apiKeyCfg[].apiKey`) support `$ENV:VAR_NAME` references to environment variables, e.g. `"clientSecret": "$ENV:DING_SECRET"`
- `config.json` and `settings-ding.json` are written with `600` permissions
- `/bash` is restricted to owner/admin; all commands are audited in `~/.cc-ding/{clientId}/bash-audit.log`

### Data Storage

All data is stored under `~/.cc-ding/{clientId}/`:

| Type | Path |
|------|------|
| Sessions | `{MD5}/.sessions/{claudeSessionId|agentSessionId}/session.{json,log}` |
| Tasks | `{MD5}/.tasks/{timestamp}/task.{json,log}` |
| Cron jobs | `cron.json` |
| Image cache | `{MD5}/.images/` |
| User mapping | `user-map.json` |

### Development

```bash
pnpm install
pnpm run lint
pnpm run test
pnpm run build
```

---

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=yihuineng/cc-ding&type=Date)](https://github.com/yihuineng/cc-ding/stargazers)

## Contributors

[![Contributors](https://contrib.rocks/image?repo=yihuineng/cc-ding)](https://github.com/yihuineng/cc-ding/graphs/contributors)

## License

MIT
