FileWatcher
FileWatcher 是 OpenCode 的跨平台文件监听系统,用于监控项目文件和 Git 仓库的变更。
概述
FileWatcher 使用 @parcel/watcher 库提供跨平台的文件监听能力,支持 macOS 的 fs-events、Linux 的 inotify 和 Windows 的原生文件系统 API。它可以实时检测文件的创建、修改和删除,并通过事件总线通知其他组件。
定义位置
packages/opencode/src/file/watcher.ts
主要组件
Event.Updated
文件更新事件。
类型:
{
file: string, // 文件路径
event: "add" | "change" | "unlink" // 事件类型
}
位置: packages/opencode/src/file/watcher.ts:26
init()
初始化文件监听器。
工作流程:
- 检查
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER标志 - 使用懒加载模式实例化 watcher
- 为项目目录和 Git 目录创建订阅
位置: packages/opencode/src/file/watcher.ts:121
平台支持
FileWatcher 根据操作系统自动选择最佳的后端:
| 平台 | 后端 | 说明 |
|---|---|---|
| macOS | fs-events | 使用 macOS FSEvents API |
| Linux | inotify | 使用 Linux inotify API |
| Windows | windows | 使用 Windows ReadDirectoryChangesW |
平台检测:
const backend = (() => {
if (process.platform === "win32") return "windows"
if (process.platform === "darwin") return "fs-events"
if (process.platform === "linux") return "inotify"
})()
位置: packages/opencode/src/file/watcher.ts:52
监听的目录
1. 项目目录
- 条件:
OPENCODE_EXPERIMENTAL_FILEWATCHER标志启用 - 监听:
Instance.directory(通常是项目根目录) - 忽略模式:
FileIgnore.PATTERNS+ 用户配置的config.watcher.ignore
位置: packages/opencode/src/file/watcher.ts:78
2. Git 目录
- 条件: 项目使用 Git 版本控制
- 监听:
.git/HEAD文件(检测分支变更) - 忽略模式: Git 目录内容(除了 HEAD)
位置: packages/opencode/src/file/watcher.ts:91
事件类型
| 事件名 | Parcel 类型 | 文件事件类型 | 说明 |
|---|---|---|---|
| add | create | add | 文件创建 |
| change | update | change | 文件修改 |
| unlink | delete | unlink | 文件删除 |
事件映射:
const subscribe = (err, evts) => {
if (err) return
for (const evt of evts) {
if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" })
if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" })
if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" })
}
}
文件忽略模式
内置忽略模式
位置: packages/opencode/src/file/ignore.ts
export const PATTERNS = [
// 文件夹
"node_modules",
"bower_components",
".pnpm-store",
"vendor",
".npm",
"dist",
"build",
"out",
".next",
"target",
"bin",
"obj",
".git",
".svn",
".hg",
".vscode",
".idea",
".turbo",
".output",
"desktop",
".sst",
".cache",
".webkit-cache",
"__pycache__",
".pytest_cache",
"mypy_cache",
".history",
".gradle",
// 文件 glob 模式
"**/*.swp",
"**/*.swo",
"**/*.pyc",
"**/.DS_Store",
"**/Thumbs.db",
"**/logs/**",
"**/tmp/**",
"**/temp/**",
"**/*.log",
"**/coverage/**",
"**/.nyc_output/**",
]
用户配置
用户可以在配置中添加自定义忽略模式:
{
watcher: {
ignore: ["node_modules", "*.log", "custom-dir/**"]
}
}
位置: packages/opencode/src/config/config.ts:897
配置标志
环境变量
| 变量名 | 说明 |
|---|---|
OPENCODE_EXPERIMENTAL_FILEWATCHER | 启用项目目录监听(实验性) |
OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER | 完全禁用文件监听 |
配置选项
{
watcher: {
ignore: string[] // 自定义忽略模式
}
}
集成点
1. 项目初始化
位置: packages/opencode/src/project/bootstrap.ts:24
import { FileWatcher } from "@/file/watcher"
export async function bootstrap() {
// ...
FileWatcher.init()
// ...
}
2. Git 分支检测
位置: packages/opencode/src/project/vcs.ts:49
Bus.subscribe(FileWatcher.Event.Updated, (evt) => {
if (evt.file.endsWith("/.git/HEAD")) {
// 检测到分支变更
const newBranch = await getCurrentBranch()
Bus.publish(VCS.Event.BranchUpdated, { branch: newBranch })
}
})
3. 程序化文件变更
位置: packages/opencode/src/tool/apply_patch.ts:230
当通过工具修改文件时,手动发布更新事件:
await Bus.publish(FileWatcher.Event.Updated, {
file: filePath,
event: "change",
})
4. Web UI 自动重载
位置: packages/app/src/context/file.tsx:356
Bus.subscribe(FileWatcher.Event.Updated, (evt) => {
if (evt.file.startsWith(".git/")) return // 跳过 Git 目录
// 自动重新加载文件内容
reloadFile(evt.file)
})
TypeScript 类型定义
export namespace FileWatcher {
export const Event = {
Updated: BusEvent.define(
"file.watcher.updated",
z.object({
file: z.string(),
event: z.union([z.literal("add"), z.literal("change"), z.literal("unlink")]),
}),
),
}
export function init(): void
}
典型使用场景
1. 监听文件变更
import { FileWatcher } from "@/file/watcher"
import { Bus } from "@/bus"
Bus.subscribe(FileWatcher.Event.Updated, (evt) => {
console.log(`文件 ${evt.file} 被修改`)
console.log(`操作类型: ${evt.event}`)
if (evt.event === "change") {
// 处理文件修改
handleFileChange(evt.file)
} else if (evt.event === "add") {
// 处理文件创建
handleFileAdd(evt.file)
} else if (evt.event === "unlink") {
// 处理文件删除
handleFileDelete(evt.file)
}
})
2. 启用实验性文件监听
# 启用项目目录监听
export OPENCODE_EXPERIMENTAL_FILEWATCHER=1
bun dev
3. 禁用文件监听
# 完全禁用文件监听
export OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=1
bun dev
4. 配置自定义忽略模式
// 在配置文件中
{
"watcher": {
"ignore": [
"node_modules",
"*.log",
"build/**",
"dist/**",
".cache/**"
]
}
}
5. 检测 Git 分支变更
import { FileWatcher } from "@/file/watcher"
import { Bus } from "@/bus"
Bus.subscribe(FileWatcher.Event.Updated, (evt) => {
// 检测 Git HEAD 文件变更(分支切换)
if (evt.file.endsWith("/.git/HEAD")) {
const currentBranch = await getCurrentBranch()
console.log(`Git 分支已切换到: ${currentBranch}`)
}
})
6. 手动发布文件变更事件
import { FileWatcher } from "@/file/watcher"
import { Bus } from "@/bus"
// 当程序化修改文件时
await writeFileSync("/path/to/file.js", content)
// 发布更新事件以通知其他组件
Bus.publish(FileWatcher.Event.Updated, {
file: "/path/to/file.js",
event: "change",
})
工作流程
初始化流程
项目启动
↓
project/bootstrap.ts
↓
FileWatcher.init()
├─ 检查是否禁用
├─ 懒加载 @parcel/watcher
├─ 检测平台后端
├─ 创建项目目录订阅(如果启用实验性标志)
├─ 创建 Git 目录订阅
└─ 设置事件回调
事件处理流程
文件系统变更
↓
@parcel/watcher 检测
↓
发布到回调
↓
映射到 OpenCode 事件类型
↓
Bus.publish("file.watcher.updated")
↓
订阅者接收事件
├─ VCS: 检测分支变更
├─ Web UI: 自动重载文件
└─ 其他组件处理
性能考虑
超时设置
订阅操作有 10 秒超时:
const SUBSCRIBE_TIMEOUT_MS = 10_000
位置: packages/opencode/src/file/watcher.ts:18
如果订阅超时,会自动清理并记录错误。
懒加载
平台特定的原生绑定使用懒加载:
const watcher = lazy((): typeof import("@parcel/watcher") | undefined => {
try {
const binding = require(`@parcel/watcher-${process.platform}-${process.arch}...`)
return createWrapper(binding)
} catch (error) {
log.error("failed to load watcher binding", { error })
return undefined
}
})
这确保只有在需要时才加载绑定,减少启动时间。
清理
当实例销毁时,自动取消所有订阅:
;async (state) => {
if (!state.subs) return
await Promise.all(state.subs.map((sub) => sub?.unsubscribe()))
}
对象关系
架构概览
依赖项
核心依赖
@parcel/watcher(v2.5.1): 跨平台文件监听库
平台特定绑定
根据操作系统和架构自动加载:
@parcel/watcher-darwin-arm64@parcel/watcher-darwin-x64@parcel/watcher-linux-x64-glibc@parcel/watcher-linux-x64-musl@parcel/watcher-win32-x64
相关文档
变更历史
| 版本 | 变更内容 | 日期 |
|---|---|---|
| v1 | 初始 FileWatcher 架构 | - |
| v1.1 | 添加 Git 分支检测 | - |
| v1.2 | 添加实验性标志和配置 | - |