native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(cli): align list runtime with latest state + stabilize tests

onevclaw 1010d424 40f0f89d

+44 -32
+23 -15
supacode/App/supacodeApp.swift
··· 176 176 } 177 177 _store = State(initialValue: appStore) 178 178 179 - let listHandler = ListCommandHandler { 180 - ListRuntimeSnapshotBuilder.makeSnapshot( 181 - repositoriesState: appStore.state.repositories, 182 - terminalManager: terminalManager 183 - ) 184 - } 185 - let cliRouter = CLICommandRouter(listHandler: listHandler) 186 - let cliServer = CLISocketServer(router: cliRouter) 187 - let cliLogger = SupaLogger("CLIService") 188 - do { 189 - try cliServer.start() 190 - cliLogger.info("CLI socket server started at \(ProwlSocket.defaultPath)") 191 - } catch { 192 - cliLogger.warning("Failed to start CLI socket server: \(String(describing: error))") 193 - } 179 + let cliServer = Self.makeCLISocketServer(appStore: appStore, terminalManager: terminalManager) 194 180 _cliSocketServer = State(initialValue: cliServer) 195 181 196 182 runtime.onQuit = { [weak appStore] in ··· 204 190 ghosttyShortcuts: shortcuts, 205 191 commandKeyObserver: keyObserver 206 192 ) 193 + } 194 + 195 + private static func makeCLISocketServer( 196 + appStore: StoreOf<AppFeature>, 197 + terminalManager: WorktreeTerminalManager 198 + ) -> CLISocketServer { 199 + let listHandler = ListCommandHandler { 200 + ListRuntimeSnapshotBuilder.makeSnapshot( 201 + repositoriesState: appStore.state.repositories, 202 + terminalManager: terminalManager 203 + ) 204 + } 205 + let cliRouter = CLICommandRouter(listHandler: listHandler) 206 + let cliServer = CLISocketServer(router: cliRouter) 207 + let logger = SupaLogger("CLIService") 208 + do { 209 + try cliServer.start() 210 + logger.info("CLI socket server started at \(ProwlSocket.defaultPath)") 211 + } catch { 212 + logger.warning("Failed to start CLI socket server: \(String(describing: error))") 213 + } 214 + return cliServer 207 215 } 208 216 209 217 var body: some Scene {
+7 -4
supacode/CLIService/ListCommandHandler.swift
··· 38 38 self.snapshotProvider = snapshotProvider 39 39 } 40 40 41 + // swiftlint:disable:next async_without_await 41 42 func handle(envelope _: CommandEnvelope) async -> CommandResponse { 42 43 do { 43 44 let snapshot = try snapshotProvider() ··· 49 50 data: RawJSON(encoding: payload) 50 51 ) 51 52 } catch { 52 - return CommandResponse.error( 53 + return CommandResponse( 54 + ok: false, 53 55 command: "list", 54 56 schemaVersion: "prowl.cli.list.v1", 55 - code: .listFailed, 56 - message: "Failed to list panes.", 57 - details: nil 57 + error: CommandError( 58 + code: CLIErrorCode.listFailed, 59 + message: "Failed to list panes." 60 + ) 58 61 ) 59 62 } 60 63 }
+7 -6
supacode/CLIService/ListRuntimeSnapshotBuilder.swift
··· 21 21 let orderedContexts = orderedWorktreeContexts(from: repositoriesState) 22 22 let focusedWorktreeID = terminalManager.selectedWorktreeID ?? terminalManager.canvasFocusedWorktreeID 23 23 24 - let worktrees = orderedContexts.compactMap { context in 24 + let worktrees: [ListRuntimeSnapshot.Worktree] = orderedContexts.compactMap { context in 25 25 guard let terminalSnapshot = activeSnapshots[context.id] else { 26 26 return nil 27 27 } 28 28 29 - let tabs = terminalSnapshot.tabs.compactMap { tabSnapshot in 29 + let tabs: [ListRuntimeSnapshot.Tab] = terminalSnapshot.tabs.compactMap { tabSnapshot in 30 30 let panes = tabSnapshot.panes.map { paneSnapshot in 31 31 ListRuntimeSnapshot.Pane( 32 32 id: paneSnapshot.id, ··· 68 68 69 69 private static func orderedWorktreeContexts(from repositoriesState: RepositoriesFeature.State) -> [WorktreeContext] { 70 70 var contexts: [WorktreeContext] = [] 71 + let repositoriesByID = Dictionary(uniqueKeysWithValues: repositoriesState.repositories.map { ($0.id, $0) }) 71 72 72 - for repositoryID in repositoriesState.orderedRepositoryIDs { 73 - guard let repository = repositoriesState.repositoriesByID[repositoryID] else { 73 + for repositoryID in repositoriesState.orderedRepositoryIDs() { 74 + guard let repository = repositoriesByID[repositoryID] else { 74 75 continue 75 76 } 76 77 ··· 82 83 name: worktree.name, 83 84 path: worktree.workingDirectory.path(percentEncoded: false), 84 85 rootPath: worktree.repositoryRootURL.path(percentEncoded: false), 85 - kind: repository.kind == .git ? .git : .plain 86 + kind: repository.kind == .git ? ListCommandWorktree.Kind.git : .plain 86 87 ) 87 88 ) 88 89 } ··· 97 98 name: repository.name, 98 99 path: rootPath, 99 100 rootPath: rootPath, 100 - kind: repository.kind == .git ? .git : .plain 101 + kind: repository.kind == .git ? ListCommandWorktree.Kind.git : .plain 101 102 ) 102 103 ) 103 104 }
+2 -2
supacode/Features/Terminal/Models/WorktreeTerminalState.swift
··· 1478 1478 } 1479 1479 1480 1480 return CLITerminalTabSnapshot( 1481 - id: tab.id, 1481 + id: tab.id.rawValue, 1482 1482 title: tab.title, 1483 1483 selected: tab.id == selectedTabID, 1484 1484 focusedPaneID: focusedSurfaceIdByTab[tab.id], ··· 1488 1488 1489 1489 return CLIWorktreeTerminalSnapshot( 1490 1490 tabs: tabs, 1491 - taskStatus: taskStatus.map { $0 == .running ? .running : .idle } 1491 + taskStatus: taskStatus == .running ? .running : .idle 1492 1492 ) 1493 1493 } 1494 1494
+4 -4
supacodeTests/CLIListCommandHandlerTests.swift
··· 35 35 cwd: "/Users/onevcat/Projects/Prowl" 36 36 ), 37 37 ] 38 - ) 38 + ), 39 39 ] 40 40 ), 41 41 .init( ··· 56 56 id: UUID(uuidString: "EF65FF31-1B72-40B2-80DA-3AA87B7B6858")!, 57 57 title: "notes", 58 58 cwd: "/Users/onevcat/Projects/Notes" 59 - ) 59 + ), 60 60 ] 61 - ) 61 + ), 62 62 ] 63 63 ), 64 64 ], ··· 74 74 #expect(response.command == "list") 75 75 #expect(response.schemaVersion == "prowl.cli.list.v1") 76 76 77 - let payload = try #require(response.data?.decode(as: ListCommandPayload.self)) 77 + let payload = try #require(try response.data?.decode(as: ListCommandPayload.self)) 78 78 #expect(payload.count == 3) 79 79 #expect(payload.items.count == 3) 80 80
+1 -1
supacodeTests/GitAutomaticBaseRefIntegrationTests.swift
··· 51 51 private func runGit(_ arguments: [String]) throws -> String { 52 52 let process = Process() 53 53 process.executableURL = URL(fileURLWithPath: "/usr/bin/git") 54 - process.arguments = arguments 54 + process.arguments = ["-c", "core.hooksPath=/dev/null"] + arguments 55 55 let pipe = Pipe() 56 56 process.standardOutput = pipe 57 57 process.standardError = pipe