A macOS utility to track home-manager JJ repo status

Add README and AGENTS.md documentation

README: Brief overview for users covering what the app does, target
audience (home-manager + jj users on macOS), and installation.

AGENTS.md: Guidelines for AI coding agents with build/test commands,
code style conventions, project structure, and development workflow.

AI-assisted: GitLab Duo Agentic Chat (Claude Opus 4.5)

+266
+196
AGENTS.md
··· 1 + # Agent Guidelines for HomeManagerStatus 2 + 3 + This document provides guidelines for AI coding agents working on this codebase. 4 + 5 + ## Project Overview 6 + 7 + HomeManagerStatus is a macOS menu bar app written in Swift that displays the Jujutsu (jj) status of `~/.config/home-manager`. It's packaged with Nix and includes a home-manager module for launchd integration. 8 + 9 + ## Build Commands 10 + 11 + ### Swift (development) 12 + 13 + ```bash 14 + # Build (debug) 15 + swift build 16 + 17 + # Build (release) 18 + swift build -c release 19 + 20 + # Run the app directly (for testing) 21 + swift run 22 + ``` 23 + 24 + ### Nix (production) 25 + 26 + ```bash 27 + # Build the package 28 + nix build 29 + 30 + # Enter development shell (provides swift-format) 31 + nix develop 32 + 33 + # Format all files (Nix, Shell, Swift) 34 + nix fmt 35 + 36 + # Check flake validity 37 + nix flake check 38 + ``` 39 + 40 + ## Test Commands 41 + 42 + ```bash 43 + # Run all tests 44 + swift test 45 + 46 + # Run a single test file 47 + swift test --filter HomeManagerStatusTests.StatusParserTests 48 + 49 + # Run a single test method 50 + swift test --filter HomeManagerStatusTests.StatusParserTests/testParseCommitCountEmpty 51 + 52 + # Run tests with verbose output 53 + swift test --verbose 54 + ``` 55 + 56 + ## Code Style 57 + 58 + ### Formatting 59 + 60 + This project uses `swift-format` for Swift code formatting, configured via treefmt-nix. Always run `nix fmt` before committing. 61 + 62 + Key formatting rules: 63 + - 2-space indentation 64 + - Line length: 100 characters (soft limit) 65 + - Trailing commas in multi-line collections 66 + 67 + ### Imports 68 + 69 + Order imports alphabetically. Standard library and system frameworks first: 70 + 71 + ```swift 72 + import Foundation 73 + import SwiftUI 74 + import XCTest 75 + 76 + @testable import HomeManagerStatus 77 + ``` 78 + 79 + ### Naming Conventions 80 + 81 + | Type | Convention | Example | 82 + |------|------------|---------| 83 + | Types (struct, class, enum, protocol) | PascalCase | `RepoStatus`, `StatusParser` | 84 + | Functions and methods | camelCase | `parseCommitCount`, `startPolling` | 85 + | Variables and properties | camelCase | `refreshInterval`, `repoPath` | 86 + | Constants | camelCase | `fixedDate` | 87 + | Enum cases | camelCase | `unexpectedDirtyOutput` | 88 + 89 + ### Types and Protocols 90 + 91 + - Prefer `struct` over `class` unless reference semantics are required 92 + - Use `@MainActor` for UI-bound types (e.g., `StatusChecker`) 93 + - Define protocols for testability (e.g., `JujutsuCommandRunner`) 94 + - Use `enum` with no cases for namespacing pure functions (e.g., `StatusParser`) 95 + 96 + ### Error Handling 97 + 98 + - Define errors as nested enums conforming to `LocalizedError` 99 + - Provide `errorDescription` for user-facing messages 100 + - Use `Result` for mock/test code, `throws` for production code 101 + 102 + ```swift 103 + enum ParserError: LocalizedError { 104 + case unexpectedDirtyOutput(String) 105 + 106 + var errorDescription: String? { 107 + switch self { 108 + case .unexpectedDirtyOutput(let output): 109 + return "Unexpected dirty status output: '\(output)'" 110 + } 111 + } 112 + } 113 + ``` 114 + 115 + ### Documentation 116 + 117 + - Use `///` doc comments for public APIs 118 + - Include parameter and return descriptions for non-trivial functions 119 + - Use `// MARK: -` to organize code sections 120 + 121 + ```swift 122 + /// Parse the output of `jj log` that lists commit short IDs (one per line) 123 + /// and return the count of commits. 124 + /// 125 + /// - Parameter output: Raw stdout from jj log command 126 + /// - Returns: Number of commits listed 127 + static func parseCommitCount(from output: String) -> Int { ... } 128 + ``` 129 + 130 + ### Testing 131 + 132 + - Test files mirror source files: `StatusParser.swift` -> `StatusParserTests.swift` 133 + - Use descriptive test names: `testParseCommitCountEmpty`, `testRefreshWithError` 134 + - Group related tests with `// MARK: -` comments 135 + - Use fixed dates for deterministic tests: `let fixedDate = Date(timeIntervalSince1970: 1_700_000_000)` 136 + - Create mock implementations of protocols for unit testing 137 + 138 + ### Async/Await 139 + 140 + - Use `async/await` for asynchronous operations 141 + - Use `withCheckedThrowingContinuation` to bridge callback-based APIs 142 + - Mark test methods as `async` when testing async code 143 + - Use `@MainActor` for classes that publish to SwiftUI 144 + 145 + ## Project Structure 146 + 147 + ``` 148 + . 149 + ├── Sources/HomeManagerStatus/ 150 + │ ├── HomeManagerStatusApp.swift # App entry point, SwiftUI views 151 + │ ├── StatusChecker.swift # Orchestrates polling and state 152 + │ ├── StatusParser.swift # Pure parsing functions 153 + │ ├── RepoStatus.swift # Data model 154 + │ └── JujutsuCommandRunner.swift # Protocol + live implementation 155 + ├── Tests/HomeManagerStatusTests/ 156 + │ ├── StatusCheckerTests.swift 157 + │ ├── StatusParserTests.swift 158 + │ └── RepoStatusTests.swift 159 + ├── nix/ 160 + │ ├── package.nix # Nix derivation 161 + │ └── modules/home-manager.nix # home-manager module 162 + ├── Package.swift # Swift package manifest 163 + ├── Info.plist # macOS app bundle metadata 164 + └── flake.nix # Nix flake 165 + ``` 166 + 167 + ## Version Control 168 + 169 + This project uses Jujutsu (jj). Key commands: 170 + 171 + ```bash 172 + jj status # Show working copy changes 173 + jj diff --git # Show diff in git format 174 + jj describe -m "msg" # Set commit message (don't use jj commit) 175 + jj new # Create new change 176 + ``` 177 + 178 + Do NOT use interactive jj commands (`jj commit`, `jj split`) without `-m` flag. 179 + 180 + ## Nix Module 181 + 182 + The home-manager module exposes: 183 + - `programs.jj-home-manager-status.enable` (bool) 184 + - `programs.jj-home-manager-status.package` (package) 185 + 186 + When modifying the module, test with: 187 + ```bash 188 + nix flake check 189 + nix eval '.#homeManagerModules.default' 190 + ``` 191 + 192 + ## Platform Requirements 193 + 194 + - macOS 13.0+ (Ventura) 195 + - Swift 5.9+ 196 + - Jujutsu (jj) in PATH
+70
README.md
··· 1 + # HomeManagerStatus 2 + 3 + A macOS menu bar app that shows the [Jujutsu (jj)](https://github.com/jj-vcs/jj) status of your `~/.config/home-manager` repository. 4 + 5 + ## What it does 6 + 7 + - Displays ahead/behind status relative to `trunk()` in the menu bar 8 + - Shows if the working copy has uncommitted changes 9 + - Polls every 5 minutes with manual refresh available 10 + - Quick action to open the repo in Ghostty terminal 11 + 12 + ## Target Audience 13 + 14 + This app is for users who: 15 + 16 + - Manage their dotfiles with [home-manager](https://github.com/nix-community/home-manager) 17 + - Use Jujutsu (jj) for version control 18 + - Run macOS 13+ (Ventura or later) 19 + 20 + ## Installation 21 + 22 + ### With home-manager (recommended) 23 + 24 + Add the flake input to your `flake.nix`: 25 + 26 + ```nix 27 + inputs.jj-home-manager-status = { 28 + url = "github:nolith/JJHomeManagerStatus.app"; 29 + inputs.nixpkgs.follows = "nixpkgs"; 30 + }; 31 + ``` 32 + 33 + Then enable the module in your home-manager configuration: 34 + 35 + ```nix 36 + { pkgs, jj-home-manager-status, ... }: 37 + { 38 + imports = [ jj-home-manager-status.homeManagerModules.default ]; 39 + 40 + programs.jj-home-manager-status = { 41 + enable = true; 42 + package = jj-home-manager-status.packages.${pkgs.system}.default; 43 + }; 44 + } 45 + ``` 46 + 47 + This configures a launchd user agent that starts the app at login and keeps it running. 48 + 49 + ### Manual build 50 + 51 + ```bash 52 + # With Nix 53 + nix build 54 + 55 + # With Swift (for development) 56 + swift build -c release 57 + ``` 58 + 59 + ## Configuration Options 60 + 61 + | Option | Type | Default | Description | 62 + | --------- | ------- | -------------------------- | ---------------------------------- | 63 + | `enable` | bool | `false` | Whether to enable the menu bar app | 64 + | `package` | package | `pkgs.home-manager-status` | The package to use | 65 + 66 + ## Requirements 67 + 68 + - macOS 13.0 or later 69 + - Jujutsu (`jj`) installed and available in PATH 70 + - A jj-managed repository at `~/.config/home-manager`