mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 06:12:26 +00:00
feat: improve file watcher with chokidar and better ignore patterns (#2621)
Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
61
packages/opencode/src/file/ignore.ts
Normal file
61
packages/opencode/src/file/ignore.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
export namespace FileIgnore {
|
||||
const DEFAULT_PATTERNS = [
|
||||
// Dependencies
|
||||
"**/node_modules/**",
|
||||
"**/bower_components/**",
|
||||
"**/.pnpm-store/**",
|
||||
"**/vendor/**",
|
||||
|
||||
// vcs
|
||||
"**/.git/**",
|
||||
|
||||
// Build outputs
|
||||
"**/dist/**",
|
||||
"**/build/**",
|
||||
"**/out/**",
|
||||
"**/.next/**",
|
||||
"**/target/**", // Rust
|
||||
"**/bin/**",
|
||||
"**/obj/**", // .NET
|
||||
|
||||
// Version control
|
||||
"**/.git/**",
|
||||
"**/.svn/**",
|
||||
"**/.hg/**",
|
||||
|
||||
// IDE/Editor
|
||||
"**/.vscode/**",
|
||||
"**/.idea/**",
|
||||
"**/*.swp",
|
||||
"**/*.swo",
|
||||
|
||||
// OS
|
||||
"**/.DS_Store",
|
||||
"**/Thumbs.db",
|
||||
|
||||
// Logs & temp
|
||||
"**/logs/**",
|
||||
"**/tmp/**",
|
||||
"**/temp/**",
|
||||
"**/*.log",
|
||||
|
||||
// Coverage/test outputs
|
||||
"**/coverage/**",
|
||||
"**/.nyc_output/**",
|
||||
]
|
||||
|
||||
const GLOBS = DEFAULT_PATTERNS.map((p) => new Bun.Glob(p))
|
||||
|
||||
export function match(
|
||||
filepath: string,
|
||||
opts: {
|
||||
extra?: Bun.Glob[]
|
||||
},
|
||||
) {
|
||||
const extra = opts.extra || []
|
||||
for (const glob of [...GLOBS, ...extra]) {
|
||||
if (glob.match(filepath)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import z from "zod/v4"
|
||||
import { Bus } from "../bus"
|
||||
import fs from "fs"
|
||||
import { Log } from "../util/log"
|
||||
import { Flag } from "../flag/flag"
|
||||
import { Instance } from "../project/instance"
|
||||
|
||||
export namespace FileWatcher {
|
||||
const log = Log.create({ service: "file.watcher" })
|
||||
|
||||
export const Event = {
|
||||
Updated: Bus.event(
|
||||
"file.watcher.updated",
|
||||
z.object({
|
||||
file: z.string(),
|
||||
event: z.union([z.literal("rename"), z.literal("change")]),
|
||||
}),
|
||||
),
|
||||
}
|
||||
const state = Instance.state(
|
||||
() => {
|
||||
if (Instance.project.vcs !== "git") return {}
|
||||
try {
|
||||
const watcher = fs.watch(Instance.directory, { recursive: true }, (event, file) => {
|
||||
log.info("change", { file, event })
|
||||
if (!file) return
|
||||
Bus.publish(Event.Updated, {
|
||||
file,
|
||||
event,
|
||||
})
|
||||
})
|
||||
return { watcher }
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
async (state) => {
|
||||
state.watcher?.close()
|
||||
},
|
||||
)
|
||||
|
||||
export function init() {
|
||||
if (Flag.OPENCODE_DISABLE_WATCHER || true) return
|
||||
state()
|
||||
}
|
||||
}
|
||||
61
packages/opencode/src/file/watcher.ts
Normal file
61
packages/opencode/src/file/watcher.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import z from "zod/v4"
|
||||
import { Bus } from "../bus"
|
||||
import chokidar from "chokidar"
|
||||
import { Flag } from "../flag/flag"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Log } from "../util/log"
|
||||
import { FileIgnore } from "./ignore"
|
||||
import { Config } from "../config/config"
|
||||
|
||||
export namespace FileWatcher {
|
||||
const log = Log.create({ service: "file.watcher" })
|
||||
|
||||
export const Event = {
|
||||
Updated: Bus.event(
|
||||
"file.watcher.updated",
|
||||
z.object({
|
||||
file: z.string(),
|
||||
event: z.union([z.literal("add"), z.literal("change"), z.literal("unlink")]),
|
||||
}),
|
||||
),
|
||||
}
|
||||
|
||||
const state = Instance.state(
|
||||
async () => {
|
||||
if (Instance.project.vcs !== "git") return {}
|
||||
log.info("init")
|
||||
const cfg = await Config.get()
|
||||
const ignore = (cfg.watcher?.ignore ?? []).map((v) => new Bun.Glob(v))
|
||||
const watcher = chokidar.watch(Instance.directory, {
|
||||
ignoreInitial: true,
|
||||
awaitWriteFinish: true,
|
||||
ignored: (filepath) => {
|
||||
return FileIgnore.match(filepath, {
|
||||
extra: ignore,
|
||||
})
|
||||
},
|
||||
})
|
||||
watcher.on("change", (file) => {
|
||||
Bus.publish(Event.Updated, { file, event: "change" })
|
||||
})
|
||||
watcher.on("add", (file) => {
|
||||
Bus.publish(Event.Updated, { file, event: "add" })
|
||||
})
|
||||
watcher.on("unlink", (file) => {
|
||||
Bus.publish(Event.Updated, { file, event: "unlink" })
|
||||
})
|
||||
watcher.on("ready", () => {
|
||||
log.info("ready")
|
||||
})
|
||||
return { watcher }
|
||||
},
|
||||
async (state) => {
|
||||
state.watcher?.close()
|
||||
},
|
||||
)
|
||||
|
||||
export function init() {
|
||||
if (!Flag.OPENCODE_EXPERIMENTAL_WATCHER) return
|
||||
state()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user