appbridge
by stevenwang15
README.md
# appbridge
> 给 agent 装上手脚:把电脑上的东西变成它能直接调用的工具,把干活的步骤存成能反复跑的配方。
电脑上的能力本来是散的:文件在硬盘里、命令在终端里、知识库在 Obsidian 里、文档是 docx。
appbridge 把它们统一成一张**动词表**——每个工具一个名字、一组参数、一个确定的返回。
- **零外部依赖**:只用 Node 内置模块,一个 `node` 就能跑
- **两种外壳**:中立 MCP server(任何宿主都能接)+ DeepSeek Harness 插件
- **内核与插件分开**:插件是薄壳,逻辑全在内核,换宿主不用重写
```
48 个工具 · 10 种工具类型 · 7 个配方 · 32 个测试 · 176 KB
```
## 它解决三件事
**一、让 AI 真的能动手。** 它本来只能说话。接上这 48 个工具,它能读笔记库、跑 git、解析 Word 和 PPT、
调本机模型、截屏、发通知——这些原来只有人在终端里敲得出来的动作,现在 AI 能直接调。
**二、让重复的活儿只做一次。** 一次跑通,存成配方;下次一条命令,不重新推理,也不会每次做得不一样。
**三、接一个新应用 = 加一段 JSON。** 不用写代码。有命令行填 `cli`,有本地端口填 `http`,有数据目录填 `fs`。
## 为什么是「动词表」而不是让 AI 现拼命令
不是不能跑 shell,是跑 shell 会一直在低水平上出错。
| | 让 AI 现拼 shell 命令 | 给它一张动词表 |
|---|---|---|
| 每次执行 | 现场拼字符串,引号、空格、转义都可能错 | 名词化调用,参数是结构化的 |
| 出错时 | 命令写错,整条废掉,得重试 | 缺参数在调用前就报清楚,改一个参数重跑 |
| 返回结果 | 一段文本,还要再解析 | 结构化的值,下一步能直接引用 |
| 复现 | 每次重新拼,可能不一样 | 写进配方,顺序固定,可重放 |
| 加新能力 | 教它一套新命令的写法 | 加一段 JSON 声明 |
一句话:**动词表让 AI 把注意力花在「干什么」上,而不是「这条命令怎么写」。**
## 快速开始
```bash
git clone https://github.com/stevenwang15/appbridge.git
cd appbridge
node bin/cli.js doctor # 体检:这台机器上哪些工具能用
node bin/cli.js tools # 48 个工具
node bin/cli.js call sys.info # 直接调一个
node bin/cli.js run vault-search --set "q=适当性" # 跑配方
```
`doctor` 检查四件事:平台对不对、命令装没装、端口通不通、路径存不存在。
```bash
cp config.json config.local.json # 然后改里面的 vault / model
```
## 三种用法
### 1. 命令行
```bash
node bin/cli.js doctor
node bin/cli.js call docx.read --set path=报告.docx
node bin/cli.js run parallel-demo --async # 后台跑
node bin/cli.js jobs / wait <id> / kill <id>
```
### 2. MCP server(中立外壳,推荐)
任何支持 MCP 的宿主都能接,不依赖宿主版本:
```json
{
"mcpServers": {
"appbridge": {
"command": "node",
"args": ["/absolute/path/to/appbridge/bin/mcp.js"]
}
}
}
```
DeepSeek Harness / Claude Desktop / Cursor / 任何 MCP 客户端通用。接上就是 48 个工具。
### 3. DeepSeek Harness 插件
```bash
npm install appbridge-dsh-plugin
```
插件把内核工具注册成 DSH 原生工具(`ctx.tools.register` + `defineTool`),实现见
[`packages/dsh-plugin`](packages/dsh-plugin)。
> 插件壳依赖宿主提供的 `@deepseek-ai/dsh-tools`。如果你的 DSH 版本不暴露它,
> 用上面的 MCP 方式接入,功能完全一样。
## 48 个工具
**Office(不装 Office 也能用)** — docx/xlsx/pptx 本质是 zip + XML,用 Node 内置 zlib 自己解析
`docx.read` `docx.write` `xlsx.read` `pptx.read`
**压缩包 / 表格** `zip.list` `zip.read` `zip.extract` `csv.read`
**文件** `fs.read` `fs.write` `fs.append` `fs.list` `fs.find` `fs.search`
**Obsidian** `obs.list` `obs.search` `obs.read` `obs.write` `obs.append` `obs.tags` `obs.backlinks`
**命令 / 版本库** `cli.run` `git.log` `git.status` `git.diff` `git.branch` `git.show`
**系统** `sys.info` `sys.disk` `sys.process` `sys.screenshot` `sys.notify` `sys.say` `clip.read` `clip.write` `app.open`
**图片** `img.info` `img.resize` `textutil.convert`
**本机模型 / 网络** `ollama.models` `ollama.chat` `http.get`
**数据加工** `text.join` `json.get` `echo` `delay`
加一个工具 = 往 `tools.json` 加一段 JSON,不用写代码:
```json
"git.status": {
"desc": "git 工作区改动",
"kind": "cli",
"command": "git",
"args": ["status", "--short"],
"cwd": "{{repo}}",
"params": { "repo": { "type": "string", "default": "." } }
}
```
## 配方:步骤的顺序
```json
{
"name": "vault-search",
"when": "在 Obsidian 库里搜关键词",
"args": { "q": { "type": "string", "required": true } },
"steps": [
{ "id": "hits", "tool": "obs.search", "args": { "pattern": "{{q}}" } },
{ "id": "body", "tool": "text.join", "args": { "items": "{{$1}}", "sep": "\n" } },
{ "id": "save", "tool": "fs.write", "args": { "path": "out/search.md", "content": "{{$2}}" } }
]
}
```
变量:`{{参数}}`、`{{$1}}`(第 1 步输出)、`{{date}}` `{{time}}` `{{stamp}}` `{{cwd}}`
配方是**数据不是脚本**:agent 能填参数生成,人能直接改,每一步都能单测。
## 异步执行
**配方内并行**
```json
{ "id": "slow", "parallel": [
{ "id": "a", "tool": "delay", "args": { "ms": 800 } },
{ "id": "b", "tool": "delay", "args": { "ms": 800 } } ] }
```
实测 3×800ms:顺序 2.44s,并行 **0.84s**。
**整条配方后台跑** — `--async` 31ms 返回任务号,状态落盘 `jobs/<id>/`,可跨进程查、等、杀。
## 调用范围
`policy.json` 决定这些工具能碰到哪里。它是**配置**,不是目的——
想让 AI 多干点,往范围里加;想收窄,删掉。
```json
{
"base": ".",
"allowExec": ["git", "node", "osascript", "screencapture", "sips", "ps", "textutil", "tesseract", "blender"],
"allowRead": ["./**", "{{config.vault}}/**"],
"allowWrite": ["./**", "{{config.vault}}/**"],
"allowNet": ["127.0.0.1", "localhost"]
}
```
- **路径**:`path` 按读/写判定,`src` 只读,`dest` 只写
- **命令**:必须在 `allowExec` 里
- **网络**:host 必须在 `allowNet` 里
`base` 固定相对程序目录,不跟 cwd 走。
> 说明:`cli` 类工具的范围是「跑哪个命令」,命令自己往哪写由那个命令决定。这一层管的是**能力边界**,不是系统沙箱。
## 可移植性
| 文件 | 放什么 | 进版本库 |
|---|---|---|
| `config.json` | 可移植默认值 | 是 |
| `config.local.json` | 本机差异(知识库路径、模型名) | 否 |
环境变量:`APPBRIDGE_VAULT` `APPBRIDGE_MODEL` `APPBRIDGE_PLATFORM` `APPBRIDGE_POLICY`
平台差异自动降级:macOS 专属工具标了 `"platform": ["darwin"]`。
```bash
APPBRIDGE_PLATFORM=linux node bin/cli.js doctor # 38/48
APPBRIDGE_PLATFORM=win32 node bin/cli.js doctor # 36/48
```
## 仓库结构
```
appbridge/ 内核(npm: appbridge-core)
├── bin/cli.js 命令行入口
├── bin/mcp.js MCP server 入口(中立外壳)
├── src/invoke.js 工具调用器
├── src/recipe.js 配方执行器
├── src/jobs.js 后台任务
├── src/doctor.js 体检
├── src/zip.js ZIP 读写
├── src/office.js docx / xlsx / pptx
├── src/mcp.js MCP 工具描述
├── src/config.js 配置合并
├── tools.json 48 个工具
├── policy.json 调用范围
├── recipes/ 配方
└── packages/dsh-plugin/ DSH 插件壳(薄)
测试:32 个(内核 25 + 插件契约 7)
```
## 开发者
```bash
node --test test/ # 内核测试
node --test packages/dsh-plugin/test/ # 插件契约测试
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo recent community issues