内容
# 奥文
奥文是一个与MCP(模型上下文协议)兼容的虚拟上下文和内存系统。它为AI助手提供了一个结构化、分页的项目视图,使其能够在不耗尽上下文窗口的情况下浏览和推理大型代码库。
奥文实现了模型上下文协议,除此之外,它不依赖于任何其他功能。任何支持MCP的编辑器、助手或代理都可以与其连接,而奥文既不知道也不依赖于哪个客户端正在调用它。
## 为什么存在
在一个真实的仓库中工作的助手面临着两个糟糕的选择。它可以读取整个文件,这会用不需要的代码填充上下文窗口;或者它可以根据文件名进行猜测,这会产生错误答案。随着项目的增长,这两种方法都会降低效率。
奥文应用了一种内存模型,该模型已经被操作系统用于解决这个问题。项目被解析成一个符号签名的索引。助手读取该索引来定位自己,然后请求它需要的特定函数或类型。函数体按需加载,在使用时跟踪,当不再需要时释放。诸如日志和差异之类的冗长材料被写入磁盘,并在上下文中替换为一个短指针。
在奥文自己的源代码中,一个大约有50,000个标记的全源读取变成了大约4,700个标记的索引,减少了约90%,而每个符号仍然只需要一个调用即可访问。运行`npm run bench`可以测量任何项目的索引大小和标记减少情况。
## 工作原理
奥文将上下文窗口建模为三个层次。
| 层级 | 内容 | 存储位置 |
| --- | --- | --- |
| L1,活动帧 | 当前正在使用的符号主体和跟踪信息 | `.orven/frames.json` |
| L2,页表 | 所有类、函数和类型的签名索引 | `.orven/page-table.json` |
| 交换,磁盘 | 跟踪信息、差异、日志和写入的笔记 | `.orven/swap/` |
解析过程使用tree-sitter,因此索引源自真实的语法树,而不是正则表达式或行分块。符号存储为字节范围;函数体按需从源代码重新读取,并且从不复制到索引中。
四种机制在项目发生变化时保持索引的正确性:
- **增量重新索引。** 每个索引文件都带有mtime和size指纹。只有更改的文件会被重新解析。在编辑过程中请求的符号会在读取之前重新索引,因此返回的函数体始终是字节精确的。
- **驱逐。** 当L1超过高水位时,背景循环会释放最近最少使用的帧,直到达到低水位。最近使用的帧和在宽限期内触摸的帧永远不会被驱逐。
- **写回。** 助手编写的笔记无法从源代码重新获取,因此在释放帧之前会写入交换区,并且可以稍后读取回来。
- **锁定。** MCP服务器和CLI是单独的进程。跨进程的咨询锁序列化了帧表的每个读-修改-写操作。
## 需求
Node.js 22.13 或更新版本。无需本地工具链;解析使用WebAssembly语法。
## 安装
### 无需安装即可运行
```
npx orven init
```
这是尝试奥文的最快方式,除了Node.js之外,不需要安装任何其他东西。
### 全局安装
```
npm install -g orven
```
推荐用于常规使用。它在您的`PATH`上放置了两个命令:
| 命令 | 用途 |
| --- | --- |
| `orven` | 命令行界面。 |
| `orven-mcp` | MCP服务器。由MCP客户端启动,而不是手动启动。 |
### 从源代码构建
```
git clone https://github.com/naseridev/orven.git
cd orven
npm install
npm run build
```
`npm install`会自动构建项目。结果是`dist/`下的两个可执行文件:CLI(`dist/cli/index.js`)和MCP服务器(`dist/server/index.js`)。如果您想从任何地方使用`orven`,请使用`npm link`将它们链接到您的`PATH`中。
## 初始化
在您要索引的项目中运行`init`:
```
cd /path/to/your/project
orven init
```
`init`执行四个步骤:
1. 创建`.orven/`及其交换目录。
2. 解析项目并写入页表。
3. 重置帧表。
4. 在`.mcp.json`中注册MCP服务器。
重新运行`init`会重新索引项目。任何时候运行它都是安全的。
## MCP集成
`init`在`.mcp.json`中写入一个标准的MCP服务器条目。当奥文全局安装或从源代码构建时,入口点直接指向服务器:
```json
{
"mcpServers": {
"orven": {
"command": "/path/to/node",
"args": ["/path/to/orven/dist/server/index.js"],
"env": { "ORVEN_ROOT": "/path/to/your/project" }
}
}
}
```
当通过`npx`运行`init`时,该路径将位于npm可以删除的临时缓存中,因此奥文会写入一个自解析条目:
```json
{
"mcpServers": {
"orven": {
"command": "npx",
"args": ["-y", "--package=orven@1.0.0", "orven-mcp"],
"env": { "ORVEN_ROOT": "/path/to/your/project" }
}
}
}
```
此表单不包含机器特定路径,因此如果`.mcp.json`提交到共享存储库,则应保留此表单。首次连接可能会更慢,因为npm需要获取包。重新运行`init`全局安装后,会将条目重写为直接表单。
读取`.mcp.json`的客户端会自动获取其中一种表单。其他客户端可以指向相同的命令、参数和环境。`ORVEN_ROOT`确定服务器为哪个项目服务;其他内容均为标准MCP_stdio传输。
服务器暴露了五个工具:
| 工具 | 用途 |
| --- | --- |
| `orven_get_page_table` | 返回项目的签名索引,不包括函数体。 |
| `orven_page_in` | 将一个符号的完整主体加载到活动上下文中。 |
| `orven_inspect_swap` | 从交换区读取跟踪信息、差异或保存的笔记。 |
| `orven_free_frame` | 释放帧并回收其标记。 |
| `orven_write_scratch` | 在内存中保存工作笔记,在驱逐时写入交换区。 |
一个典型的会话从`orven_get_page_table`开始定位,然后对于每个实际需要的符号调用`orven_page_in`。`orven_page_in`还会返回根据依赖图得出的下一个最有可能需要的符号,以及调用正在读取的符号的符号。
## 命令
```
orven init 索引项目并发布MCP服务器
orven status 显示索引、上下文使用和效率
orven reset 释放工作上下文并压缩交换区
orven remove 从项目中删除奥文
```
所有命令都接受`-C, --root <dir>`以定位到指定目录:
- `status`默认打印简短摘要。`--verbose`添加完整的引擎诊断信息:水位线、依赖图统计信息、预取调优、交换区组成和锁定状态。
- `reset`释放过时的帧并压缩交换区日志。`--all`释放所有帧。不会丢失任何信息;草稿笔记会先写入交换区。
- `remove`完全删除`.orven/`并从`.mcp.json`中删除`orven`条目,使项目恢复到以前的状态。它在未传递`--yes`的情况下会提示确认。`.mcp.json`中的其他条目将被保留,如果`orven`是唯一条目,则会删除该文件。
`purge`和`uninstall`仍然是`reset`和`remove`的隐藏别名。
## 配置
默认配置在第一次`init`时写入`.orven/config.json`,可以直接编辑:
| 键 | 默认值 | 效果 |
| --- | --- | --- |
| `l1TokenBudget` | `12000` | 活动上下文的目标大小。 |
| `highWaterRatio` | `0.85` | 触发驱逐的预算分数。 |
| `lowWaterRatio` | `0.6` | 驱逐回收到的预算分数。 |
| `evictionGraceMs` | `30000` | 最近使用的帧在此期间受到保护。 |
| `sweepIntervalMs` | `15000` | 背景驱逐检查间隔。 |
| `daemonEnabled` | `true` | 启用自动驱逐。 |
| `reindexEnabled` | `true` | 启用增量重新索引。 |
| `reindexIntervalMs` | `20000` | 背景一致性检查间隔。 |
| `maxScratchBytes` | `32768` | 单个草稿笔记的大小限制。 |
| `swapCompactionEnabled` | `true` | 启用交换区日志修剪。 |
| `maxSwapBytes` | `8388608` | 交换区大小预算。 |
| `swapJournalKeep` | `24` | 按年龄保留的日志。 |
| `prefetchEnabled` | `true` | 启用下一个符号预测。 |
| `prefetchMaxHops` | `2` | 预测的依赖图深度。 |
| `prefetchDecay` | `0.5` | 每个跳跃应用的分数衰减。 |
| `prefetchBudgetTokens` | `1500` | 预测的标记预算。 |
| `prefetchDepth` | `6` | 请求的预测符号的最大数量。 |
| `prefetchEager` | `false` | 包括预测的主体,而不仅仅是签名。 |
| `prefetchAdaptive` | `true` | 根据测量精度调整预测深度。 |
| `purgeTargetRatio` | `0.8` | `reset`回收的活动上下文份额。 |
| `maxFileBytes` | `1500000` | 大于此大小的文件将被跳过。 |
| `ignoredDirectories` | 构建和供应商目录 | 索引时排除的目录。 |
环境变量:
| 变量 | 效果 |
| --- | --- |
| `ORVEN_ROOT` | MCP服务器服务的项目目录。 |
| `NO_COLOR` | 禁用颜色输出。 |
| `ORVEN_ASCII` | 强制使用ASCII字符,适用于不支持Unicode的终端。 |
| `ORVEN_NO_FLAVOR` | 禁用CLI输出中的可选风格行。 |
| `ORVEN_FLAVOR_SEED` | 使风格行确定,以便用于脚本或快照使用。 |
## 常见工作流程
```
cd my-project
orven init # 索引项目,注册MCP服务器
# 连接MCP客户端,然后像往常一样工作
orven status # 检查索引新鲜度和上下文使用情况
orven init # 在发生重大更改后重新索引
orven reset # 如果工作上下文已满,则释放它
```
在正常使用中,引擎会自动管理自身。驱逐、重新索引和交换区压缩在MCP服务器连接时在后台运行。`status`是您最常用的命令;通常不需要手动`reset`。
## 架构
```
src/
types.ts 共享领域模型
config/ 路径、默认值、阈值
util/ 原子JSON写入、文件锁定、标记估计
ast/ tree-sitter解析、符号和引用提取
memory/ 页表、帧、交换区、驱逐、图、写回
server/ MCP服务器、工具、驱逐守护进程、一致性扫描器
cli/ 命令行界面和渲染
```
`memory/`、`ast/`和`server/`不包含任何特定于客户端的逻辑。服务器实现了MCP,但不知道连接到它的客户端。CLI仅用于呈现,不持有任何引擎状态。
项目状态仅限于`.orven/`:
```
.orven/
config.json 设置
page-table.json 符号索引
frames.json 活动帧
meta.json 计数器和时间戳
swap/ 跟踪信息、差异、写入的笔记
```
`predictions.json`仅在预取具有数据时添加,而`frames.lock`仅在进行写入时存在。源文件从不修改。
## 开发
源代码位于 [github.com/naseridev/orven](https://github.com/naseridev/orven)。错误和功能请求请提交到 [问题跟踪器](https://github.com/naseridev/orven/issues)。
```
npm run build 编译TypeScript
npm run typecheck 类型检查而无需发出
npm test 构建,然后运行CLI和引擎测试套件
npm run bench 报告项目的索引大小和标记减少情况
npm run dev:cli 从源代码运行CLI
npm run dev:server 从源代码运行MCP服务器
```
测试套件涵盖了CLI表面和内存引擎的MCP接口,包括跨编辑的字节精确分页、写回和恢复、驱逐行为以及多个进程的并发访问。
`web-tree-sitter`固定在0.24.x版本。后续版本需要语法模块的格式,而预编译语法不提供此格式。
## 许可证
GNU通用公共许可证第3.0版。完整文本请参见 [LICENSE](LICENSE)。