A macOS utility to track home-manager JJ repo status
1import Foundation
2
3/// Single-shot jj status check. Cross-platform (no Apple frameworks).
4public enum StatusChecker {
5 /// Perform a single status check against a jj repository.
6 ///
7 /// - Parameters:
8 /// - repoPath: Path to the jj repository
9 /// - runner: Command runner to use (defaults to LiveJujutsuCommandRunner)
10 /// - date: Timestamp for the check (defaults to now)
11 /// - Returns: A fully populated RepoStatus
12 public static func check(
13 repoPath: String,
14 runner: JujutsuCommandRunner = LiveJujutsuCommandRunner(),
15 at date: Date = Date()
16 ) async -> RepoStatus {
17 do {
18 // Use fork_point(@|trunk()) as the base for both ahead/behind checks.
19 // This finds the best common ancestor of @ and trunk(), which is more
20 // correct than set difference when there's divergence.
21 // We use @- (parent of working copy) to exclude the jj working copy
22 // change itself — it's always present and its emptiness/dirtiness
23 // is tracked separately via the dirty check below.
24 async let aheadOutput = runner.run(
25 args: [
26 "log",
27 "-r", "fork_point(@|trunk())..@-",
28 "--no-graph",
29 "-T", "description.first_line() ++ \"\\n\"",
30 ],
31 repoPath: repoPath
32 )
33
34 async let behindOutput = runner.run(
35 args: [
36 "log",
37 "-r", "fork_point(@|trunk())..trunk()",
38 "--no-graph",
39 "-T", "description.first_line() ++ \"\\n\"",
40 ],
41 repoPath: repoPath
42 )
43
44 async let dirtyOutput = runner.run(
45 args: [
46 "log",
47 "-r", "@",
48 "--no-graph",
49 "-T", "if(empty, \"clean\", \"dirty\")",
50 ],
51 repoPath: repoPath
52 )
53
54 let (ahead, behind, dirty) = try await (aheadOutput, behindOutput, dirtyOutput)
55 return StatusParser.parse(
56 aheadOutput: ahead,
57 behindOutput: behind,
58 dirtyOutput: dirty,
59 at: date
60 )
61 } catch {
62 return RepoStatus.error(error.localizedDescription, at: date)
63 }
64 }
65}