Files
dstalk/README.md
XiuChengWu e6f24f00f1 Refactor to plugin architecture with B3 CLI UX, C2 smoke tests, C3 CI scripts
Architecture overhaul (Wave 1-4 collaborative work):
- Migrated dstalk-core from monolithic api.cpp to plugin-based design with
  host/service_registry/event_bus/plugin_loader and topological initialization.
- Split public headers into dstalk_host.h / dstalk_services.h /
  dstalk_lsp.h / dstalk_types.h; deleted obsolete dstalk_api.h and inlined
  TLS/file/net code now provided by plugins.
- Added 9 plugins: deepseek, anthropic, network, session, context, tools,
  config, file-io, lsp; AI plugins register as "ai.<provider>" services.

B3 CLI interaction enhancement:
- Prompt now shows current model name (A1).
- /status command prints model/base_url/api_key (sanitized: shown only
  as set/unset)/services readiness (A2).
- SIGINT/Ctrl+C handled on POSIX (signal) and Windows (SetConsoleCtrlHandler);
  /quit no longer std::exit(0) but sets a quit flag so dstalk_shutdown runs
  exactly once via natural control flow (B1+B2).
- Cross-DLL free fixed: print_file uses dstalk_free instead of std::free (B4).
- --batch mode plus isatty auto-detection for piped stdin (C1).
- fgets truncation detection with friendly error and stdin draining (C3).
- Distinct exit codes (init/AI/service-unavailable) (C4).
- /model rejects empty model name (C5).

C2 smoke test extension:
- 4 new test blocks: null-safety (file_io/session/tools/config),
  escape-boundary round-trip, tools->execute call chain, session robustness
  (add(nullptr), clear -> token_count == 0).

C3 CI build scripts:
- scripts/ci-build.sh and scripts/ci-build.bat invoke cmake configure +
  parallel build + ctest, suitable for GitHub Actions.

Build verified: dstalk-cli compiles, smoke test passes via ctest.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-27 05:12:56 +08:00

