Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,6 @@ The older OpenClaw/beads/macOS-only prototype has been removed from the active s
## Imported Claude Cowork project instructions

fix the ui theme

## Activity — 2026-05-24
- (no commits)
27 changes: 27 additions & 0 deletions AgentBoardTests/NativeSwiftUIInterfaceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,33 @@ struct NativeSwiftUIInterfaceTests {
#expect(!source.contains("loadItem(forTypeIdentifier:"))
}

@Test func workBoardPersistsSelectedRepositoryAndSeedsCreateIssueSheet() throws {
let workSource = try Self.source("AgentBoardUI/Screens/WorkScreen.swift")
let createSource = try Self.source("AgentBoardUI/Screens/CreateIssueSheet.swift")

#expect(workSource.contains(#"@SceneStorage("work.selectedRepository")"#))
#expect(workSource.contains("CreateIssueSheet(initialRepository: selectedCreateRepository)"))
#expect(workSource.contains("private var selectedCreateRepository: ConfiguredRepository?"))
#expect(createSource.contains("init(initialRepository: ConfiguredRepository? = nil)"))
#expect(createSource.contains("_selectedRepository = State(initialValue: initialRepository)"))
Comment on lines +81 to +89
}

@Test func launchedSessionsOpenTerminalInDesktopShell() throws {
let source = try Self.source("AgentBoard/DesktopRootView.swift")

#expect(source.contains("onChange(of: appModel.sessionLauncher.activeSessions.map(\\.id))"))
#expect(source.contains("activeSessionTerminal = session"))
Comment on lines +92 to +96
}

@Test func companionSessionDetailOffersTerminalWhenTmuxSessionExists() throws {
let source = try Self.source("AgentBoardUI/Screens/SessionDetailSheet.swift")

#expect(source.contains("session.tmuxSession"))
#expect(source.contains(#"Text("Terminal").tag(2)"#))
#expect(source.contains("SessionLauncher.attachCommand(for: tmuxSession)"))
#expect(source.contains("EmbeddedTerminalView("))
Comment on lines +99 to +105
}

@Test func nilIfEmptyHasSingleSharedDefinition() throws {
let coreURL = Self.repositoryRoot.appending(path: "AgentBoardCore")
let fileURLs = try FileManager.default.subpathsOfDirectory(atPath: coreURL.path)
Expand Down
64 changes: 64 additions & 0 deletions AgentBoardTests/SessionLauncherTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,68 @@ struct SessionLauncherTests {
@Test @MainActor func tmuxSocketPathUsesExpectedSuffix() {
#expect(SessionLauncher.tmuxSocketPath.hasSuffix("/.tmux/sock"))
}

@Test @MainActor func checkSessionReturnsCompletedWhenPaneShowsSuccessfulExit() async {
let launcher = SessionLauncher(tmux: FakeTmuxController(
hasSessionResult: true,
paneOutput: "work complete\nEXITED: 0"
))
let session = makeActiveSession(name: "ab-agentboard-130")

let status = await launcher.checkSession(session)

#expect(status == .completed)
}

@Test @MainActor func checkSessionReturnsFailedWhenPaneShowsNonzeroExit() async {
let launcher = SessionLauncher(tmux: FakeTmuxController(
hasSessionResult: true,
paneOutput: "Failed to authenticate\nEXITED: 1"
))
let session = makeActiveSession(name: "ab-agentboard-132")

let status = await launcher.checkSession(session)

#expect(status == .failed)
}
Comment on lines +130 to +152

@MainActor
private func makeActiveSession(name: String) -> SessionLauncher.ActiveSession {
SessionLauncher.ActiveSession(
id: name,
sessionName: name,
issueNumber: 130,
preset: .ralphLoop,
agentType: .claude,
startTime: Date(),
status: .running
)
}
}

private actor FakeTmuxController: TmuxControlling {
private let hasSessionResult: Bool
private let paneOutput: String?

init(hasSessionResult: Bool, paneOutput: String?) {
self.hasSessionResult = hasSessionResult
self.paneOutput = paneOutput
}

func launchSession(
name _: String,
repoPath _: String,
agentLaunchFlag _: String,
prdPath _: String
) async throws {}

func hasSession(name _: String) async throws -> Bool {
hasSessionResult
}

func capturePane(name _: String) async -> String? {
paneOutput
}

nonisolated func openInTerminal(name _: String) {}
}
20 changes: 20 additions & 0 deletions AgentBoardTests/WorkStoreCRUDTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,26 @@ struct WorkStoreCRUDTests {
#expect(store.errorMessage == nil)
}

@Test func createIssueReturnsCreatedItemOnSuccess() async throws {
let createdJSON = issueJSON(number: 102, title: "Dismiss sheet", body: "Body here")
let (store, _) = try makeStore(mockHandler: { request in
let response = try Self.successResponse(for: request.url)
if request.httpMethod == "POST" {
return (response, Data(createdJSON.utf8))
}
return (response, Data("[]".utf8))
})

let created = await store.createIssue(
repository: ConfiguredRepository(owner: "org", name: "repo"),
title: "Dismiss sheet",
body: "Body here"
)

Comment on lines +89 to +94
#expect(created?.issueNumber == 102)
#expect(created?.title == "Dismiss sheet")
}

@Test func createIssueSendsTitleBodyAndLabelsInRequestPayload() async throws {
final class Capture: @unchecked Sendable {
var payload: [String: Any] = [:]
Expand Down
Loading