@@ -14,6 +14,7 @@ import { LocalFileSource } from "src/quartz/LocalFileSource";
1414import { QuartzVersionDetector } from "src/quartz/QuartzVersionDetector" ;
1515import { getValueByPath , setValueByPath } from "src/cli/handlers/cliUtils" ;
1616import type { PublicationCenterManager } from "src/operability/PublicationCenterManager" ;
17+ import type { QuartzHubManager } from "src/operability/QuartzHubManager" ;
1718
1819type PublishStatusSummary = {
1920 unpublished : number ;
@@ -42,6 +43,7 @@ export class ActionRegistry {
4243 private getPublicationService : ( ) => PublicationService | null ,
4344 private getOnboardingService : ( ) => OnboardingService | null ,
4445 private getPublicationCenterManager : ( ) => PublicationCenterManager | null ,
46+ private getQuartzHubManager : ( ) => QuartzHubManager | null ,
4547 ) { }
4648
4749 getPublishStatusSummary ( ) : PublishStatusSummary | null {
@@ -103,6 +105,22 @@ export class ActionRegistry {
103105 return this . selectAllPublicationPaths ( ) ;
104106 case "pub.deselectAll" :
105107 return this . deselectAllPublicationPaths ( ) ;
108+ case "hub.open" :
109+ return this . openQuartzHub ( ) ;
110+ case "hub.close" :
111+ return this . closeQuartzHub ( ) ;
112+ case "hub.setup.link" :
113+ return this . withLock ( ( ) =>
114+ this . linkLocalRepo ( action . params . path ) ,
115+ ) ;
116+ case "hub.setup.clone" :
117+ return this . withLock ( ( ) =>
118+ this . cloneAndLinkRepo (
119+ action . params . url ,
120+ action . params . dest ,
121+ action . params . confirm ,
122+ ) ,
123+ ) ;
106124 case "onboarding.start" :
107125 case "onboarding.setToken" :
108126 case "onboarding.createRepo" :
@@ -248,7 +266,7 @@ export class ActionRegistry {
248266 private openPublicationCenter ( ) : ActionResult {
249267 const manager = this . getPublicationCenterManager ( ) ;
250268 if ( ! manager ) {
251- return { success : false , error : "Publication center unavailable" } ;
269+ return { success : false , error : "Publication Center unavailable" } ;
252270 }
253271 manager . open ( ) ;
254272 return { success : true } ;
@@ -257,16 +275,111 @@ export class ActionRegistry {
257275 private closePublicationCenter ( ) : ActionResult {
258276 const manager = this . getPublicationCenterManager ( ) ;
259277 if ( ! manager ) {
260- return { success : false , error : "Publication center unavailable" } ;
278+ return { success : false , error : "Publication Center unavailable" } ;
279+ }
280+ manager . close ( ) ;
281+ return { success : true } ;
282+ }
283+
284+ private openQuartzHub ( ) : ActionResult {
285+ const manager = this . getQuartzHubManager ( ) ;
286+ if ( ! manager ) {
287+ return { success : false , error : "Quartz Hub unavailable" } ;
288+ }
289+ manager . open ( ) ;
290+ return { success : true } ;
291+ }
292+
293+ private closeQuartzHub ( ) : ActionResult {
294+ const manager = this . getQuartzHubManager ( ) ;
295+ if ( ! manager ) {
296+ return { success : false , error : "Quartz Hub unavailable" } ;
261297 }
262298 manager . close ( ) ;
263299 return { success : true } ;
264300 }
265301
302+ private async linkLocalRepo ( path : string ) : Promise < ActionResult > {
303+ if ( ! path ) {
304+ return { success : false , error : "Path is required" } ;
305+ }
306+
307+ const trimmed = path . trim ( ) ;
308+ const { QuartzHubService } =
309+ await import ( "src/services/QuartzHubService" ) ;
310+ const service = new QuartzHubService ( this . plugin ) ;
311+ const validation = service . validateRepoPath ( trimmed ) ;
312+
313+ if ( ! validation . ok ) {
314+ return { success : false , error : validation . message } ;
315+ }
316+
317+ this . plugin . settings . quartzRepoPath = trimmed ;
318+ this . plugin . settings . enableSystemCommands = true ;
319+ await this . plugin . saveSettings ( ) ;
320+
321+ return { success : true , data : { path : trimmed } } ;
322+ }
323+
324+ private async cloneAndLinkRepo (
325+ url : string ,
326+ dest : string ,
327+ confirm : true | undefined ,
328+ ) : Promise < ActionResult > {
329+ if ( ! confirm ) {
330+ return { success : false , error : "Confirmation required" } ;
331+ }
332+
333+ if ( ! url || ! dest ) {
334+ return {
335+ success : false ,
336+ error : "URL and destination path are required" ,
337+ } ;
338+ }
339+
340+ const gitRunner = this . plugin . gitRunner ;
341+ const npmRunner = this . plugin . npmRunner ;
342+
343+ if ( ! gitRunner ) {
344+ return { success : false , error : "Git runner unavailable" } ;
345+ }
346+
347+ if ( ! npmRunner ) {
348+ return { success : false , error : "Npm runner unavailable" } ;
349+ }
350+
351+ const parentDir = dest . substring ( 0 , dest . lastIndexOf ( "/" ) ) || "/" ;
352+ const dirName = dest . substring ( dest . lastIndexOf ( "/" ) + 1 ) ;
353+
354+ const cloneResult = await gitRunner . clone ( url , dirName , {
355+ cwd : parentDir ,
356+ } ) ;
357+ if ( ! cloneResult . ok ) {
358+ return {
359+ success : false ,
360+ error : `Clone failed: ${ cloneResult . error } ` ,
361+ } ;
362+ }
363+
364+ const installResult = await npmRunner . install ( { cwd : dest } ) ;
365+ if ( ! installResult . ok ) {
366+ return {
367+ success : false ,
368+ error : `npm install failed: ${ installResult . error } ` ,
369+ } ;
370+ }
371+
372+ this . plugin . settings . quartzRepoPath = dest ;
373+ this . plugin . settings . enableSystemCommands = true ;
374+ await this . plugin . saveSettings ( ) ;
375+
376+ return { success : true , data : { path : dest } } ;
377+ }
378+
266379 private selectPublicationPaths ( paths : string [ ] ) : ActionResult {
267380 const controller = this . getPublicationCenterController ( ) ;
268381 if ( ! controller ) {
269- return { success : false , error : "Publication center unavailable" } ;
382+ return { success : false , error : "Publication Center unavailable" } ;
270383 }
271384 controller . setSelected ( paths ) ;
272385 return { success : true } ;
@@ -275,7 +388,7 @@ export class ActionRegistry {
275388 private deselectPublicationPaths ( paths : string [ ] ) : ActionResult {
276389 const controller = this . getPublicationCenterController ( ) ;
277390 if ( ! controller ) {
278- return { success : false , error : "Publication center unavailable" } ;
391+ return { success : false , error : "Publication Center unavailable" } ;
279392 }
280393 const remaining = new Set ( controller . getSelected ( ) ) ;
281394 for ( const path of paths ) {
@@ -288,7 +401,7 @@ export class ActionRegistry {
288401 private selectAllPublicationPaths ( ) : ActionResult {
289402 const controller = this . getPublicationCenterController ( ) ;
290403 if ( ! controller ) {
291- return { success : false , error : "Publication center unavailable" } ;
404+ return { success : false , error : "Publication Center unavailable" } ;
292405 }
293406 controller . selectAll ( ) ;
294407 return { success : true } ;
@@ -297,7 +410,7 @@ export class ActionRegistry {
297410 private deselectAllPublicationPaths ( ) : ActionResult {
298411 const controller = this . getPublicationCenterController ( ) ;
299412 if ( ! controller ) {
300- return { success : false , error : "Publication center unavailable" } ;
413+ return { success : false , error : "Publication Center unavailable" } ;
301414 }
302415 controller . deselectAll ( ) ;
303416 return { success : true } ;
0 commit comments