enable parcel file watcher, expand parcel ignore patterns, replace fs watcher for git branches with parcel (#4805)

This commit is contained in:
Aiden Cline
2025-11-26 15:33:43 -08:00
committed by GitHub
parent 3ff0eb3065
commit 99d7ff47c4
5 changed files with 77 additions and 62 deletions

View File

@@ -6,6 +6,7 @@ export namespace FileIgnore {
"bower_components",
".pnpm-store",
"vendor",
".npm",
"dist",
"build",
"out",
@@ -22,12 +23,21 @@ export namespace FileIgnore {
".output",
"desktop",
".sst",
".cache",
".webkit-cache",
"__pycache__",
".pytest_cache",
"mypy_cache",
".history",
".gradle",
])
const FILES = [
"**/*.swp",
"**/*.swo",
"**/*.pyc",
// OS
"**/.DS_Store",
"**/Thumbs.db",

View File

@@ -1,6 +1,5 @@
import z from "zod"
import { Bus } from "../bus"
import { Flag } from "../flag/flag"
import { Instance } from "../project/instance"
import { Log } from "../util/log"
import { FileIgnore } from "./ignore"
@@ -8,6 +7,7 @@ import { Config } from "../config/config"
// @ts-ignore
import { createWrapper } from "@parcel/watcher/wrapper"
import { lazy } from "@/util/lazy"
import type ParcelWatcher from "@parcel/watcher"
export namespace FileWatcher {
const log = Log.create({ service: "file.watcher" })
@@ -44,32 +44,46 @@ export namespace FileWatcher {
return {}
}
log.info("watcher backend", { platform: process.platform, backend })
const sub = await watcher().subscribe(
Instance.directory,
(err, evts) => {
if (err) return
for (const evt of evts) {
log.info("event", evt)
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" })
}
},
{
ignore: [...FileIgnore.PATTERNS, ...(cfg.watcher?.ignore ?? [])],
const subscribe: ParcelWatcher.SubscribeCallback = (err, evts) => {
if (err) return
for (const evt of evts) {
log.info("event", evt)
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" })
}
}
const subs = []
const cfgIgnores = cfg.watcher?.ignore ?? []
subs.push(
await watcher().subscribe(Instance.directory, subscribe, {
ignore: [...FileIgnore.PATTERNS, ...cfgIgnores],
backend,
},
}),
)
return { sub }
const vcsDir = Instance.project.vcsDir
if (vcsDir && !cfgIgnores.includes(".git") && !cfgIgnores.includes(vcsDir)) {
subs.push(
await watcher().subscribe(vcsDir, subscribe, {
ignore: ["hooks", "info", "logs", "objects", "refs", "worktrees", "modules", "lfs"],
backend,
}),
)
}
return { subs }
},
async (state) => {
if (!state.sub) return
await state.sub?.unsubscribe()
if (!state.subs) return
await Promise.all(state.subs.map((sub) => sub?.unsubscribe()))
},
)
export function init() {
if (!Flag.OPENCODE_EXPERIMENTAL_WATCHER) return
// if (!Flag.OPENCODE_EXPERIMENTAL_WATCHER) return
state()
}
}

View File

@@ -12,6 +12,7 @@ export namespace Project {
.object({
id: z.string(),
worktree: z.string(),
vcsDir: z.string().optional(),
vcs: z.literal("git").optional(),
time: z.object({
created: z.number(),
@@ -80,9 +81,16 @@ export namespace Project {
.cwd(worktree)
.text()
.then((x) => x.trim())
const vcsDir = await $`git rev-parse --path-format=absolute --git-dir`
.quiet()
.nothrow()
.cwd(worktree)
.text()
.then((x) => x.trim())
const project: Info = {
id,
worktree,
vcsDir,
vcs: "git",
time: {
created: Date.now(),

View File

@@ -1,10 +1,10 @@
import { $ } from "bun"
import { watch, type FSWatcher } from "fs"
import path from "path"
import z from "zod"
import { Log } from "@/util/log"
import { Bus } from "@/bus"
import { Instance } from "./instance"
import { FileWatcher } from "@/file/watcher"
const log = Log.create({ service: "vcs" })
@@ -39,49 +39,31 @@ export namespace Vcs {
const state = Instance.state(
async () => {
if (Instance.project.vcs !== "git") {
return { branch: async () => undefined, watcher: undefined }
const vcsDir = Instance.project.vcsDir
if (Instance.project.vcs !== "git" || !vcsDir) {
return { branch: async () => undefined, unsubscribe: undefined }
}
let current = await currentBranch()
log.info("initialized", { branch: current })
const gitDir = await $`git rev-parse --git-dir`
.quiet()
.nothrow()
.cwd(Instance.worktree)
.text()
.then((x) => x.trim())
.catch(() => undefined)
if (!gitDir) {
log.warn("failed to resolve git directory")
return { branch: async () => current, watcher: undefined }
}
const gitHead = path.join(gitDir, "HEAD")
let watcher: FSWatcher | undefined
// we should probably centralize file watching (see watcher.ts)
// but parcel still marked experimental rn
try {
watcher = watch(gitHead, async () => {
const next = await currentBranch()
if (next !== current) {
log.info("branch changed", { from: current, to: next })
current = next
Bus.publish(Event.BranchUpdated, { branch: next })
}
})
log.info("watching", { path: gitHead })
} catch (e) {
log.warn("failed to watch git HEAD", { error: e })
}
const head = path.join(vcsDir, "HEAD")
const unsubscribe = Bus.subscribe(FileWatcher.Event.Updated, async (evt) => {
if (evt.properties.file !== head) return
const next = await currentBranch()
if (next !== current) {
log.info("branch changed", { from: current, to: next })
current = next
Bus.publish(Event.BranchUpdated, { branch: next })
}
})
return {
branch: async () => current,
watcher,
unsubscribe,
}
},
async (state) => {
state.watcher?.close()
state.unsubscribe?.()
},
)

View File

@@ -589,6 +589,14 @@ export type EventSessionError = {
}
}
export type EventFileWatcherUpdated = {
type: "file.watcher.updated"
properties: {
file: string
event: "add" | "change" | "unlink"
}
}
export type EventVcsBranchUpdated = {
type: "vcs.branch.updated"
properties: {
@@ -647,14 +655,6 @@ export type EventServerConnected = {
}
}
export type EventFileWatcherUpdated = {
type: "file.watcher.updated"
properties: {
file: string
event: "add" | "change" | "unlink"
}
}
export type Event =
| EventInstallationUpdated
| EventInstallationUpdateAvailable
@@ -677,12 +677,12 @@ export type Event =
| EventSessionDeleted
| EventSessionDiff
| EventSessionError
| EventFileWatcherUpdated
| EventVcsBranchUpdated
| EventTuiPromptAppend
| EventTuiCommandExecute
| EventTuiToastShow
| EventServerConnected
| EventFileWatcherUpdated
export type GlobalEvent = {
directory: string
@@ -692,6 +692,7 @@ export type GlobalEvent = {
export type Project = {
id: string
worktree: string
vcsDir?: string
vcs?: "git"
time: {
created: number