Compare commits

..

1 Commits

Author SHA1 Message Date
Kit Langton 7c29a5aded refactor: use InstanceState context in worktree cleanup paths 2026-04-16 23:35:53 -04:00
3 changed files with 34 additions and 38 deletions
+19 -21
View File
@@ -1,17 +1,15 @@
import { Npm } from "../npm"
import type { InstanceContext } from "../project/instance"
import { Instance } from "../project/instance"
import { Filesystem } from "../util"
import { Process } from "../util"
import { which } from "../util/which"
import { Flag } from "@/flag/flag"
export interface Context extends Pick<InstanceContext, "directory" | "worktree"> {}
export interface Info {
name: string
environment?: Record<string, string>
extensions: string[]
enabled(context: Context): Promise<string[] | false>
enabled(): Promise<string[] | false>
}
export const gofmt: Info = {
@@ -67,8 +65,8 @@ export const prettier: Info = {
".graphql",
".gql",
],
async enabled(context) {
const items = await Filesystem.findUp("package.json", context.directory, context.worktree)
async enabled() {
const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree)
for (const item of items) {
const json = await Filesystem.readJson<{
dependencies?: Record<string, string>
@@ -89,9 +87,9 @@ export const oxfmt: Info = {
BUN_BE_BUN: "1",
},
extensions: [".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"],
async enabled(context) {
async enabled() {
if (!Flag.OPENCODE_EXPERIMENTAL_OXFMT) return false
const items = await Filesystem.findUp("package.json", context.directory, context.worktree)
const items = await Filesystem.findUp("package.json", Instance.directory, Instance.worktree)
for (const item of items) {
const json = await Filesystem.readJson<{
dependencies?: Record<string, string>
@@ -139,10 +137,10 @@ export const biome: Info = {
".graphql",
".gql",
],
async enabled(context) {
async enabled() {
const configs = ["biome.json", "biome.jsonc"]
for (const config of configs) {
const found = await Filesystem.findUp(config, context.directory, context.worktree)
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
if (found.length > 0) {
const bin = await Npm.which("@biomejs/biome")
if (bin) return [bin, "format", "--write", "$FILE"]
@@ -165,8 +163,8 @@ export const zig: Info = {
export const clang: Info = {
name: "clang-format",
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
async enabled(context) {
const items = await Filesystem.findUp(".clang-format", context.directory, context.worktree)
async enabled() {
const items = await Filesystem.findUp(".clang-format", Instance.directory, Instance.worktree)
if (items.length > 0) {
const match = which("clang-format")
if (match) return [match, "-i", "$FILE"]
@@ -188,11 +186,11 @@ export const ktlint: Info = {
export const ruff: Info = {
name: "ruff",
extensions: [".py", ".pyi"],
async enabled(context) {
async enabled() {
if (!which("ruff")) return false
const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"]
for (const config of configs) {
const found = await Filesystem.findUp(config, context.directory, context.worktree)
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
if (found.length > 0) {
if (config === "pyproject.toml") {
const content = await Filesystem.readText(found[0])
@@ -204,7 +202,7 @@ export const ruff: Info = {
}
const deps = ["requirements.txt", "pyproject.toml", "Pipfile"]
for (const dep of deps) {
const found = await Filesystem.findUp(dep, context.directory, context.worktree)
const found = await Filesystem.findUp(dep, Instance.directory, Instance.worktree)
if (found.length > 0) {
const content = await Filesystem.readText(found[0])
if (content.includes("ruff")) return ["ruff", "format", "$FILE"]
@@ -235,8 +233,8 @@ export const rlang: Info = {
export const uvformat: Info = {
name: "uv",
extensions: [".py", ".pyi"],
async enabled(context) {
if (await ruff.enabled(context)) return false
async enabled() {
if (await ruff.enabled()) return false
const uv = which("uv")
if (uv == null) return false
const output = await Process.run([uv, "format", "--help"], { nothrow: true })
@@ -288,9 +286,9 @@ export const dart: Info = {
export const ocamlformat: Info = {
name: "ocamlformat",
extensions: [".ml", ".mli"],
async enabled(context) {
async enabled() {
if (!which("ocamlformat")) return false
const items = await Filesystem.findUp(".ocamlformat", context.directory, context.worktree)
const items = await Filesystem.findUp(".ocamlformat", Instance.directory, Instance.worktree)
if (items.length > 0) return ["ocamlformat", "-i", "$FILE"]
return false
},
@@ -359,8 +357,8 @@ export const rustfmt: Info = {
export const pint: Info = {
name: "pint",
extensions: [".php"],
async enabled(context) {
const items = await Filesystem.findUp("composer.json", context.directory, context.worktree)
async enabled() {
const items = await Filesystem.findUp("composer.json", Instance.directory, Instance.worktree)
for (const item of items) {
const json = await Filesystem.readJson<{
require?: Record<string, string>
+2 -6
View File
@@ -40,15 +40,11 @@ export const layer = Layer.effect(
Effect.fn("Format.state")(function* (_ctx) {
const commands: Record<string, string[] | false> = {}
const formatters: Record<string, Formatter.Info> = {}
const context = {
directory: _ctx.directory,
worktree: _ctx.worktree,
}
async function getCommand(item: Formatter.Info) {
let cmd = commands[item.name]
if (cmd === false || cmd === undefined) {
cmd = await item.enabled(context)
cmd = await item.enabled()
commands[item.name] = cmd
}
return cmd
@@ -157,7 +153,7 @@ export const layer = Layer.effect(
...info,
name,
extensions: info.extensions ?? [],
enabled: builtIn && !info.command ? builtIn.enabled : async (_context) => info.command ?? false,
enabled: builtIn && !info.command ? builtIn.enabled : async () => info.command ?? false,
}
}
}
+13 -11
View File
@@ -365,13 +365,14 @@ export const layer: Layer.Layer<
}
const remove = Effect.fn("Worktree.remove")(function* (input: RemoveInput) {
if (Instance.project.vcs !== "git") {
const ctx = yield* InstanceState.context
if (ctx.project.vcs !== "git") {
throw new NotGitError({ message: "Worktrees are only supported for git projects" })
}
const directory = yield* canonical(input.directory)
const list = yield* git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree })
const list = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree })
if (list.code !== 0) {
throw new RemoveFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" })
}
@@ -389,9 +390,9 @@ export const layer: Layer.Layer<
}
yield* stopFsmonitor(entry.path)
const removed = yield* git(["worktree", "remove", "--force", entry.path], { cwd: Instance.worktree })
const removed = yield* git(["worktree", "remove", "--force", entry.path], { cwd: ctx.worktree })
if (removed.code !== 0) {
const next = yield* git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree })
const next = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree })
if (next.code !== 0) {
throw new RemoveFailedError({
message: removed.stderr || removed.text || next.stderr || next.text || "Failed to remove git worktree",
@@ -408,7 +409,7 @@ export const layer: Layer.Layer<
const branch = entry.branch?.replace(/^refs\/heads\//, "")
if (branch) {
const deleted = yield* git(["branch", "-D", branch], { cwd: Instance.worktree })
const deleted = yield* git(["branch", "-D", branch], { cwd: ctx.worktree })
if (deleted.code !== 0) {
throw new RemoveFailedError({
message: deleted.stderr || deleted.text || "Failed to delete worktree branch",
@@ -498,17 +499,18 @@ export const layer: Layer.Layer<
})
const reset = Effect.fn("Worktree.reset")(function* (input: ResetInput) {
if (Instance.project.vcs !== "git") {
const ctx = yield* InstanceState.context
if (ctx.project.vcs !== "git") {
throw new NotGitError({ message: "Worktrees are only supported for git projects" })
}
const directory = yield* canonical(input.directory)
const primary = yield* canonical(Instance.worktree)
const primary = yield* canonical(ctx.worktree)
if (directory === primary) {
throw new ResetFailedError({ message: "Cannot reset the primary workspace" })
}
const list = yield* git(["worktree", "list", "--porcelain"], { cwd: Instance.worktree })
const list = yield* git(["worktree", "list", "--porcelain"], { cwd: ctx.worktree })
if (list.code !== 0) {
throw new ResetFailedError({ message: list.stderr || list.text || "Failed to read git worktrees" })
}
@@ -520,7 +522,7 @@ export const layer: Layer.Layer<
const worktreePath = entry.path
const base = yield* gitSvc.defaultBranch(Instance.worktree)
const base = yield* gitSvc.defaultBranch(ctx.worktree)
if (!base) {
throw new ResetFailedError({ message: "Default branch not found" })
}
@@ -531,7 +533,7 @@ export const layer: Layer.Layer<
const branch = base.ref.slice(sep + 1)
yield* gitExpect(
["fetch", remote, branch],
{ cwd: Instance.worktree },
{ cwd: ctx.worktree },
(r) => new ResetFailedError({ message: r.stderr || r.text || `Failed to fetch ${base.ref}` }),
)
}
@@ -574,7 +576,7 @@ export const layer: Layer.Layer<
throw new ResetFailedError({ message: `Worktree reset left local changes:\n${status.text.trim()}` })
}
yield* runStartScripts(worktreePath, { projectID: Instance.project.id }).pipe(
yield* runStartScripts(worktreePath, { projectID: ctx.project.id }).pipe(
Effect.catchCause((cause) => Effect.sync(() => log.error("worktree start task failed", { cause }))),
Effect.forkIn(scope),
)