Skip to content

Commit f3b7100

Browse files
committed
core: replace chokidar with @parcel/watcher for better performance and cross-platform support
1 parent 0a96d25 commit f3b7100

5 files changed

Lines changed: 40 additions & 24 deletions

File tree

bun.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/opencode/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@ai-sdk/amazon-bedrock": "2.2.10",
2121
"@ai-sdk/google-vertex": "3.0.16",
2222
"@octokit/webhooks-types": "7.6.1",
23+
"@parcel/watcher-win32-x64": "2.5.1",
2324
"@standard-schema/spec": "1.0.0",
2425
"@tsconfig/bun": "1.0.7",
2526
"@types/bun": "catalog:",
@@ -37,6 +38,7 @@
3738
"@openauthjs/openauth": "0.4.3",
3839
"@opencode-ai/plugin": "workspace:*",
3940
"@opencode-ai/sdk": "workspace:*",
41+
"@parcel/watcher": "2.5.1",
4042
"@standard-schema/spec": "1.0.0",
4143
"@zip.js/zip.js": "2.7.62",
4244
"ai": "catalog:",

packages/opencode/script/build.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/env bun
2+
import path from "path"
23
const dir = new URL("..", import.meta.url).pathname
34
process.chdir(dir)
45
import { $ } from "bun"
@@ -32,6 +33,12 @@ for (const [os, arch] of targets) {
3233
await $`CGO_ENABLED=0 GOOS=${os} GOARCH=${GOARCH[arch]} go build -ldflags="-s -w -X main.Version=${version}" -o ../opencode/dist/${name}/bin/tui ../tui/cmd/opencode/main.go`
3334
.cwd("../tui")
3435
.quiet()
36+
37+
const watcher = `@parcel/watcher-${os === "windows" ? "win32" : os}-${arch.replace("-baseline", "")}${os === "linux" ? "-glibc" : ""}`
38+
await $`mkdir -p ../../node_modules/${watcher}`
39+
await $`npm pack npm pack ${watcher}`.cwd(path.join(dir, "../../node_modules")).quiet()
40+
await $`tar -xf ../../node_modules/${watcher.replace("@parcel/", "parcel-")}-*.tgz -C ../../node_modules/${watcher} --strip-components=1`
41+
3542
await Bun.build({
3643
compile: {
3744
target: `bun-${os}-${arch}` as any,

packages/opencode/src/file/ignore.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ export namespace FileIgnore {
4545

4646
const FILE_GLOBS = FILES.map((p) => new Bun.Glob(p))
4747

48+
export const PATTERNS = [...FILES, ...FOLDERS]
49+
4850
export function match(
4951
filepath: string,
5052
opts?: {

packages/opencode/src/file/watcher.ts

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import z from "zod/v4"
22
import { Bus } from "../bus"
3-
import chokidar from "chokidar"
43
import { Flag } from "../flag/flag"
54
import { Instance } from "../project/instance"
65
import { Log } from "../util/log"
76
import { FileIgnore } from "./ignore"
87
import { Config } from "../config/config"
8+
// @ts-ignore
9+
import { createWrapper } from "@parcel/watcher/wrapper"
10+
import { lazy } from "@/util/lazy"
911

1012
export namespace FileWatcher {
1113
const log = Log.create({ service: "file.watcher" })
@@ -20,37 +22,38 @@ export namespace FileWatcher {
2022
),
2123
}
2224

25+
const watcher = lazy(() => {
26+
const binding = require(
27+
`@parcel/watcher-${process.platform}-${process.arch}${process.platform === "linux" ? "-glibc" : ""}`,
28+
)
29+
return createWrapper(binding) as typeof import("@parcel/watcher")
30+
})
31+
2332
const state = Instance.state(
2433
async () => {
2534
if (Instance.project.vcs !== "git") return {}
2635
log.info("init")
2736
const cfg = await Config.get()
28-
const ignore = (cfg.watcher?.ignore ?? []).map((v) => new Bun.Glob(v))
29-
const watcher = chokidar.watch(Instance.directory, {
30-
ignoreInitial: true,
31-
ignored: (filepath) => {
32-
return FileIgnore.match(filepath, {
33-
whitelist: [new Bun.Glob("**/.git/{index,logs/HEAD}")],
34-
extra: ignore,
35-
})
37+
const sub = await watcher().subscribe(
38+
Instance.directory,
39+
(err, evts) => {
40+
if (err) return
41+
for (const evt of evts) {
42+
log.info("event", evt)
43+
if (evt.type === "create") Bus.publish(Event.Updated, { file: evt.path, event: "add" })
44+
if (evt.type === "update") Bus.publish(Event.Updated, { file: evt.path, event: "change" })
45+
if (evt.type === "delete") Bus.publish(Event.Updated, { file: evt.path, event: "unlink" })
46+
}
47+
},
48+
{
49+
ignore: [...FileIgnore.PATTERNS, ...(cfg.watcher?.ignore ?? [])],
50+
backend: "inotify",
3651
},
37-
})
38-
watcher.on("change", (file) => {
39-
Bus.publish(Event.Updated, { file, event: "change" })
40-
})
41-
watcher.on("add", (file) => {
42-
Bus.publish(Event.Updated, { file, event: "add" })
43-
})
44-
watcher.on("unlink", (file) => {
45-
Bus.publish(Event.Updated, { file, event: "unlink" })
46-
})
47-
watcher.on("ready", () => {
48-
log.info("ready")
49-
})
50-
return { watcher }
52+
)
53+
return { sub }
5154
},
5255
async (state) => {
53-
state.watcher?.close()
56+
state.sub?.unsubscribe()
5457
},
5558
)
5659

0 commit comments

Comments
 (0)