A macOS utility to track home-manager JJ repo status
at main 196 lines 5.5 kB view raw view rendered
1# Agent Guidelines for HomeManagerStatus 2 3This document provides guidelines for AI coding agents working on this codebase. 4 5## Project Overview 6 7HomeManagerStatus 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) 15swift build 16 17# Build (release) 18swift build -c release 19 20# Run the app directly (for testing) 21swift run 22``` 23 24### Nix (production) 25 26```bash 27# Build the package 28nix build 29 30# Enter development shell (provides swift-format) 31nix develop 32 33# Format all files (Nix, Shell, Swift) 34nix fmt 35 36# Check flake validity 37nix flake check 38``` 39 40## Test Commands 41 42```bash 43# Run all tests 44swift test 45 46# Run a single test file 47swift test --filter HomeManagerStatusTests.StatusParserTests 48 49# Run a single test method 50swift test --filter HomeManagerStatusTests.StatusParserTests/testParseCommitCountEmpty 51 52# Run tests with verbose output 53swift test --verbose 54``` 55 56## Code Style 57 58### Formatting 59 60This project uses `swift-format` for Swift code formatting, configured via treefmt-nix. Always run `nix fmt` before committing. 61 62Key formatting rules: 63- 2-space indentation 64- Line length: 100 characters (soft limit) 65- Trailing commas in multi-line collections 66 67### Imports 68 69Order imports alphabetically. Standard library and system frameworks first: 70 71```swift 72import Foundation 73import SwiftUI 74import 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 103enum 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 127static 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 169This project uses Jujutsu (jj). Key commands: 170 171```bash 172jj status # Show working copy changes 173jj diff --git # Show diff in git format 174jj describe -m "msg" # Set commit message (don't use jj commit) 175jj new # Create new change 176``` 177 178Do NOT use interactive jj commands (`jj commit`, `jj split`) without `-m` flag. 179 180## Nix Module 181 182The home-manager module exposes: 183- `programs.jj-home-manager-status.enable` (bool) 184- `programs.jj-home-manager-status.package` (package) 185 186When modifying the module, test with: 187```bash 188nix flake check 189nix eval '.#homeManagerModules.default' 190``` 191 192## Platform Requirements 193 194- macOS 13.0+ (Ventura) 195- Swift 5.9+ 196- Jujutsu (jj) in PATH