native macOS codings agent orchestrator
6
fork

Configure Feed

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

format

khoi 2b9c9bab b668f0d1

+353 -303
+26 -26
supacode/App/supacodeApp.swift
··· 5 5 // Created by khoi on 20/1/26. 6 6 // 7 7 8 + import ComposableArchitecture 8 9 import Foundation 9 10 import GhosttyKit 10 - import SwiftUI 11 - import ComposableArchitecture 12 11 import Sentry 12 + import SwiftUI 13 13 14 14 private enum GhosttyCLI { 15 15 static let argv: [UnsafeMutablePointer<CChar>?] = { ··· 36 36 37 37 @MainActor init() { 38 38 #if !DEBUG 39 - SentrySDK.start { options in 40 - options.dsn = "https://fb4d394e0bd3e72871b01c7ef3cac129@o1224589.ingest.us.sentry.io/4510770231050240" 41 - options.tracesSampleRate = 1.0 42 - } 39 + SentrySDK.start { options in 40 + options.dsn = "https://fb4d394e0bd3e72871b01c7ef3cac129@o1224589.ingest.us.sentry.io/4510770231050240" 41 + options.tracesSampleRate = 1.0 42 + } 43 43 #endif 44 44 if let resourceURL = Bundle.main.resourceURL?.appendingPathComponent("ghostty") { 45 45 setenv("GHOSTTY_RESOURCES_DIR", resourceURL.path, 1) ··· 65 65 let appStore = Store( 66 66 initialState: AppFeature.State(settings: SettingsFeature.State(settings: initialSettings)) 67 67 ) { 68 - AppFeature() 69 - .logActions() 70 - } withDependencies: { values in 71 - values.terminalClient = TerminalClient( 72 - send: { command in 73 - terminalManager.handleCommand(command) 74 - }, 75 - events: { 76 - terminalManager.eventStream() 77 - } 78 - ) 79 - values.worktreeInfoWatcher = WorktreeInfoWatcherClient( 80 - send: { command in 81 - worktreeInfoWatcher.handleCommand(command) 82 - }, 83 - events: { 84 - worktreeInfoWatcher.eventStream() 85 - } 86 - ) 87 - } 68 + AppFeature() 69 + .logActions() 70 + } withDependencies: { values in 71 + values.terminalClient = TerminalClient( 72 + send: { command in 73 + terminalManager.handleCommand(command) 74 + }, 75 + events: { 76 + terminalManager.eventStream() 77 + } 78 + ) 79 + values.worktreeInfoWatcher = WorktreeInfoWatcherClient( 80 + send: { command in 81 + worktreeInfoWatcher.handleCommand(command) 82 + }, 83 + events: { 84 + worktreeInfoWatcher.eventStream() 85 + } 86 + ) 87 + } 88 88 _store = State(initialValue: appStore) 89 89 SettingsWindowManager.shared.configure( 90 90 store: appStore,
+11 -10
supacode/Clients/Git/GitClient.swift
··· 201 201 guard let headURL else { 202 202 return nil 203 203 } 204 - guard let line = try? String(contentsOf: headURL, encoding: .utf8) 205 - .split(whereSeparator: \.isNewline) 206 - .first 204 + guard 205 + let line = try? String(contentsOf: headURL, encoding: .utf8) 206 + .split(whereSeparator: \.isNewline) 207 + .first 207 208 else { 208 209 return nil 209 210 } ··· 377 378 gitError = .commandFailed(command: command, message: error.localizedDescription) 378 379 } 379 380 #if !DEBUG 380 - SentrySDK.logger.error( 381 - "git command failed", 382 - attributes: [ 383 - "operation": operation.rawValue, 384 - "exit_code": Int(exitCode), 385 - ] 386 - ) 381 + SentrySDK.logger.error( 382 + "git command failed", 383 + attributes: [ 384 + "operation": operation.rawValue, 385 + "exit_code": Int(exitCode), 386 + ] 387 + ) 387 388 #endif 388 389 return gitError 389 390 }
+15 -14
supacode/Clients/Github/GithubCLIClient.swift
··· 57 57 arguments: ["repo", "view", "--json", "defaultBranchRef"], 58 58 repoRoot: repoRoot 59 59 ) 60 - let data = Data(output.utf8) 61 - let decoder = JSONDecoder() 62 - decoder.dateDecodingStrategy = .iso8601 63 - let response = try decoder.decode(GithubRepoViewResponse.self, from: data) 64 - return response.defaultBranchRef.name 60 + let data = Data(output.utf8) 61 + let decoder = JSONDecoder() 62 + decoder.dateDecodingStrategy = .iso8601 63 + let response = try decoder.decode(GithubRepoViewResponse.self, from: data) 64 + return response.defaultBranchRef.name 65 65 }, 66 66 latestRun: { repoRoot, branch in 67 67 let output = try await runGh( ··· 78 78 ], 79 79 repoRoot: repoRoot 80 80 ) 81 - if output.isEmpty { 82 - return nil 83 - } 84 - let data = Data(output.utf8) 85 - let decoder = JSONDecoder() 86 - decoder.dateDecodingStrategy = .iso8601 87 - let runs = try decoder.decode([GithubWorkflowRun].self, from: data) 88 - return runs.first 81 + if output.isEmpty { 82 + return nil 83 + } 84 + let data = Data(output.utf8) 85 + let decoder = JSONDecoder() 86 + decoder.dateDecodingStrategy = .iso8601 87 + let runs = try decoder.decode([GithubWorkflowRun].self, from: data) 88 + return runs.first 89 89 }, 90 90 currentPullRequest: { worktreeRoot in 91 91 let baseFields = [ ··· 157 157 let data = Data(output.utf8) 158 158 let response = try decodeAuthStatusResponse(from: data) 159 159 guard let (host, accounts) = response.hosts.first, 160 - let activeAccount = accounts.first(where: { $0.active }) else { 160 + let activeAccount = accounts.first(where: { $0.active }) 161 + else { 161 162 return nil 162 163 } 163 164 return GithubAuthStatus(username: activeAccount.login, host: host)
+1 -1
supacode/Clients/Updates/UpdaterClient.swift
··· 32 32 33 33 static let testValue = UpdaterClient( 34 34 configure: { _, _, _ in }, 35 - checkForUpdates: { } 35 + checkForUpdates: {} 36 36 ) 37 37 } 38 38
+6 -5
supacode/Clients/Workspace/WorkspaceClient.swift
··· 2 2 import ComposableArchitecture 3 3 4 4 struct WorkspaceClient { 5 - var open: @MainActor @Sendable ( 6 - _ action: OpenWorktreeAction, 7 - _ worktree: Worktree, 8 - _ onError: @escaping @MainActor (OpenActionError) -> Void 9 - ) -> Void 5 + var open: 6 + @MainActor @Sendable ( 7 + _ action: OpenWorktreeAction, 8 + _ worktree: Worktree, 9 + _ onError: @escaping @MainActor (OpenActionError) -> Void 10 + ) -> Void 10 11 } 11 12 12 13 extension WorkspaceClient: DependencyKey {
+5 -5
supacode/Features/App/Reducer/AppFeature.swift
··· 137 137 let worktrees = repositories.flatMap(\.worktrees) 138 138 state.runScriptStatusByWorktreeID = state.runScriptStatusByWorktreeID.filter { ids.contains($0.key) } 139 139 if case .repository(let repositoryID) = state.settings.selection, 140 - !repositories.contains(where: { $0.id == repositoryID }) 140 + !repositories.contains(where: { $0.id == repositoryID }) 141 141 { 142 142 return .merge( 143 143 .send(.settings(.setSelection(.general))), ··· 340 340 341 341 case .settings(.repositorySettings(.delegate(.settingsChanged(let rootURL)))): 342 342 guard let selectedWorktree = state.repositories.worktree(for: state.repositories.selectedWorktreeID), 343 - selectedWorktree.repositoryRootURL == rootURL 343 + selectedWorktree.repositoryRootURL == rootURL 344 344 else { 345 345 return .none 346 346 } ··· 419 419 func reduce(into state: inout Base.State, action: Base.Action) -> Effect<Base.Action> { 420 420 let actionLabel = debugCaseOutput(action) 421 421 #if !DEBUG 422 - SentrySDK.logger.info("received action: \(actionLabel)") 422 + SentrySDK.logger.info("received action: \(actionLabel)") 423 423 #endif 424 424 return base.reduce(into: &state, action: action) 425 425 } 426 426 } 427 427 428 - private extension Reducer { 429 - func printActionLabels() -> ActionLabelReducer<Self> { 428 + extension Reducer { 429 + fileprivate func printActionLabels() -> ActionLabelReducer<Self> { 430 430 ActionLabelReducer(base: self) 431 431 } 432 432 }
+7 -5
supacode/Features/Repositories/BusinessLogic/WorktreeInfoWatcherManager.swift
··· 1 + import Darwin 1 2 import Dispatch 2 3 import Foundation 3 - import Darwin 4 4 5 5 @MainActor 6 6 final class WorktreeInfoWatcherManager { ··· 80 80 } 81 81 82 82 private func configureWatcher(for worktree: Worktree) { 83 - guard let headURL = GitWorktreeHeadResolver.headURL( 84 - for: worktree.workingDirectory, 85 - fileManager: .default 86 - ) else { 83 + guard 84 + let headURL = GitWorktreeHeadResolver.headURL( 85 + for: worktree.workingDirectory, 86 + fileManager: .default 87 + ) 88 + else { 87 89 stopWatcher(for: worktree.id) 88 90 return 89 91 }
+18 -14
supacode/Features/Repositories/Reducer/RepositoriesFeature.swift
··· 176 176 } 177 177 if didPrunePinned { 178 178 let pinnedWorktreeIDs = state.pinnedWorktreeIDs 179 - allEffects.append(.run { _ in 180 - await repositoryPersistence.savePinnedWorktreeIDs(pinnedWorktreeIDs) 181 - }) 179 + allEffects.append( 180 + .run { _ in 181 + await repositoryPersistence.savePinnedWorktreeIDs(pinnedWorktreeIDs) 182 + }) 182 183 } 183 184 return .merge(allEffects) 184 185 ··· 237 238 } else { 238 239 let errors = failures.map(\.message) 239 240 if !errors.isEmpty { 240 - state.alert = errorAlert( 241 - title: errors.count == 1 ? "Failed to load repository" : "Failed to load repositories", 242 - message: errors.joined(separator: "\n") 243 - ) 241 + state.alert = errorAlert( 242 + title: errors.count == 1 ? "Failed to load repository" : "Failed to load repositories", 243 + message: errors.joined(separator: "\n") 244 + ) 244 245 } 245 246 } 246 247 let selectionChanged = previousSelection != state.selectedWorktreeID ··· 253 254 } 254 255 if didPrunePinned { 255 256 let pinnedWorktreeIDs = state.pinnedWorktreeIDs 256 - allEffects.append(.run { _ in 257 - await repositoryPersistence.savePinnedWorktreeIDs(pinnedWorktreeIDs) 258 - }) 257 + allEffects.append( 258 + .run { _ in 259 + await repositoryPersistence.savePinnedWorktreeIDs(pinnedWorktreeIDs) 260 + }) 259 261 } 260 262 return .merge(allEffects) 261 263 ··· 495 497 state.alert = nil 496 498 state.deletingWorktreeIDs.insert(worktree.id) 497 499 let selectionWasRemoved = state.selectedWorktreeID == worktree.id 498 - let nextSelection = selectionWasRemoved 500 + let nextSelection = 501 + selectionWasRemoved 499 502 ? nextWorktreeID(afterRemoving: worktree, in: repository, state: state) 500 503 : nil 501 504 return .run { send in ··· 551 554 } 552 555 state.alert = nil 553 556 state.removingRepositoryIDs.insert(repository.id) 554 - let selectionWasRemoved = state.selectedWorktreeID.map { id in 555 - repository.worktrees.contains(where: { $0.id == id }) 556 - } ?? false 557 + let selectionWasRemoved = 558 + state.selectedWorktreeID.map { id in 559 + repository.worktrees.contains(where: { $0.id == id }) 560 + } ?? false 557 561 return .send(.repositoryRemoved(repository.id, selectionWasRemoved: selectionWasRemoved)) 558 562 559 563 case .repositoryRemoved(let repositoryID, let selectionWasRemoved):
+62 -47
supacode/Features/Repositories/Views/WorktreeDetailView.swift
··· 18 18 let hasActiveWorktree = selectedWorktree != nil && loadingInfo == nil 19 19 let worktreeInfoSnapshot = state.worktreeInfo.snapshot 20 20 let openActionSelection = state.openActionSelection 21 - let openSelectedWorktreeAction: (() -> Void)? = hasActiveWorktree 21 + let openSelectedWorktreeAction: (() -> Void)? = 22 + hasActiveWorktree 22 23 ? { store.send(.openSelectedWorktree) } 23 24 : nil 24 - let newTerminalAction: (() -> Void)? = hasActiveWorktree 25 + let newTerminalAction: (() -> Void)? = 26 + hasActiveWorktree 25 27 ? { store.send(.newTerminal) } 26 28 : nil 27 - let closeTabAction: (() -> Void)? = hasActiveWorktree 29 + let closeTabAction: (() -> Void)? = 30 + hasActiveWorktree 28 31 ? { store.send(.closeTab) } 29 32 : nil 30 - let closeSurfaceAction: (() -> Void)? = hasActiveWorktree 33 + let closeSurfaceAction: (() -> Void)? = 34 + hasActiveWorktree 31 35 ? { store.send(.closeSurface) } 32 36 : nil 33 - let startSearchAction: (() -> Void)? = hasActiveWorktree 37 + let startSearchAction: (() -> Void)? = 38 + hasActiveWorktree 34 39 ? { store.send(.startSearch) } 35 40 : nil 36 - let searchSelectionAction: (() -> Void)? = hasActiveWorktree 41 + let searchSelectionAction: (() -> Void)? = 42 + hasActiveWorktree 37 43 ? { store.send(.searchSelection) } 38 44 : nil 39 - let navigateSearchNextAction: (() -> Void)? = hasActiveWorktree 45 + let navigateSearchNextAction: (() -> Void)? = 46 + hasActiveWorktree 40 47 ? { store.send(.navigateSearchNext) } 41 48 : nil 42 - let navigateSearchPreviousAction: (() -> Void)? = hasActiveWorktree 49 + let navigateSearchPreviousAction: (() -> Void)? = 50 + hasActiveWorktree 43 51 ? { store.send(.navigateSearchPrevious) } 44 52 : nil 45 - let endSearchAction: (() -> Void)? = hasActiveWorktree 53 + let endSearchAction: (() -> Void)? = 54 + hasActiveWorktree 46 55 ? { store.send(.endSearch) } 47 56 : nil 48 - let runScriptEnabled = hasActiveWorktree 57 + let runScriptEnabled = 58 + hasActiveWorktree 49 59 && !state.selectedRunScript.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty 50 60 let runScriptIsRunning = selectedWorktree.flatMap { state.runScriptStatusByWorktreeID[$0.id] } == true 51 61 let runScriptAction: (() -> Void)? = runScriptEnabled ? { store.send(.runScript) } : nil 52 62 let stopRunScriptAction: (() -> Void)? = runScriptIsRunning ? { store.send(.stopRunScript) } : nil 53 - let navigationTitle = hasActiveWorktree 63 + let navigationTitle = 64 + hasActiveWorktree 54 65 ? "" 55 66 : (selectedWorktree?.name ?? loadingInfo?.name ?? "Supacode") 56 67 let content = Group { ··· 199 210 ) 200 211 } 201 212 ToolbarItem(placement: .principal) { 202 - HStack { 203 - if let model = PullRequestStatusModel(snapshot: toolbarState.worktreeInfoSnapshot) { 204 - PullRequestStatusButton(model: model).padding(.horizontal) 205 - } else { 206 - XcodeStyleStatusView().padding(.horizontal) 207 - } 208 - Divider() 209 - RunScriptToolbarButton( 210 - isRunning: toolbarState.runScriptIsRunning, 211 - isEnabled: toolbarState.runScriptEnabled, 212 - runHelpText: toolbarState.runScriptHelpText, 213 - stopHelpText: toolbarState.stopRunScriptHelpText, 214 - runShortcut: AppShortcuts.runScript.display, 215 - stopShortcut: AppShortcuts.stopRunScript.display, 216 - runAction: { store.send(.runScript) }, 217 - stopAction: { store.send(.stopRunScript) } 218 - ) 213 + HStack { 214 + if let model = PullRequestStatusModel(snapshot: toolbarState.worktreeInfoSnapshot) { 215 + PullRequestStatusButton(model: model).padding(.horizontal) 216 + } else { 217 + XcodeStyleStatusView().padding(.horizontal) 219 218 } 219 + Divider() 220 + RunScriptToolbarButton( 221 + isRunning: toolbarState.runScriptIsRunning, 222 + isEnabled: toolbarState.runScriptEnabled, 223 + runHelpText: toolbarState.runScriptHelpText, 224 + stopHelpText: toolbarState.stopRunScriptHelpText, 225 + runShortcut: AppShortcuts.runScript.display, 226 + stopShortcut: AppShortcuts.stopRunScript.display, 227 + runAction: { store.send(.runScript) }, 228 + stopAction: { store.send(.stopRunScript) } 229 + ) 230 + } 220 231 } 221 - 232 + 222 233 ToolbarItem(placement: .automatic) { 223 234 openMenu( 224 235 openActionSelection: toolbarState.openActionSelection, ··· 294 305 295 306 var body: some View { 296 307 if isRunning { 297 - button(config: RunScriptButtonConfig( 298 - title: "Stop", 299 - systemImage: "stop.fill", 300 - helpText: stopHelpText, 301 - shortcut: stopShortcut, 302 - isEnabled: true, 303 - action: stopAction 304 - )) 308 + button( 309 + config: RunScriptButtonConfig( 310 + title: "Stop", 311 + systemImage: "stop.fill", 312 + helpText: stopHelpText, 313 + shortcut: stopShortcut, 314 + isEnabled: true, 315 + action: stopAction 316 + )) 305 317 } else { 306 - button(config: RunScriptButtonConfig( 307 - title: "Run", 308 - systemImage: "play.fill", 309 - helpText: runHelpText, 310 - shortcut: runShortcut, 311 - isEnabled: isEnabled, 312 - action: runAction 313 - )) 318 + button( 319 + config: RunScriptButtonConfig( 320 + title: "Run", 321 + systemImage: "play.fill", 322 + helpText: runHelpText, 323 + shortcut: runShortcut, 324 + isEnabled: isEnabled, 325 + action: runAction 326 + )) 314 327 } 315 328 } 316 329 ··· 402 415 let availableActions = OpenWorktreeAction.availableCases 403 416 let resolvedOpenActionSelection = OpenWorktreeAction.availableSelection(openActionSelection) 404 417 HStack(spacing: 0) { 405 - Button {} label: { 418 + Button { 419 + } label: { 406 420 OpenWorktreeActionMenuLabelView( 407 421 action: resolvedOpenActionSelection, 408 422 shortcutHint: showExtras ? AppShortcuts.openFinder.display : nil ··· 416 430 417 431 Menu { 418 432 ForEach(availableActions) { action in 419 - Button {} label: { 433 + Button { 434 + } label: { 420 435 OpenWorktreeActionMenuLabelView(action: action, shortcutHint: nil) 421 436 } 422 437 .buttonStyle(.plain)
+6 -5
supacode/Features/Repositories/Views/WorktreeRow.swift
··· 16 16 let showsSpinner = isLoading || taskStatus == .running 17 17 let branchIconName = isMainWorktree ? "star.fill" : (isPinned ? "pin.fill" : "arrow.triangle.branch") 18 18 let pullRequest = info?.pullRequest 19 - let matchesWorktree = if let pullRequest { 20 - pullRequest.headRefName == nil || pullRequest.headRefName == name 21 - } else { 22 - false 23 - } 19 + let matchesWorktree = 20 + if let pullRequest { 21 + pullRequest.headRefName == nil || pullRequest.headRefName == name 22 + } else { 23 + false 24 + } 24 25 let displayPullRequest = matchesWorktree ? pullRequest : nil 25 26 let displayAddedLines = displayPullRequest?.additions ?? info?.addedLines 26 27 let displayRemovedLines = displayPullRequest?.deletions ?? info?.removedLines
-5
supacode/Features/RepositorySettings/Reducer/RepositorySettingsFeature.swift
··· 7 7 struct State: Equatable { 8 8 var rootURL: URL 9 9 var settings: RepositorySettings 10 - 11 - init(rootURL: URL, settings: RepositorySettings) { 12 - self.rootURL = rootURL 13 - self.settings = settings 14 - } 15 10 } 16 11 17 12 enum Action: Equatable {
+16 -11
supacode/Features/Settings/Models/RepositorySettings.swift
··· 39 39 40 40 init(from decoder: Decoder) throws { 41 41 let container = try decoder.container(keyedBy: CodingKeys.self) 42 - setupScript = try container.decodeIfPresent(String.self, forKey: .setupScript) 42 + setupScript = 43 + try container.decodeIfPresent(String.self, forKey: .setupScript) 43 44 ?? Self.default.setupScript 44 - runScript = try container.decodeIfPresent(String.self, forKey: .runScript) 45 + runScript = 46 + try container.decodeIfPresent(String.self, forKey: .runScript) 45 47 ?? Self.default.runScript 46 - openActionID = try container.decodeIfPresent(String.self, forKey: .openActionID) 48 + openActionID = 49 + try container.decodeIfPresent(String.self, forKey: .openActionID) 47 50 ?? Self.default.openActionID 48 - copyIgnoredOnWorktreeCreate = try container.decodeIfPresent( 49 - Bool.self, 50 - forKey: .copyIgnoredOnWorktreeCreate 51 - ) ?? Self.default.copyIgnoredOnWorktreeCreate 52 - copyUntrackedOnWorktreeCreate = try container.decodeIfPresent( 53 - Bool.self, 54 - forKey: .copyUntrackedOnWorktreeCreate 55 - ) ?? Self.default.copyUntrackedOnWorktreeCreate 51 + copyIgnoredOnWorktreeCreate = 52 + try container.decodeIfPresent( 53 + Bool.self, 54 + forKey: .copyIgnoredOnWorktreeCreate 55 + ) ?? Self.default.copyIgnoredOnWorktreeCreate 56 + copyUntrackedOnWorktreeCreate = 57 + try container.decodeIfPresent( 58 + Bool.self, 59 + forKey: .copyUntrackedOnWorktreeCreate 60 + ) ?? Self.default.copyUntrackedOnWorktreeCreate 56 61 } 57 62 }
+2 -2
supacode/Features/Settings/Views/SettingsView.swift
··· 1 1 import ComposableArchitecture 2 2 import SwiftUI 3 3 4 - private extension View { 4 + extension View { 5 5 @ViewBuilder 6 - func removingSidebarToggle() -> some View { 6 + fileprivate func removingSidebarToggle() -> some View { 7 7 if #available(macOS 14.0, *) { 8 8 toolbar(removing: .sidebarToggle) 9 9 } else {
+6 -5
supacode/Features/Terminal/Models/WorktreeTerminalState.swift
··· 486 486 let trimmedTitle = title.trimmingCharacters(in: .whitespacesAndNewlines) 487 487 let trimmedBody = body.trimmingCharacters(in: .whitespacesAndNewlines) 488 488 guard !(trimmedTitle.isEmpty && trimmedBody.isEmpty) else { return } 489 - notifications.append(WorktreeTerminalNotification( 490 - surfaceId: surfaceId, 491 - title: trimmedTitle, 492 - body: trimmedBody 493 - )) 489 + notifications.append( 490 + WorktreeTerminalNotification( 491 + surfaceId: surfaceId, 492 + title: trimmedTitle, 493 + body: trimmedBody 494 + )) 494 495 if !isSelected() { 495 496 hasUnseenNotification = true 496 497 }
+1 -1
supacode/Features/Terminal/TabBar/Views/TerminalTabView.swift
··· 50 50 isDragging: isDragging, 51 51 isHovering: isHovering 52 52 ) 53 - .animation(.easeInOut(duration: TerminalTabBarMetrics.hoverAnimationDuration), value: isHovering) 53 + .animation(.easeInOut(duration: TerminalTabBarMetrics.hoverAnimationDuration), value: isHovering) 54 54 } 55 55 .frame( 56 56 minWidth: TerminalTabBarMetrics.tabMinWidth,
+6 -4
supacode/Features/Terminal/TabBar/Views/TerminalTabsRowView.swift
··· 156 156 let adjustedIndex = targetIndex > sourceIndex ? targetIndex - 1 : targetIndex 157 157 let safeIndex = min(max(0, adjustedIndex), newOrder.count) 158 158 newOrder.insert(draggedId, at: safeIndex) 159 - withAnimation(.spring( 160 - duration: TerminalTabBarMetrics.reorderAnimationDuration, 161 - bounce: TerminalTabBarMetrics.reorderAnimationBounce 162 - )) { 159 + withAnimation( 160 + .spring( 161 + duration: TerminalTabBarMetrics.reorderAnimationDuration, 162 + bounce: TerminalTabBarMetrics.reorderAnimationBounce 163 + ) 164 + ) { 163 165 openedTabs = newOrder 164 166 } 165 167 manager.reorderTabs(newOrder)
+13 -11
supacode/Features/Terminal/Views/GhosttySurfaceProgressBar.swift
··· 8 8 @State private var position: CGFloat = 0 9 9 10 10 var body: some View { 11 - let color: Color = switch progressState { 12 - case GHOSTTY_PROGRESS_STATE_ERROR: .red 13 - case GHOSTTY_PROGRESS_STATE_PAUSE: .orange 14 - default: .accentColor 15 - } 11 + let color: Color = 12 + switch progressState { 13 + case GHOSTTY_PROGRESS_STATE_ERROR: .red 14 + case GHOSTTY_PROGRESS_STATE_PAUSE: .orange 15 + default: .accentColor 16 + } 16 17 let progress: Int? = 17 18 progressValue ?? (progressState == GHOSTTY_PROGRESS_STATE_PAUSE ? 100 : nil) 18 - let accessibilityLabel: String = switch progressState { 19 - case GHOSTTY_PROGRESS_STATE_ERROR: "Terminal progress - Error" 20 - case GHOSTTY_PROGRESS_STATE_PAUSE: "Terminal progress - Paused" 21 - case GHOSTTY_PROGRESS_STATE_INDETERMINATE: "Terminal progress - In progress" 22 - default: "Terminal progress" 23 - } 19 + let accessibilityLabel: String = 20 + switch progressState { 21 + case GHOSTTY_PROGRESS_STATE_ERROR: "Terminal progress - Error" 22 + case GHOSTTY_PROGRESS_STATE_PAUSE: "Terminal progress - Paused" 23 + case GHOSTTY_PROGRESS_STATE_INDETERMINATE: "Terminal progress - In progress" 24 + default: "Terminal progress" 25 + } 24 26 let accessibilityValue: String = 25 27 if let progress { 26 28 "\(progress) percent complete"
+1 -1
supacode/Features/Updates/Reducer/UpdatesFeature.swift
··· 20 20 var body: some Reducer<State, Action> { 21 21 Reduce { state, action in 22 22 switch action { 23 - case let .applySettings(checks, downloads): 23 + case .applySettings(let checks, let downloads): 24 24 let checkInBackground = !state.didConfigureUpdates 25 25 state.didConfigureUpdates = true 26 26 return .run { _ in
+6 -5
supacode/Features/WorktreeInfo/Views/WorktreeInfoView.swift
··· 85 85 } 86 86 87 87 LabeledContent("PR state") { 88 - Text(prStateText( 89 - state: snapshot.pullRequestState, 90 - isDraft: snapshot.pullRequestIsDraft, 91 - reviewDecision: snapshot.pullRequestReviewDecision 92 - )) 88 + Text( 89 + prStateText( 90 + state: snapshot.pullRequestState, 91 + isDraft: snapshot.pullRequestIsDraft, 92 + reviewDecision: snapshot.pullRequestReviewDecision 93 + )) 93 94 } 94 95 95 96 if let updatedAt = snapshot.pullRequestUpdatedAt {
+4 -4
supacode/Infrastructure/Ghostty/GhosttyRuntime.swift
··· 319 319 static let ghosttyRuntimeConfigDidChange = Notification.Name("ghosttyRuntimeConfigDidChange") 320 320 } 321 321 322 - private extension NSColor { 323 - var isLightColor: Bool { 322 + extension NSColor { 323 + fileprivate var isLightColor: Bool { 324 324 luminance > 0.5 325 325 } 326 326 327 - var luminance: Double { 327 + fileprivate var luminance: Double { 328 328 var red: CGFloat = 0 329 329 var green: CGFloat = 0 330 330 var blue: CGFloat = 0 ··· 334 334 return (0.299 * red) + (0.587 * green) + (0.114 * blue) 335 335 } 336 336 337 - convenience init(ghostty: ghostty_config_color_s) { 337 + fileprivate convenience init(ghostty: ghostty_config_color_s) { 338 338 let red = Double(ghostty.r) / 255 339 339 let green = Double(ghostty.g) / 255 340 340 let blue = Double(ghostty.b) / 255
+122 -105
supacode/Infrastructure/Ghostty/GhosttySurfaceView.swift
··· 518 518 private func handleControlReturn(_ event: NSEvent) -> Bool { 519 519 guard event.charactersIgnoringModifiers == "\r" else { return false } 520 520 guard event.modifierFlags.contains(.control) else { return false } 521 - guard let finalEvent = NSEvent.keyEvent( 522 - with: .keyDown, 523 - location: event.locationInWindow, 524 - modifierFlags: event.modifierFlags, 525 - timestamp: event.timestamp, 526 - windowNumber: event.windowNumber, 527 - context: nil, 528 - characters: "\r", 529 - charactersIgnoringModifiers: "\r", 530 - isARepeat: event.isARepeat, 531 - keyCode: event.keyCode 532 - ) else { 521 + guard 522 + let finalEvent = NSEvent.keyEvent( 523 + with: .keyDown, 524 + location: event.locationInWindow, 525 + modifierFlags: event.modifierFlags, 526 + timestamp: event.timestamp, 527 + windowNumber: event.windowNumber, 528 + context: nil, 529 + characters: "\r", 530 + charactersIgnoringModifiers: "\r", 531 + isARepeat: event.isARepeat, 532 + keyCode: event.keyCode 533 + ) 534 + else { 533 535 return false 534 536 } 535 537 sendKey(action: GHOSTTY_ACTION_PRESS, event: finalEvent) ··· 540 542 guard event.charactersIgnoringModifiers == "/" else { return false } 541 543 guard event.modifierFlags.contains(.control) else { return false } 542 544 guard event.modifierFlags.isDisjoint(with: [.shift, .command, .option]) else { return false } 543 - guard let finalEvent = NSEvent.keyEvent( 544 - with: .keyDown, 545 - location: event.locationInWindow, 546 - modifierFlags: event.modifierFlags, 547 - timestamp: event.timestamp, 548 - windowNumber: event.windowNumber, 549 - context: nil, 550 - characters: "_", 551 - charactersIgnoringModifiers: "_", 552 - isARepeat: event.isARepeat, 553 - keyCode: event.keyCode 554 - ) else { 545 + guard 546 + let finalEvent = NSEvent.keyEvent( 547 + with: .keyDown, 548 + location: event.locationInWindow, 549 + modifierFlags: event.modifierFlags, 550 + timestamp: event.timestamp, 551 + windowNumber: event.windowNumber, 552 + context: nil, 553 + characters: "_", 554 + charactersIgnoringModifiers: "_", 555 + isARepeat: event.isARepeat, 556 + keyCode: event.keyCode 557 + ) 558 + else { 555 559 return false 556 560 } 557 561 sendKey(action: GHOSTTY_ACTION_PRESS, event: finalEvent) ··· 636 640 } 637 641 menu.addItem(NSMenuItem(title: "Paste", action: #selector(paste(_:)), keyEquivalent: "")) 638 642 menu.addItem(.separator()) 639 - menu.addItem(menuItem( 640 - title: "Split Right", 641 - action: #selector(splitRight(_:)), 642 - symbol: "rectangle.righthalf.inset.filled" 643 - )) 644 - menu.addItem(menuItem( 645 - title: "Split Left", 646 - action: #selector(splitLeft(_:)), 647 - symbol: "rectangle.leadinghalf.inset.filled" 648 - )) 649 - menu.addItem(menuItem( 650 - title: "Split Down", 651 - action: #selector(splitDown(_:)), 652 - symbol: "rectangle.bottomhalf.inset.filled" 653 - )) 654 - menu.addItem(menuItem( 655 - title: "Split Up", 656 - action: #selector(splitUp(_:)), 657 - symbol: "rectangle.tophalf.inset.filled" 658 - )) 643 + menu.addItem( 644 + menuItem( 645 + title: "Split Right", 646 + action: #selector(splitRight(_:)), 647 + symbol: "rectangle.righthalf.inset.filled" 648 + )) 649 + menu.addItem( 650 + menuItem( 651 + title: "Split Left", 652 + action: #selector(splitLeft(_:)), 653 + symbol: "rectangle.leadinghalf.inset.filled" 654 + )) 655 + menu.addItem( 656 + menuItem( 657 + title: "Split Down", 658 + action: #selector(splitDown(_:)), 659 + symbol: "rectangle.bottomhalf.inset.filled" 660 + )) 661 + menu.addItem( 662 + menuItem( 663 + title: "Split Up", 664 + action: #selector(splitUp(_:)), 665 + symbol: "rectangle.tophalf.inset.filled" 666 + )) 659 667 menu.addItem(.separator()) 660 - menu.addItem(menuItem( 661 - title: "Reset Terminal", 662 - action: #selector(resetTerminal(_:)), 663 - symbol: "arrow.trianglehead.2.clockwise" 664 - )) 668 + menu.addItem( 669 + menuItem( 670 + title: "Reset Terminal", 671 + action: #selector(resetTerminal(_:)), 672 + symbol: "arrow.trianglehead.2.clockwise" 673 + )) 665 674 menu.addItem(.separator()) 666 - menu.addItem(menuItem( 667 - title: "Change Title...", 668 - action: #selector(changeTitle(_:)), 669 - symbol: "pencil.line" 670 - )) 675 + menu.addItem( 676 + menuItem( 677 + title: "Change Title...", 678 + action: #selector(changeTitle(_:)), 679 + symbol: "pencil.line" 680 + )) 671 681 return menu 672 682 } 673 683 ··· 1127 1137 refreshAppearance() 1128 1138 1129 1139 scrollView.contentView.postsBoundsChangedNotifications = true 1130 - observers.append(NotificationCenter.default.addObserver( 1131 - forName: NSView.boundsDidChangeNotification, 1132 - object: scrollView.contentView, 1133 - queue: .main 1134 - ) { [weak self] _ in 1135 - self?.handleScrollChange() 1136 - }) 1140 + observers.append( 1141 + NotificationCenter.default.addObserver( 1142 + forName: NSView.boundsDidChangeNotification, 1143 + object: scrollView.contentView, 1144 + queue: .main 1145 + ) { [weak self] _ in 1146 + self?.handleScrollChange() 1147 + }) 1137 1148 1138 - observers.append(NotificationCenter.default.addObserver( 1139 - forName: NSScrollView.willStartLiveScrollNotification, 1140 - object: scrollView, 1141 - queue: .main 1142 - ) { [weak self] _ in 1143 - self?.isLiveScrolling = true 1144 - }) 1149 + observers.append( 1150 + NotificationCenter.default.addObserver( 1151 + forName: NSScrollView.willStartLiveScrollNotification, 1152 + object: scrollView, 1153 + queue: .main 1154 + ) { [weak self] _ in 1155 + self?.isLiveScrolling = true 1156 + }) 1145 1157 1146 - observers.append(NotificationCenter.default.addObserver( 1147 - forName: NSScrollView.didEndLiveScrollNotification, 1148 - object: scrollView, 1149 - queue: .main 1150 - ) { [weak self] _ in 1151 - self?.isLiveScrolling = false 1152 - }) 1158 + observers.append( 1159 + NotificationCenter.default.addObserver( 1160 + forName: NSScrollView.didEndLiveScrollNotification, 1161 + object: scrollView, 1162 + queue: .main 1163 + ) { [weak self] _ in 1164 + self?.isLiveScrolling = false 1165 + }) 1153 1166 1154 - observers.append(NotificationCenter.default.addObserver( 1155 - forName: NSScrollView.didLiveScrollNotification, 1156 - object: scrollView, 1157 - queue: .main 1158 - ) { [weak self] _ in 1159 - self?.handleLiveScroll() 1160 - }) 1167 + observers.append( 1168 + NotificationCenter.default.addObserver( 1169 + forName: NSScrollView.didLiveScrollNotification, 1170 + object: scrollView, 1171 + queue: .main 1172 + ) { [weak self] _ in 1173 + self?.handleLiveScroll() 1174 + }) 1161 1175 1162 - observers.append(NotificationCenter.default.addObserver( 1163 - forName: NSScroller.preferredScrollerStyleDidChangeNotification, 1164 - object: nil, 1165 - queue: nil 1166 - ) { [weak self] _ in 1167 - self?.handleScrollerStyleChange() 1168 - }) 1176 + observers.append( 1177 + NotificationCenter.default.addObserver( 1178 + forName: NSScroller.preferredScrollerStyleDidChangeNotification, 1179 + object: nil, 1180 + queue: nil 1181 + ) { [weak self] _ in 1182 + self?.handleScrollerStyleChange() 1183 + }) 1169 1184 1170 - observers.append(NotificationCenter.default.addObserver( 1171 - forName: .ghosttyRuntimeConfigDidChange, 1172 - object: nil, 1173 - queue: .main 1174 - ) { [weak self] _ in 1175 - self?.refreshAppearance() 1176 - }) 1185 + observers.append( 1186 + NotificationCenter.default.addObserver( 1187 + forName: .ghosttyRuntimeConfigDidChange, 1188 + object: nil, 1189 + queue: .main 1190 + ) { [weak self] _ in 1191 + self?.refreshAppearance() 1192 + }) 1177 1193 } 1178 1194 1179 1195 required init?(coder: NSCoder) { ··· 1271 1287 trackingAreas.forEach { removeTrackingArea($0) } 1272 1288 super.updateTrackingAreas() 1273 1289 guard let scroller = scrollView.verticalScroller else { return } 1274 - addTrackingArea(NSTrackingArea( 1275 - rect: convert(scroller.bounds, from: scroller), 1276 - options: [ 1277 - .mouseMoved, 1278 - .activeInKeyWindow, 1279 - ], 1280 - owner: self, 1281 - userInfo: nil 1282 - )) 1290 + addTrackingArea( 1291 + NSTrackingArea( 1292 + rect: convert(scroller.bounds, from: scroller), 1293 + options: [ 1294 + .mouseMoved, 1295 + .activeInKeyWindow, 1296 + ], 1297 + owner: self, 1298 + userInfo: nil 1299 + )) 1283 1300 } 1284 1301 }
+12 -12
supacode/Support/DebugCaseOutput.swift
··· 1 - import Foundation 2 1 import ComposableArchitecture 3 2 import CustomDump 3 + import Foundation 4 4 import Sentry 5 5 6 6 extension Reducer where State: Equatable { ··· 16 16 func reduce(into state: inout Base.State, action: Base.Action) -> Effect<Base.Action> { 17 17 let actionLabel = debugCaseOutput(action) 18 18 #if DEBUG 19 - let previousState = state 20 - let effects = base.reduce(into: &state, action: action) 21 - print("Action: \(actionLabel)") 22 - if previousState != state, let diff = CustomDump.diff(previousState, state) { 23 - print(diff) 24 - } 25 - return effects 19 + let previousState = state 20 + let effects = base.reduce(into: &state, action: action) 21 + print("Action: \(actionLabel)") 22 + if previousState != state, let diff = CustomDump.diff(previousState, state) { 23 + print(diff) 24 + } 25 + return effects 26 26 #else 27 - let breadcrumb = Breadcrumb(level: .debug, category: "action") 28 - breadcrumb.message = actionLabel 29 - SentrySDK.addBreadcrumb(breadcrumb) 30 - return base.reduce(into: &state, action: action) 27 + let breadcrumb = Breadcrumb(level: .debug, category: "action") 28 + breadcrumb.message = actionLabel 29 + SentrySDK.addBreadcrumb(breadcrumb) 30 + return base.reduce(into: &state, action: action) 31 31 #endif 32 32 } 33 33 }
+6 -4
supacode/Support/GitWorktreeHeadResolver.swift
··· 4 4 static func headURL(for worktreeURL: URL, fileManager: FileManager) -> URL? { 5 5 let gitURL = worktreeURL.appending(path: ".git") 6 6 var isDirectory = ObjCBool(false) 7 - guard fileManager.fileExists( 8 - atPath: gitURL.path(percentEncoded: false), 9 - isDirectory: &isDirectory 10 - ) else { 7 + guard 8 + fileManager.fileExists( 9 + atPath: gitURL.path(percentEncoded: false), 10 + isDirectory: &isDirectory 11 + ) 12 + else { 11 13 return nil 12 14 } 13 15 if isDirectory.boolValue {
+1 -1
supacodeTests/GhosttySurfaceBridgeTests.swift
··· 1 + import GhosttyKit 1 2 import Testing 2 3 3 4 @testable import supacode 4 - import GhosttyKit 5 5 6 6 @MainActor 7 7 struct GhosttySurfaceBridgeTests {