11import { BusEvent } from "@/bus/bus-event"
22import { Bus } from "@/bus"
3- import path from "path"
43import z from "zod"
54import { Log } from "@/util/log"
65import { Instance } from "./instance"
6+ import { InstanceContext } from "@/effect/instance-context"
77import { FileWatcher } from "@/file/watcher"
88import { git } from "@/util/git"
9+ import { Effect , Layer , ServiceMap } from "effect"
910
1011const log = Log . create ( { service : "vcs" } )
1112
@@ -27,50 +28,57 @@ export namespace Vcs {
2728 ref : "VcsInfo" ,
2829 } )
2930 export type Info = z . infer < typeof Info >
31+ }
3032
31- async function currentBranch ( ) {
32- const result = await git ( [ "rev-parse" , "--abbrev-ref" , "HEAD" ] , {
33- cwd : Instance . worktree ,
34- } )
35- if ( result . exitCode !== 0 ) return
36- const text = result . text ( ) . trim ( )
37- if ( ! text ) return
38- return text
33+ export namespace VcsService {
34+ export interface Service {
35+ readonly init : ( ) => Effect . Effect < void >
36+ readonly branch : ( ) => Effect . Effect < string | undefined >
3937 }
38+ }
4039
41- const state = Instance . state (
42- async ( ) => {
43- if ( Instance . project . vcs !== "git" ) {
44- return { branch : async ( ) => undefined , unsubscribe : undefined }
45- }
46- let current = await currentBranch ( )
47- log . info ( "initialized" , { branch : current } )
40+ export class VcsService extends ServiceMap . Service < VcsService , VcsService . Service > ( ) ( "@opencode/Vcs" ) {
41+ static readonly layer = Layer . effect (
42+ VcsService ,
43+ Effect . gen ( function * ( ) {
44+ const instance = yield * InstanceContext
45+ let current : string | undefined
4846
49- const unsubscribe = Bus . subscribe ( FileWatcher . Event . Updated , async ( evt ) => {
50- if ( ! evt . properties . file . endsWith ( "HEAD" ) ) return
51- const next = await currentBranch ( )
52- if ( next !== current ) {
53- log . info ( "branch changed" , { from : current , to : next } )
54- current = next
55- Bus . publish ( Event . BranchUpdated , { branch : next } )
47+ if ( instance . project . vcs === "git" ) {
48+ const currentBranch = async ( ) => {
49+ const result = await git ( [ "rev-parse" , "--abbrev-ref" , "HEAD" ] , {
50+ cwd : instance . project . worktree ,
51+ } )
52+ if ( result . exitCode !== 0 ) return undefined
53+ const text = result . text ( ) . trim ( )
54+ return text || undefined
5655 }
57- } )
5856
59- return {
60- branch : async ( ) => current ,
61- unsubscribe,
62- }
63- } ,
64- async ( state ) => {
65- state . unsubscribe ?.( )
66- } ,
67- )
57+ current = yield * Effect . promise ( ( ) => currentBranch ( ) )
58+ log . info ( "initialized" , { branch : current } )
6859
69- export async function init ( ) {
70- return state ( )
71- }
60+ const unsubscribe = Bus . subscribe (
61+ FileWatcher . Event . Updated ,
62+ Instance . bind ( async ( evt ) => {
63+ if ( ! evt . properties . file . endsWith ( "HEAD" ) ) return
64+ const next = await currentBranch ( )
65+ if ( next !== current ) {
66+ log . info ( "branch changed" , { from : current , to : next } )
67+ current = next
68+ Bus . publish ( Vcs . Event . BranchUpdated , { branch : next } )
69+ }
70+ } ) ,
71+ )
7272
73- export async function branch ( ) {
74- return await state ( ) . then ( ( s ) => s . branch ( ) )
75- }
73+ yield * Effect . addFinalizer ( ( ) => Effect . sync ( unsubscribe ) )
74+ }
75+
76+ return VcsService . of ( {
77+ init : Effect . fn ( "VcsService.init" ) ( function * ( ) { } ) ,
78+ branch : Effect . fn ( "VcsService.branch" ) ( function * ( ) {
79+ return current
80+ } ) ,
81+ } )
82+ } ) ,
83+ )
7684}
0 commit comments