@@ -32,6 +32,23 @@ struct ErrorResponse: Codable {
3232 let error : String
3333}
3434
35+ struct WorkstreamResponse : Codable {
36+ let id : String
37+ let name : String
38+ let theme : String
39+ let directory : String ?
40+ let hasCommand : Bool
41+ }
42+
43+ struct WorkstreamsResponse : Codable {
44+ let workstreams : [ WorkstreamResponse ]
45+ }
46+
47+ struct WorkstreamLaunchResponse : Codable {
48+ let name : String
49+ let theme : String
50+ }
51+
3552// MARK: - API Server
3653
3754class APIServer {
@@ -47,6 +64,9 @@ class APIServer {
4764 var windowDataProvider : ( ( ) -> [ GhosttyWindow ] ) ?
4865 var focusWindowHandler : ( ( Int , pid_t ) -> Void ) ?
4966 var launchRandomHandler : ( ( ) -> ( theme: String , windowName: String ) ? ) ?
67+ var workstreamsProvider : ( ( ) -> [ WorkstreamResponse ] ) ?
68+ var launchWorkstreamHandler : ( ( String ) -> ( name: String , theme: String ) ? ) ?
69+ var openQuickLaunchHandler : ( ( ) -> Void ) ?
5070
5171 private init ( ) { }
5272
@@ -180,6 +200,16 @@ class APIServer {
180200 case ( " POST " , " /api/launch-random " ) :
181201 handleLaunchRandom ( connection)
182202
203+ case ( " GET " , " /api/workstreams " ) :
204+ handleGetWorkstreams ( connection)
205+
206+ case ( " POST " , " /api/quick-launch " ) :
207+ handleOpenQuickLaunch ( connection)
208+
209+ case ( " POST " , _) where path. hasPrefix ( " /api/workstreams/ " ) && path. hasSuffix ( " /launch " ) :
210+ let workstreamId = extractWorkstreamId ( from: path)
211+ handleLaunchWorkstream ( connection, workstreamId: workstreamId)
212+
183213 case ( " POST " , _) where path. hasPrefix ( " /api/windows/ " ) && path. hasSuffix ( " /focus " ) :
184214 let windowId = extractWindowId ( from: path)
185215 handleFocusWindow ( connection, windowId: windowId)
@@ -202,6 +232,15 @@ class APIServer {
202232 return " "
203233 }
204234
235+ private func extractWorkstreamId( from path: String ) -> String {
236+ // /api/workstreams/{id}/launch -> extract {id}
237+ let components = path. components ( separatedBy: " / " )
238+ if components. count >= 4 {
239+ return components [ 3 ]
240+ }
241+ return " "
242+ }
243+
205244 private func handleHealth( _ connection: NWConnection ) {
206245 let response = HealthResponse ( status: " ok " , version: " 1.0.0 " )
207246 sendResponse ( connection, status: 200 , body: response)
@@ -274,6 +313,42 @@ class APIServer {
274313 sendResponse ( connection, status: 200 , body: response)
275314 }
276315
316+ private func handleGetWorkstreams( _ connection: NWConnection ) {
317+ guard let provider = workstreamsProvider else {
318+ sendResponse ( connection, status: 503 , body: ErrorResponse ( error: " Workstreams not available " ) )
319+ return
320+ }
321+
322+ let workstreams = provider ( )
323+ let response = WorkstreamsResponse ( workstreams: workstreams)
324+ sendResponse ( connection, status: 200 , body: response)
325+ }
326+
327+ private func handleLaunchWorkstream( _ connection: NWConnection , workstreamId: String ) {
328+ guard let handler = launchWorkstreamHandler else {
329+ sendResponse ( connection, status: 503 , body: ErrorResponse ( error: " Workstream launch handler not available " ) )
330+ return
331+ }
332+
333+ guard let result = handler ( workstreamId) else {
334+ sendResponse ( connection, status: 404 , body: ErrorResponse ( error: " Workstream not found " ) )
335+ return
336+ }
337+
338+ let response = WorkstreamLaunchResponse ( name: result. name, theme: result. theme)
339+ sendResponse ( connection, status: 200 , body: response)
340+ }
341+
342+ private func handleOpenQuickLaunch( _ connection: NWConnection ) {
343+ guard let handler = openQuickLaunchHandler else {
344+ sendResponse ( connection, status: 503 , body: ErrorResponse ( error: " Quick launch handler not available " ) )
345+ return
346+ }
347+
348+ handler ( )
349+ sendResponse ( connection, status: 200 , body: [ " success " : true ] )
350+ }
351+
277352 private func sendResponse< T: Encodable > ( _ connection: NWConnection , status: Int , body: T ) {
278353 let encoder = JSONEncoder ( )
279354 encoder. outputFormatting = . prettyPrinted
0 commit comments