mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-01 22:48:16 +00:00
enable parcel file watcher, expand parcel ignore patterns, replace fs watcher for git branches with parcel (#4805)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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?.()
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user