398 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# dstalk
> 基于 DeepSeek V4 大模型、兼容 OpenAI / Anthropic API 的 AI 编程 CLI
>
> 官网: [dstalk.top](https://dstalk.top)
---
## 这是什么?
dstalk 是一款 AI 编程助手命令行工具。通过调用 DeepSeek V4 大模型(兼容 OpenAI 和 Anthropic API在终端里用自然语言完成代码编写、重构、调试和文件操作。功能对标 Claude Code、OpenCode、KiloCode。
核心设计为 **插件化 CDLL + 多前端解耦**
```text
┌───────────────────────────────────────────────────────────┐
│ 前端层 (Frontends) │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ dstalk-cli │ │ dstalk-gui │ │
│ │ ANSI 终端 UI │ │ SDL3 图形化 UI │ │
│ │ exe → dstalk.dll│ │ exe → dstalk.dll │ │
│ └────────┬─────────┘ └─────────────┬─────────────┘ │
│ │ │ │
│ └──────────────┬───────────────┘ │
│ │ C ABI │
└──────────────────────────┼─────────────────────────────────┘
┌──────────────────────────▼─────────────────────────────────┐
│ 核心层 (dstalk-core.dll) — 插件宿主 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Host: 插件加载 · 服务注册 · 事件总线 · 配置管理 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ 服务查询 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ deepseek │ │ anthropic│ │ network │ │ lsp │ │
│ │ (ai) │ │ (ai) │ │ (http) │ │ 客户端 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ session │ │ context │ │ file-io │ │ tools │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
- **`dstalk-core`** —— C11/C++20 插件化宿主 DLL负责插件加载、服务注册/查询、事件总线、配置管理。
- **`dstalk-cli`** —— 命令行前端ANSI 转义码实现,调用 `dstalk.dll`
- **`dstalk-gui`** —— 图形化前端SDL3 跨平台窗口,调用 `dstalk.dll`
- **`plugins/`** —— 9 个功能插件,编译为独立 DLL通过 C ABI 动态注册服务。
核心与界面完全解耦,可以轻松编写自己的前端,或把 AI 能力嵌入到现有工具中。所有功能通过插件实现,插件只需引用 `dstalk.dll` 即可。
---
## 核心功能
| 功能 | 状态 | 说明 |
|------|------|------|
| **多后端 AI 支持** | 已完成 | DeepSeek V4 和 Anthropic Claude 通过插件独立加载,`config.toml``ai.provider` 一键切换 |
| **流式输出** | 已完成 | SSE 流式响应,终端逐字打印 AI 思考过程 |
| **多轮会话** | 已完成 | 上下文窗口连续对话,支持 `/clear` 清空、`/save` `/load` 持久化 |
| **文件读写工具** | 已完成 | 内置 `/file` 命令集,支持列目录、查看、读取、写入文件 |
| **LSP 集成** | 已完成 | 完整 LSP 客户端子进程管理、JSON-RPC 2.0),支持诊断、悬停、补全 |
| **插件系统** | 已完成 | 9 个功能插件拓扑排序依赖管理DLL 动态加载,服务注册/查询 |
| **GUI 前端** | 已完成 | SDL3 跨平台图形界面,流式输出、会话管理、输入历史、剪贴板 |
---
## 为什么用 C/C++ 实现?
| 维度 | dstalk (C/C++) | 典型竞品 (TypeScript/Node.js) |
|------|----------------|------------------------------|
| 启动速度 | 毫秒级 | 秒级 |
| 内存占用 | 数十 MB | 数百 MB 起 |
| 运行时依赖 | 零(单文件 DLL | 需要 Node.js 运行时 |
| 嵌入能力 | 任意语言通过 C ABI 调用 | 困难 |
| GC 影响 | 无 GC 停顿 | 可能内存膨胀 |
AI 编程助手需要长期驻留、频繁交互,性能特征值得用系统级语言重新思考。
---
## 与竞品的差异化
| 特性 | dstalk | Claude Code | OpenCode | KiloCode |
|------|--------|-------------|----------|----------|
| 实现语言 | C11 / C++20 | TypeScript | TypeScript | TypeScript |
| 运行时 | 零依赖 CDLL | Node.js | Node.js | Node.js |
| 前端形态 | CLI + GUI 双前端 | 终端集成 | VS Code 插件 | VS Code 插件 |
| 模型 | DeepSeek / OpenAI / Anthropic | Claude | 多模型 | 多模型 |
| 嵌入第三方 | C ABI极易 | 困难 | 困难 | 困难 |
### DLL 架构优势
- **语言无关** —— C ABI 意味着 C/C++、Python、Rust、C#、Go 都能直接调用
- **进程内集成** —— 无需 HTTP 通信、零 IPC 开销,直接函数调用
- **前端零状态** —— CLI 和 GUI 不持有业务逻辑,只负责渲染和输入
---
## 快速开始
### 1. 安装工具链(全自动,存入 tools\,需系统已安装 Python 3.10+
```bash
cd tools
setup.bat # 下载 CMake + Ninja + LLVM/Clang并在 tools/.venv 安装 Conan2
```
> 网络不畅时可手动下载放入对应目录:[Ninja](https://github.com/ninja-build/ninja/releases) | [CMake](https://cmake.org/download/) | [LLVM](https://github.com/llvm/llvm-project/releases)
>
> 目录结构要求: `tools/cmake/bin/cmake.exe` / `tools/ninja/ninja.exe` / `tools/llvm/bin/clang.exe` / `tools/.venv/Scripts/conan.exe`
### 2. 编译
```bash
build.bat # 一键: Conan拉依赖 → CMake配置 → Ninja编译
```
### 3. 运行
```bash
build/dstalk-cli/dstalk-cli.exe # 命令行模式
# 图形模式默认关闭;需要 SDL3 时用 -DDSTALK_BUILD_GUI=ON 重新配置
```
---
## 使用示例
```text
$ dstalk-cli
dstalk v0.1.0 | 模型: deepseek-v4-pro | /help 查看帮助
> 帮我写一个读取 CSV 并计算平均值的 C 程序
[dstalk] 正在思考...
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "用法: %s <csv文件>\n", argv[0]);
return 1;
}
FILE *fp = fopen(argv[1], "r");
if (!fp) { perror("fopen"); return 1; }
double sum = 0.0;
int count = 0;
char line[1024];
while (fgets(line, sizeof(line), fp)) {
sum += atof(line);
count++;
}
fclose(fp);
printf("平均值: %.2f (共 %d 行)\n", sum / count, count);
return 0;
}
已写入 csv_avg.c。需要我帮你编译测试吗
> 把这段代码改成支持表头的
[dstalk] 已更新 csv_avg.c——跳过第一行表头增加列选择功能。
> /file show csv_avg.c
[dstalk] 已显示 csv_avg.c 内容。
```
### 常用命令
| 命令 | 说明 |
|------|------|
| `/file list [path]` | 列出目录内容 |
| `/file show <path>` | 查看文件内容 |
| `/file read <path>` | 读取文件内容 |
| `/file write <path> <content>` | 写入文件 |
| `/model <name>` | 切换 AI 模型 |
| `/clear` | 清空会话上下文 |
| `/save <path>` | 保存会话 |
| `/load <path>` | 恢复会话 |
| `/help` | 显示帮助 |
---
## 工程结构
```text
dstalk/
├── deps/
│ └── conanfile.txt # Conan2 依赖声明 (Boost, OpenSSL, SDL3)
├── dstalk-core/ # 核心 DLL — 插件宿主
│ ├── include/dstalk/
│ │ ├── dstalk_host.h # 公开 API: 宏定义、宿主API、插件生命周期
│ │ ├── dstalk_services.h # 服务接口 vtable 定义 (AI/Session/Context/HTTP/FileIO/Config/Tools/LSP)
│ │ ├── dstalk_types.h # 共享类型: 消息、结果、事件、日志等级
│ │ └── dstalk_lsp.h # LSP 便捷函数 (委托给 lsp 插件)
│ ├── src/
│ │ ├── host.cpp # 宿主: 初始化、服务查询、LSP 便捷函数
│ │ ├── config_store.cpp/.hpp # 配置管理 (TOML 解析)
│ │ ├── event_bus.cpp/.hpp # 事件总线 (发布/订阅)
│ │ ├── service_registry.cpp/.hpp # 服务注册表 (名称→vtable)
│ │ ├── plugin_loader.cpp/.hpp # 插件加载器 (DLL 加载、拓扑排序、依赖管理)
│ │ └── boost_json.cpp # Boost.JSON 编译单元
│ └── CMakeLists.txt
├── plugins/ # 功能插件 (每个编译为独立 DLL)
│ ├── deepseek/ # DeepSeek AI (服务名: ai.deepseek)
│ ├── anthropic/ # Anthropic Claude (服务名: ai.anthropic)
│ ├── network/ # HTTP/HTTPS 客户端 (服务名: http)
│ ├── session/ # 会话管理 (服务名: session)
│ ├── context/ # 上下文/Token 管理 (服务名: context)
│ ├── file-io/ # 文件读写 (服务名: file_io)
│ ├── tools/ # 工具注册/执行 (服务名: tools)
│ ├── lsp/ # LSP 客户端 (服务名: lsp)
│ ├── config/ # 配置服务 (服务名: config)
│ └── CMakeLists.txt # 插件构建 (按依赖顺序)
├── dstalk-cli/ # 命令行前端 (ANSI)
│ ├── src/main.cpp
│ └── CMakeLists.txt
├── dstalk-gui/ # 图形化前端 (SDL3)
│ ├── src/main.cpp
│ └── CMakeLists.txt
├── examples/ # 示例代码
│ └── example_plugin/
│ └── example_plugin.cpp # 插件开发示例
├── tests/ # 集成测试
│ └── smoke_test.cpp
├── CMakeLists.txt # 根 CMake
└── README.md
```
---
## 公开 API
头文件:
- [dstalk_host.h](dstalk-core/include/dstalk/dstalk_host.h) — 宿主 API、插件生命周期
- [dstalk_services.h](dstalk-core/include/dstalk/dstalk_services.h) — 服务接口 vtable 定义
- [dstalk_types.h](dstalk-core/include/dstalk/dstalk_types.h) — 共享类型
- [dstalk_lsp.h](dstalk-core/include/dstalk/dstalk_lsp.h) — LSP 便捷函数
```c
/* 宿主生命周期 */
int dstalk_init(const char* config_path);
void dstalk_shutdown(void);
/* 插件管理 */
int dstalk_plugin_load(const char* path);
int dstalk_plugin_unload(int plugin_id);
int dstalk_plugin_list(char** output_json);
/* 服务查询 —— 通过名称获取插件注册的 vtable */
void* dstalk_service_query(const char* service_name, int min_version);
/* 事件总线 */
int dstalk_event_subscribe(int event_type, dstalk_event_handler_fn handler, void* userdata);
int dstalk_event_emit(int event_type, const void* data);
void dstalk_event_unsubscribe(int subscription_id);
/* 配置 */
const char* dstalk_config_get(const char* key);
int dstalk_config_set(const char* key, const char* value);
/* 内存管理 */
void* dstalk_alloc(size_t size);
void dstalk_free(void* ptr);
char* dstalk_strdup(const char* s);
/* LSP 便捷函数 (委托给 lsp 插件) */
int dstalk_lsp_start(const char* server_cmd, const char* language);
void dstalk_lsp_stop(void);
int dstalk_lsp_open(const char* uri, const char* content, const char* language_id);
int dstalk_lsp_close(const char* uri);
int dstalk_lsp_diagnostics(const char* uri, char** output);
int dstalk_lsp_hover(const char* uri, int line, int character, char** output);
int dstalk_lsp_completion(const char* uri, int line, int character, char** output);
```
**调用约定:**
- 所有字符串均为 UTF-8 编码
- 通过 `dstalk_service_query` 获取服务 vtable再通过函数指针调用具体功能
- `dstalk_free` 释放所有 API 返回的堆内存
- 返回 `0` 成功,负数表示错误码
**跨语言调用示例:**
```c
#include "dstalk/dstalk_host.h"
#include "dstalk/dstalk_services.h"
#include <stdio.h>
int main(void) {
if (dstalk_init("config.toml") != 0) {
fprintf(stderr, "初始化失败\n");
return 1;
}
// 查询 AI 服务
const char* provider = dstalk_config_get("ai.provider");
if (!provider) provider = "ai.deepseek";
const dstalk_ai_service_t* ai = dstalk_service_query(provider, 1);
if (ai) {
ai->configure(provider, "https://api.deepseek.com/v1", "sk-xxx",
"deepseek-v4-pro", 4096, 0.7);
}
dstalk_shutdown();
return 0;
}
```
---
## FAQ
**Q: 为什么不用 Rust**
A: 团队对 C/C++ 生态更熟悉C++20 的现代特性已能让我们写出安全高效的代码。且 CDLL 需要稳定的 C ABIC/C++ 最直接。
**Q: 支持哪些模型?**
A: 主要支持 DeepSeek V4同时兼容 OpenAI GPT 系列和 Anthropic Claude 系列的 API。通过配置文件切换 API 基地址和密钥即可。
**Q: 为什么同时做 CLI 和 GUI**
A: CLI 适合终端/SSH/CI 环境GUI 适合需要富文本和鼠标交互的场景。两者共享同一核心 DLL功能一致。
**Q: 如何配置 API Key**
A: 首次运行前,手动创建项目目录下的 `config.toml`,按需选择后端:
```toml
# 选择 AI 后端插件: ai.deepseek 或 ai.anthropic
ai.provider = "ai.deepseek"
# DeepSeek
api.base_url = "https://api.deepseek.com/v1"
api.api_key = "sk-xxxxxxxx"
api.model = "deepseek-v4-pro"
# Anthropic Claude (切换 ai.provider 为 "ai.anthropic" 即可)
# api.base_url = "https://api.anthropic.com/v1"
# api.api_key = "sk-ant-xxxxxxxx"
# api.model = "claude-opus-4-20250514"
```
修改 `ai.provider` 字段即可在不同后端间切换,无需改动代码。
---
## 路线图
| 阶段 | 内容 |
|------|------|
| **Phase 1** | 项目骨架、CMake 构建、DLL 导出、CLI 前端主循环 |
| **Phase 2** | HTTPS 网络层、DeepSeek API 对接、基本对话 |
| **Phase 3** | ~~流式输出、多轮会话、文件读写工具、CLI 体验对齐~~ |
| **Phase 4** (当前) | ~~插件化架构重构、多后端 AI、LSP 客户端、SDL3 GUI~~ |
| **Phase 5** | GUI 完善、工具调用Function Calling、插件生态、多语言扩展 |
---
## 贡献指南
1. Fork 仓库并克隆到本地
2. 创建分支: `git checkout -b feature/功能名`
3. 编码: C 代码 K&R 风格C++ 代码 LLVM 风格
4. 确保 `cmake --build build` 通过
5. 提交 PR描述改动内容和动机
### 代码规范
- C: C11 标准,头文件 `#pragma once`
- C++: C++20 标准,优先标准库,必要时引入 Boost
- 内存: C++ 优先 RAIIC 代码显式管理
- 对外接口: `extern "C"` 纯 C 函数,不抛异常
---
## 技术风险与对策
| 风险 | 对策 |
|------|------|
| C++ 开发效率低于脚本语言 | Boost 库弥补;核心 API 稳定后开发速度不会慢于竞品 |
| OpenSSL 跨平台兼容性 | Conan2 锁定版本,统一 Windows/Linux/macOS HTTPS 后端 |
| SDL3 依赖体积较大 | GUI 默认关闭,需要图形前端时再启用 `DSTALK_BUILD_GUI` |
| AI API 协议变更 | 适配层独立模块,变更时只改一处 |
---
## 许可证
GNU General Public License v3. Copyright (c) 2026 dstalk contributors.
---
[dstalk.top](https://dstalk.top) | [GitHub](https://github.com/dstalk/dstalk) | [Issue 反馈](https://github.com/dstalk/dstalk/issues)