mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-27 03:51:21 -04:00
refactor(core): move git vcs into internal plugin (#44992)
This commit is contained in:
@@ -85,6 +85,7 @@ import { PluginRuntime } from "./runtime.js"
|
||||
import { SkillPlugin } from "./skill.js"
|
||||
import { SystemPromptPlugin } from "./system-prompt.js"
|
||||
import { VariantPlugin } from "./variant.js"
|
||||
import { VcsGitPlugin } from "./vcs/git.js"
|
||||
import { WarmingPlugin } from "./warming.js"
|
||||
import { WellKnownPlugin } from "../wellknown/plugin.js"
|
||||
|
||||
@@ -235,6 +236,7 @@ const pre = [
|
||||
ConfigMCPPlugin.Plugin,
|
||||
MCPCodeModeExclusionPlugin.Plugin,
|
||||
WellKnownPlugin.Plugin,
|
||||
VcsGitPlugin.Plugin,
|
||||
AgentPlugin.Plugin,
|
||||
PlanPlugin.Plugin,
|
||||
CommandPlugin.Plugin,
|
||||
|
||||
@@ -1,20 +1,47 @@
|
||||
export * as VcsGit from "./git.js"
|
||||
export * as VcsGitPlugin from "./git.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { Effect } from "effect"
|
||||
import { ChildProcess } from "effect/unstable/process"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { BranchList, FileStatus, Info, Mode } from "@opencode-ai/schema/vcs"
|
||||
import { AppProcess } from "@opencode-ai/util/process"
|
||||
import type { Adapter, BranchOptions, DiffOptions } from "../vcs.js"
|
||||
import { chunksByFile, emptyPatch, MAX_PATCH_BYTES, MAX_TOTAL_PATCH_BYTES, PATCH_CONTEXT_LINES } from "./patch.js"
|
||||
import type { Patch } from "./patch.js"
|
||||
import { Location } from "../../location.js"
|
||||
import type { Adapter, BranchOptions, DiffOptions } from "../../vcs.js"
|
||||
import { chunksByFile, emptyPatch, MAX_PATCH_BYTES, MAX_TOTAL_PATCH_BYTES, PATCH_CONTEXT_LINES } from "../../vcs/patch.js"
|
||||
import type { Patch } from "../../vcs/patch.js"
|
||||
|
||||
export const Plugin = define({
|
||||
id: "opencode.vcs.git",
|
||||
effect: Effect.fn("VcsGitPlugin")(function* (ctx) {
|
||||
const location = yield* Location.Service
|
||||
if (location.vcs?.type !== "git") return
|
||||
|
||||
const processes = yield* AppProcess.Service
|
||||
const adapter = make(processes, {
|
||||
directory: location.directory,
|
||||
worktree: location.project.directory,
|
||||
})
|
||||
|
||||
yield* ctx.vcs.transform((draft) => {
|
||||
draft.add({
|
||||
id: "git",
|
||||
name: "Git",
|
||||
info: () => adapter.info(),
|
||||
branches: (input) => adapter.branches({ search: input.search, limit: input.limit }),
|
||||
status: () => adapter.status(),
|
||||
diff: (input) => adapter.diff(input.mode, { context: input.context }),
|
||||
})
|
||||
})
|
||||
}),
|
||||
})
|
||||
|
||||
/**
|
||||
* Git adapter for the Vcs service. Ported from the V1 pipeline: patches are
|
||||
* batched through one `git diff` invocation where possible and capped by
|
||||
* per-file and total byte budgets, falling back to empty patches when capped.
|
||||
*/
|
||||
export function make(proc: AppProcess.Interface, input: { directory: string; worktree: string }): Adapter {
|
||||
function make(proc: AppProcess.Interface, input: { directory: string; worktree: string }): Adapter {
|
||||
// Listing commands scope pathspecs to the requested directory; per-file
|
||||
// commands run from the worktree root because git lists root-relative paths.
|
||||
const ctx: Ctx = { git: makeGit(proc), directory: input.directory, worktree: input.worktree }
|
||||
@@ -13,7 +13,6 @@ import { Location } from "./location.js"
|
||||
import { AppProcess } from "@opencode-ai/util/process"
|
||||
import { Bus } from "./bus.js"
|
||||
import { State } from "./state.js"
|
||||
import { VcsGit } from "./vcs/git.js"
|
||||
import { VcsHg } from "./vcs/hg.js"
|
||||
import { emptyPatch, MAX_TOTAL_PATCH_BYTES, PATCH_CONTEXT_LINES } from "./vcs/patch.js"
|
||||
|
||||
@@ -49,7 +48,6 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/Vc
|
||||
// results so callers never need to special-case.
|
||||
const adapter = (proc: AppProcess.Interface, fs: FSUtil.Interface, location: Location.Interface) => {
|
||||
const scope = { directory: location.directory, worktree: location.project.directory }
|
||||
if (location.vcs?.type === "git") return VcsGit.make(proc, scope)
|
||||
if (location.vcs?.type === "hg") return VcsHg.make(proc, fs, scope)
|
||||
}
|
||||
|
||||
@@ -69,7 +67,7 @@ const layer = Layer.effect(
|
||||
canonical: location.project.canonical,
|
||||
...(vcs ? { store: vcs.store } : {}),
|
||||
}
|
||||
const decodeInfo = Schema.decodeUnknownEffect(Info)
|
||||
const decodeInfo = Schema.decodeUnknownEffect(Schema.toType(Info))
|
||||
const decodeBranches = Schema.decodeUnknownEffect(BranchList)
|
||||
const decodeStatus = Schema.decodeUnknownEffect(Schema.Array(FileStatus))
|
||||
const decodeDiff = Schema.decodeUnknownEffect(Schema.Array(FileDiff.Info))
|
||||
@@ -112,7 +110,7 @@ const layer = Layer.effect(
|
||||
if (changed) yield* bus.publish(VcsEvent.BranchUpdated, { branch: next.branch.current })
|
||||
})
|
||||
|
||||
if (vcs && native) {
|
||||
if (vcs) {
|
||||
const store = yield* fs.realPath(vcs.store).pipe(Effect.orElseSucceed(() => vcs.store))
|
||||
const isBranchMetadata =
|
||||
vcs.type === "git"
|
||||
|
||||
@@ -4,20 +4,23 @@ import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { Cause, Effect, Exit, Fiber, Layer, Stream } from "effect"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { AppProcess } from "@opencode-ai/util/process"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||
import { Vcs } from "@opencode-ai/core/vcs"
|
||||
import { VcsGitPlugin } from "@opencode-ai/core/plugin/vcs/git"
|
||||
import type { VcsDefinition, VcsDiffInput } from "@opencode-ai/plugin/effect/vcs"
|
||||
import { FileSystem } from "@opencode-ai/schema/filesystem"
|
||||
import { VcsEvent } from "@opencode-ai/schema/vcs-event"
|
||||
import { location } from "./fixture/location"
|
||||
import { tmpdir } from "./fixture/tmpdir"
|
||||
import { it } from "./lib/effect"
|
||||
import { host } from "./plugin/host"
|
||||
|
||||
const provide = (directory: string, input: { git?: boolean } = {}) =>
|
||||
Effect.provide(
|
||||
LayerNode.compile(LayerNode.group([Vcs.node, Bus.node]), [
|
||||
LayerNode.compile(LayerNode.group([Vcs.node, Bus.node, Location.node, AppProcess.node]), [
|
||||
[
|
||||
Location.node,
|
||||
Layer.succeed(
|
||||
@@ -42,7 +45,17 @@ const withTmp = <A, E, R>(f: (directory: string) => Effect.Effect<A, E, R>) =>
|
||||
const withGit = <A, E, R>(f: (directory: string) => Effect.Effect<A, E, R>) =>
|
||||
withTmp((directory) =>
|
||||
Effect.promise(() => initRepo(directory)).pipe(
|
||||
Effect.andThen(f(directory).pipe(provide(directory, { git: true }))),
|
||||
Effect.andThen(
|
||||
Effect.gen(function* () {
|
||||
const vcs = yield* Vcs.Service
|
||||
const context = host()
|
||||
yield* VcsGitPlugin.Plugin.effect({
|
||||
...context,
|
||||
vcs: { ...context.vcs, transform: vcs.transform, reload: vcs.reload },
|
||||
})
|
||||
return yield* f(directory)
|
||||
}).pipe(provide(directory, { git: true })),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user