@@ -30,13 +30,41 @@ type Client interface {
3030 Configure (ctx context.Context , fsys afero.Fs ) error
3131}
3232
33+
34+ // baseClient provides default implementations for the Client interface
35+ type baseClient struct {
36+ name string
37+ displayName string
38+ installInstructions string
39+ checkInstalled func () bool
40+ }
41+
42+ func (b * baseClient ) Name () string {
43+ return b .name
44+ }
45+
46+ func (b * baseClient ) DisplayName () string {
47+ return b .displayName
48+ }
49+
50+ func (b * baseClient ) IsInstalled () bool {
51+ if b .checkInstalled != nil {
52+ return b .checkInstalled ()
53+ }
54+ return false
55+ }
56+
57+ func (b * baseClient ) InstallInstructions () string {
58+ return b .installInstructions
59+ }
60+
3361// clientRegistry holds all supported clients
3462var clientRegistry = []Client {
35- & claudeCodeClient {} ,
36- & cursorClient {} ,
63+ newClaudeCodeClient () ,
64+ newCursorClient () ,
3765 // Add new clients here in the future:
38- // &vscodeClient{} ,
39- // &claudeDesktopClient{} ,
66+ // newVSCodeClient() ,
67+ // newClaudeDesktopClient() ,
4068}
4169
4270func Run (ctx context.Context , fsys afero.Fs , clientFlag string ) error {
@@ -122,22 +150,21 @@ func configureSpecificClient(ctx context.Context, fsys afero.Fs, clientName stri
122150}
123151
124152// claudeCodeClient implements the Client interface for Claude Code
125- type claudeCodeClient struct {}
126-
127- func (c * claudeCodeClient ) Name () string {
128- return "claude-code"
129- }
130-
131- func (c * claudeCodeClient ) DisplayName () string {
132- return "Claude Code"
153+ type claudeCodeClient struct {
154+ baseClient
133155}
134156
135- func (c * claudeCodeClient ) IsInstalled () bool {
136- return commandExists ("claude" )
137- }
138-
139- func (c * claudeCodeClient ) InstallInstructions () string {
140- return "npm install -g @anthropic-ai/claude-cli"
157+ func newClaudeCodeClient () * claudeCodeClient {
158+ return & claudeCodeClient {
159+ baseClient : baseClient {
160+ name : "claude-code" ,
161+ displayName : "Claude Code" ,
162+ installInstructions : "npm install -g @anthropic-ai/claude-cli" ,
163+ checkInstalled : func () bool {
164+ return commandExists ("claude" )
165+ },
166+ },
167+ }
141168}
142169
143170func (c * claudeCodeClient ) Configure (ctx context.Context , fsys afero.Fs ) error {
@@ -169,23 +196,21 @@ func commandExists(command string) bool {
169196}
170197
171198// cursorClient implements the Client interface for Cursor
172- type cursorClient struct {}
173-
174- func (c * cursorClient ) Name () string {
175- return "cursor"
199+ type cursorClient struct {
200+ baseClient
176201}
177202
178- func ( c * cursorClient ) DisplayName () string {
179- return "Cursor"
180- }
181-
182- func ( c * cursorClient ) IsInstalled () bool {
183- // Check if cursor command exists or app is installed
184- return commandExists ( "cursor" ) || appExists ( "Cursor" )
185- }
186-
187- func ( c * cursorClient ) InstallInstructions () string {
188- return "Download from https://cursor.sh"
203+ func newCursorClient () * cursorClient {
204+ return & cursorClient {
205+ baseClient : baseClient {
206+ name : "cursor" ,
207+ displayName : "Cursor" ,
208+ installInstructions : "Download from https:// cursor.sh" ,
209+ checkInstalled : func () bool {
210+ return commandExists ( "cursor" ) || appExists ( "Cursor" )
211+ },
212+ },
213+ }
189214}
190215
191216func (c * cursorClient ) Configure (ctx context.Context , fsys afero.Fs ) error {
@@ -292,4 +317,43 @@ func appExists(appName string) bool {
292317 return false
293318}
294319
320+ // Example: Adding a new client
321+ //
322+ // 1. Create a struct that embeds baseClient:
323+ //
324+ // type myNewClient struct {
325+ // baseClient
326+ // }
327+ //
328+ // 2. Create a constructor function:
329+ //
330+ // func newMyNewClient() *myNewClient {
331+ // return &myNewClient{
332+ // baseClient: baseClient{
333+ // name: "my-client",
334+ // displayName: "My Client",
335+ // installInstructions: "Installation command or URL",
336+ // checkInstalled: func() bool {
337+ // return commandExists("my-cli") || appExists("MyApp")
338+ // },
339+ // },
340+ // }
341+ // }
342+ //
343+ // 3. Implement the Configure method:
344+ //
345+ // func (c *myNewClient) Configure(ctx context.Context, fsys afero.Fs) error {
346+ // // Your configuration logic here
347+ // // See claudeCodeClient or cursorClient for examples
348+ // return nil
349+ // }
350+ //
351+ // 4. Add to clientRegistry:
352+ //
353+ // var clientRegistry = []Client{
354+ // newClaudeCodeClient(),
355+ // newCursorClient(),
356+ // newMyNewClient(), // Add here
357+ // }
358+
295359
0 commit comments