mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-21 03:15:11 +00:00
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: rekram1-node <rekram1-node@users.noreply.github.com>
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
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"
|
|
|
|
const log = Log.create({ service: "vcs" })
|
|
|
|
export namespace Vcs {
|
|
export const Event = {
|
|
BranchUpdated: Bus.event(
|
|
"vcs.branch.updated",
|
|
z.object({
|
|
branch: z.string().optional(),
|
|
}),
|
|
),
|
|
}
|
|
|
|
async function currentBranch() {
|
|
return $`git rev-parse --abbrev-ref HEAD`
|
|
.quiet()
|
|
.nothrow()
|
|
.cwd(Instance.worktree)
|
|
.text()
|
|
.then((x) => x.trim())
|
|
.catch(() => undefined)
|
|
}
|
|
|
|
const state = Instance.state(
|
|
async () => {
|
|
if (Instance.project.vcs !== "git") {
|
|
return { branch: async () => undefined, watcher: 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 })
|
|
}
|
|
|
|
return {
|
|
branch: async () => current,
|
|
watcher,
|
|
}
|
|
},
|
|
async (state) => {
|
|
state.watcher?.close()
|
|
},
|
|
)
|
|
|
|
export async function init() {
|
|
return state()
|
|
}
|
|
|
|
export async function branch() {
|
|
return await state().then((s) => s.branch())
|
|
}
|
|
}
|