import CodexBarCoreimport Foundationimport Testing struct AgentSessionParserTests { @Test func `ps parser deduplicates desktop wrapper and excludes app server and helpers`() throws { let output = try Self.fixtureString("agent-sessions-ps", extension: "txt") let records = AgentPSOutputParser.parse(output) let agents = AgentPSOutputParser.agentProcesses(from: records) #expect(records.count == 9) #expect(agents.map(\ .pid) == [102, 201]) #expect(AgentPSOutputParser.provider(for: agents[0]) == .claude) #expect(AgentPSOutputParser.source(for: agents[0]) == .desktopApp) #expect(AgentPSOutputParser.provider(for: agents[1]) == .codex) #expect(agents[1].command.hasSuffix("strange argv here")) #expect(AgentPSOutputParser.hasCodexAppServer(in: records)) } @Test func `lsof parser maps batched cwd records`() throws { let output = try Self.fixtureString("agent-sessions-lsof", extension: "txt") let paths = LSOFCWDOutputParser.parse(output) #expect(paths[102] == "/Users/test/Projects/alpha") #expect(paths[201] == "/Users/test/Projects/project with spaces") } @Test func `same cwd processes remain uncorrelated when ownership is ambiguous`() { let olderStart = Date(timeIntervalSince1970: 100) let newerStart = Date(timeIntervalSince1970: 200) let older = AgentProcessRecord(pid: 10, ppid: 1, startedAt: olderStart, command: "claude") let newer = AgentProcessRecord(pid: 20, ppid: 1, startedAt: newerStart, command: "claude") let olderTranscript = ClaudeSessionProjectMapper.Transcript( url: URL(fileURLWithPath: "/tmp/older.jsonl"), modifiedAt: Date(timeIntervalSince1970: 150)) let newerTranscript = ClaudeSessionProjectMapper.Transcript( url: URL(fileURLWithPath: "/tmp/newer.jsonl"), modifiedAt: Date(timeIntervalSince1970: 250)) let assignments = AgentSessionCorrelation.assignClaudeTranscripts( processes: [older, newer], cwdByPID: [10: "/project", 20: "/project"], transcriptsByCWD: ["/project": [newerTranscript, olderTranscript]]) #expect(assignments.isEmpty) } @Test func `newest process sorts first for rollout correlation`() { let older = AgentProcessRecord( pid: 10, ppid: 1, startedAt: Date(timeIntervalSince1970: 100), command: "codex exec") let newer = AgentProcessRecord( pid: 20, ppid: 1, startedAt: Date(timeIntervalSince1970: 200), command: "codex exec") #expect(AgentSessionCorrelation.newestProcessesFirst([older, newer]).map(\ .pid) == [20, 10]) } static func fixtureURL(_ name: String, extension fileExtension: String) throws -> URL { try #require(Bundle.module.url(forResource: name, withExtension: fileExtension, subdirectory: "Fixtures")) } static func fixtureString(_ name: String, extension fileExtension: String) throws -> String { try String(contentsOf: self.fixtureURL(name, extension: fileExtension), encoding: .utf8) }}
import CodexBarCore
import Foundation
import Testing
struct AgentSessionParserTests {
@Test
func `ps parser deduplicates desktop wrapper and excludes app server and helpers`() throws {
let output = try Self.fixtureString("agent-sessions-ps", extension: "txt")
let records = AgentPSOutputParser.parse(output)
let agents = AgentPSOutputParser.agentProcesses(from: records)
#expect(records.count == 9)
#expect(agents.map(\ .pid) == [102, 201])
#expect(AgentPSOutputParser.provider(for: agents[0]) == .claude)
#expect(AgentPSOutputParser.source(for: agents[0]) == .desktopApp)
#expect(AgentPSOutputParser.provider(for: agents[1]) == .codex)
#expect(agents[1].command.hasSuffix("strange argv here"))
#expect(AgentPSOutputParser.hasCodexAppServer(in: records))
}
@Test
func `lsof parser maps batched cwd records`() throws {
let output = try Self.fixtureString("agent-sessions-lsof", extension: "txt")
let paths = LSOFCWDOutputParser.parse(output)
#expect(paths[102] == "/Users/test/Projects/alpha")
#expect(paths[201] == "/Users/test/Projects/project with spaces")
}
@Test
func `same cwd processes remain uncorrelated when ownership is ambiguous`() {
let olderStart = Date(timeIntervalSince1970: 100)
let newerStart = Date(timeIntervalSince1970: 200)
let older = AgentProcessRecord(pid: 10, ppid: 1, startedAt: olderStart, command: "claude")
let newer = AgentProcessRecord(pid: 20, ppid: 1, startedAt: newerStart, command: "claude")
let olderTranscript = ClaudeSessionProjectMapper.Transcript(
url: URL(fileURLWithPath: "/tmp/older.jsonl"),
modifiedAt: Date(timeIntervalSince1970: 150))
let newerTranscript = ClaudeSessionProjectMapper.Transcript(
url: URL(fileURLWithPath: "/tmp/newer.jsonl"),
modifiedAt: Date(timeIntervalSince1970: 250))
let assignments = AgentSessionCorrelation.assignClaudeTranscripts(
processes: [older, newer],
cwdByPID: [10: "/project", 20: "/project"],
transcriptsByCWD: ["/project": [newerTranscript, olderTranscript]])
#expect(assignments.isEmpty)
}
@Test
func `newest process sorts first for rollout correlation`() {
let older = AgentProcessRecord(
pid: 10,
ppid: 1,
startedAt: Date(timeIntervalSince1970: 100),
command: "codex exec")
let newer = AgentProcessRecord(
pid: 20,
ppid: 1,
startedAt: Date(timeIntervalSince1970: 200),
command: "codex exec")
#expect(AgentSessionCorrelation.newestProcessesFirst([older, newer]).map(\ .pid) == [20, 10])
}
static func fixtureURL(_ name: String, extension fileExtension: String) throws -> URL {
try #require(Bundle.module.url(forResource: name, withExtension: fileExtension, subdirectory: "Fixtures"))
}
static func fixtureString(_ name: String, extension fileExtension: String) throws -> String {
try String(contentsOf: self.fixtureURL(name, extension: fileExtension), encoding: .utf8)
}
}