Skip to content

Commit 30a7193

Browse files
authored
chore: prepare v0.4.0 release (#1)
- Consolidate unreleased changes into v0.4.0 section in CHANGELOG - Add CLAUDE.md documentation for Claude Code integration
1 parent ecb04d6 commit 30a7193

2 files changed

Lines changed: 191 additions & 108 deletions

File tree

CHANGELOG.md

Lines changed: 33 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -9,126 +9,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12-
- **Comprehensive end-to-end testing suite** - Added e2e tests that verify CLI behavior by building and executing the actual binary:
13-
- **Complete command coverage**: All commands tested with various flag combinations and edge cases
14-
- **Workflow testing**: Multi-command workflows that simulate real user scenarios
15-
- **Test infrastructure**: Efficient test helpers with binary caching and environment isolation
16-
- **Setup automation**: `scripts/setup-testdata.sh` creates isolated test environments
17-
- **Output validation**: Tests for both text and JSON output formats
18-
- **Error handling**: Comprehensive testing of error conditions and user feedback
19-
- **Cross-platform support**: Tests run on all platforms with Windows-specific handling
12+
### Changed
13+
14+
### Deprecated
15+
16+
### Removed
2017

2118
### Fixed
2219

23-
- **Remove/Prune --yes flag** - Fixed inverted logic that caused `--yes` flag to still prompt for confirmation
24-
- The `remove` and `prune` commands now correctly skip confirmation when `--yes` is provided
25-
- Previously, the logic was inverted causing `--yes` to have no effect
26-
27-
- **Adopt command flag parsing** - Fixed flag parsing issue that prevented adopt command from working
28-
- Removed `--source-dir` and `--target-dir` from global flags as they were command-specific
29-
- The adopt command can now properly parse its required `--source-dir` flag
30-
- Previously, global flag parsing consumed these flags before commands could see them
31-
32-
- **Config file error handling** - Fixed config loading to properly report errors for invalid configurations
33-
- When using `--config` flag with an invalid or non-existent file, lnk now exits with an error
34-
- Previously, config loading errors were silently ignored and fell back to defaults
35-
- Validation errors in config files are now properly reported to the user
36-
37-
- **Progress indicator consistency** - Fixed progress indicators showing prematurely and leaving terminal artifacts:
38-
- Progress indicators now only show for operations taking longer than 1 second
39-
- Removed duplicate progress tracking that caused immediate output
40-
- Fixed terminal cleanup to prevent `` symbols from appearing
41-
- Consistent behavior across all commands (create, status, adopt, orphan, remove, prune)
42-
43-
- **Output formatting consistency** - Standardized output across all commands:
44-
- All commands now display a newline after headers for consistent spacing
45-
- Empty result messages are consistent (e.g., "No files to link found.")
46-
- Summary sections have consistent spacing with newlines before them
47-
- Added helper functions to enforce output patterns
48-
- Fixed `create` command to show feedback when all symlinks already exist
49-
50-
### Breaking Changes
51-
52-
- **Removed environment variables in favor of flags** - All custom environment variables have been removed:
53-
- `LNK_CONFIG` → Use `--config` flag instead
54-
- `LNK_IGNORE` → Set ignore patterns in config file or use future `--ignore` flag
55-
- `LNK_DEBUG` → Use `--verbose` flag instead for detailed output
56-
- Standard environment variables (`HOME`, `XDG_CONFIG_HOME`, `NO_COLOR`, `PATH`) are still supported
57-
- This change makes the tool more discoverable and follows CLI best practices
58-
59-
- **Renamed project from cfgman to lnk** - The project has been renamed to better reflect its focused purpose as a symlink management tool:
60-
- Binary name: `cfgman``lnk`
61-
- Config file: `.cfgman.json``.lnk.json`
62-
- Environment variables: `CFGMAN_*``LNK_*`
63-
- Go module: `github.com/cpplain/cfgman``github.com/cpplain/lnk`
64-
65-
- **Command names reverted to original form**:
66-
- `link``create` (for creating symlinks)
67-
- `unlink``remove` (for removing symlinks)
68-
69-
- **Directory-based architecture with absolute paths** - lnk now uses absolute paths for source directories:
70-
- Source directories in config must now be absolute paths (e.g., `~/dotfiles/home` instead of `home`)
71-
- Adopt command requires absolute path: `--source-dir ~/dotfiles/home`
72-
- Removed `--repo-dir` flag and `LNK_REPO_DIR` environment variable
73-
- Can run lnk from any directory - no longer requires a "repository directory"
74-
75-
- **Command arguments replaced with explicit flags**:
76-
- `adopt PATH SOURCE_DIR``adopt --path PATH --source-dir SOURCE_DIR`
77-
- `orphan PATH``orphan --path PATH`
78-
79-
- **Flag changes**:
80-
- Removed `--force` flags from commands in favor of global `--yes` flag
81-
- Replaced `--json` flag with `--output FORMAT` flag (supports text/json)
82-
83-
- **Removed `init` command** - lnk works with built-in defaults and doesn't require a config file
20+
### Security
21+
22+
## [0.4.0] - 2026-02-14
8423

8524
### Added
8625

87-
- **Works without configuration** - Configuration discovery with flexible precedence:
88-
- Built-in defaults: `~/dotfiles/home``~/`, `~/dotfiles/config``~/.config/`
89-
- XDG Base Directory support: `$XDG_CONFIG_HOME/lnk/config.json`
90-
- Global flags: `--config`, `--source-dir`, `--target-dir`, `--ignore`
91-
- Environment variables: `LNK_CONFIG`, `LNK_SOURCE_DIR`, `LNK_TARGET_DIR`, `LNK_IGNORE`
92-
93-
- **Global flags for better control**:
94-
- `--verbose`/`-v`: Detailed debug output
95-
- `--quiet`/`-q`: Suppress non-error output
96-
- `--yes`/`-y`: Skip confirmation prompts
97-
- `--no-color`: Disable colored output
98-
- `--output FORMAT`: Choose output format (text/json)
99-
100-
- **Enhanced user experience features**:
101-
- "Did you mean?" suggestions for mistyped commands
102-
- Progress indicators for operations taking more than 1 second
103-
- Next-step suggestions after successful operations
104-
- Confirmation prompts for destructive operations
105-
- Error messages with actionable "Try:" suggestions
106-
107-
- **Machine-friendly features**:
108-
- JSON output support for `status` command
109-
- Automatic output adaptation for piping (simplified format)
110-
- Specific exit codes: 0 (success), 1 (runtime errors), 2 (usage errors)
111-
112-
- **CLI design documentation** following [cpplain/cli-design](https://github.com/cpplain/cli-design) principles
26+
- Comprehensive end-to-end testing suite
27+
- Zero-configuration defaults with flexible config discovery (`~/.config/lnk/config.json`, `~/.lnk.json`)
28+
- Global flags: `--verbose`, `--quiet`, `--yes`, `--no-color`, `--output`
29+
- Command suggestions for typos, progress indicators, confirmation prompts
30+
- JSON output and specific exit codes for scripting
11331

11432
### Changed
11533

116-
- **Improved help system**:
117-
- Standardized formatting across all commands
118-
- Commands appear before options (standard convention)
119-
- "See also" sections for related commands
120-
- Removed `help` command (use `lnk <command> --help`)
34+
- Improved help system with standardized formatting and "See also" sections
35+
- Better output formatting with consistent indicators (✓, ✗, !) and `~` for home
36+
- **BREAKING: Renamed project from cfgman to lnk** (binary, config, module)
37+
- **BREAKING: Command names** `link``create`, `unlink``remove`
38+
- **BREAKING: Source directories must be absolute paths**; removed `--repo-dir`
39+
- **BREAKING: Explicit flags required** (`adopt --path PATH --source-dir DIR`)
40+
- **BREAKING: Replaced `--force` with global `--yes`**; `--json` with `--output FORMAT`
41+
42+
### Removed
12143

122-
- **Better output formatting**:
123-
- Consistent visual indicators: ✓ (success), ✗ (error), ! (warning)
124-
- Home directory displayed as `~` consistently
125-
- Summary statistics for bulk operations
126-
- Table-aligned status output
44+
- **BREAKING: Custom environment variables** (`LNK_CONFIG`, `LNK_IGNORE`, `LNK_DEBUG`)
45+
- **BREAKING: `init` command** (built-in defaults work without config)
12746

12847
### Fixed
12948

130-
- **Circular symlink validation** - Now correctly allows existing symlinks that already point to their intended target
131-
- **Test environment isolation** - Tests no longer load system configuration files
49+
- `--yes` flag now correctly skips confirmation in `remove` and `prune`
50+
- Adopt command flag parsing (previously consumed by global flags)
51+
- Config file errors now reported instead of silently falling back to defaults
52+
- Progress indicators only show after 1 second; no terminal artifacts
53+
- Output spacing consistency across all commands
54+
- Circular symlink validation for existing correct symlinks
55+
- Test environment isolation from system config
13256

13357
## [0.3.0] - 2025-06-28
13458

@@ -184,7 +108,8 @@ Initial release of cfgman.
184108
- **Performance** - Concurrent operations for status checking
185109
- **Zero dependencies** - Pure Go implementation using only standard library
186110

187-
[unreleased]: https://github.com/cpplain/lnk/compare/v0.3.0...HEAD
111+
[unreleased]: https://github.com/cpplain/lnk/compare/v0.4.0...HEAD
112+
[0.4.0]: https://github.com/cpplain/lnk/compare/v0.3.0...v0.4.0
188113
[0.3.0]: https://github.com/cpplain/lnk/compare/v0.2.0...v0.3.0
189114
[0.2.0]: https://github.com/cpplain/lnk/compare/v0.1.1...v0.2.0
190115
[0.1.1]: https://github.com/cpplain/lnk/compare/v0.1.0...v0.1.1

CLAUDE.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
`lnk` is an opinionated symlink manager for dotfiles written in Go. It recursively traverses source directories and creates individual symlinks for each file (not directories), allowing mixed file sources in the same target directory.
8+
9+
## Development Commands
10+
11+
```bash
12+
# Build
13+
make build # Build binary to bin/lnk with version from git tags
14+
15+
# Testing
16+
make test # Run all tests (unit + e2e)
17+
make test-unit # Run unit tests only (internal/lnk)
18+
make test-e2e # Run e2e tests only (e2e/)
19+
make test-coverage # Generate coverage report (coverage.html)
20+
21+
# Code Quality
22+
make fmt # Format code (prefers goimports, falls back to gofmt)
23+
make lint # Run go vet
24+
make check # Run fmt, test, and lint in sequence
25+
26+
# Installation
27+
make install # Build and install to /usr/local/bin (or PREFIX=/path)
28+
make install PREFIX=~/.local # Install to user directory
29+
```
30+
31+
## Architecture
32+
33+
### Core Components
34+
35+
- **cmd/lnk/main.go**: CLI entry point with manual flag parsing (not stdlib flags for global flags). Routes to command handlers. Uses Levenshtein distance for command suggestions.
36+
37+
- **internal/lnk/config.go**: Configuration system with precedence chain:
38+
1. `--config` flag
39+
2. `$XDG_CONFIG_HOME/lnk/config.json`
40+
3. `~/.config/lnk/config.json`
41+
4. `~/.lnk.json`
42+
5. `./.lnk.json` in current directory
43+
6. Built-in defaults
44+
45+
- **internal/lnk/linker.go**: Symlink operations with 3-phase execution:
46+
1. Collect planned links (recursive file traversal)
47+
2. Validate all targets
48+
3. Execute or show dry-run
49+
50+
- **internal/lnk/adopt.go**: Moves files from target to source directory and creates symlinks
51+
52+
- **internal/lnk/orphan.go**: Removes symlinks and restores actual files to target locations
53+
54+
### Key Design Patterns
55+
56+
**Recursive File Linking**: lnk creates symlinks for individual files, NOT directories. This allows:
57+
58+
- Multiple source directories can map to the same target
59+
- Local-only files can coexist with managed configs
60+
- Parent directories are created as regular directories, never symlinks
61+
62+
**Error Handling**: Uses custom error types in `errors.go`:
63+
64+
- `PathError`: for file operation errors
65+
- `ValidationError`: for validation failures
66+
- `WithHint()`: adds actionable hints to errors
67+
68+
**Output System**: Centralized in `output.go` with support for:
69+
70+
- Text format (default, colorized)
71+
- JSON format (`--output json`)
72+
- Verbosity levels: quiet, normal, verbose
73+
74+
**Terminal Detection**: `terminal.go` detects TTY for conditional formatting (colors, progress bars)
75+
76+
### Configuration Structure
77+
78+
```go
79+
type Config struct {
80+
IgnorePatterns []string // Gitignore-style patterns
81+
LinkMappings []LinkMapping // Source-to-target mappings
82+
}
83+
84+
type LinkMapping struct {
85+
Source string // Absolute path or ~/path
86+
Target string // Where symlinks are created
87+
}
88+
```
89+
90+
### Testing Structure
91+
92+
- **Unit tests**: `internal/lnk/*_test.go` - use `testutil_test.go` helpers for temp dirs
93+
- **E2E tests**: `e2e/e2e_test.go` - full workflow testing
94+
- Test data: Use `e2e/helpers_test.go` for creating test repositories
95+
96+
## Development Guidelines
97+
98+
### Commit Messages
99+
100+
Follow [Conventional Commits](https://www.conventionalcommits.org/):
101+
102+
- `feat:` - new feature
103+
- `fix:` - bug fix
104+
- `docs:` - documentation only
105+
- `refactor:` - code restructuring
106+
- `test:` - adding/updating tests
107+
- `chore:` - build/tooling changes
108+
109+
Breaking changes use `!` suffix: `feat!:` or `BREAKING CHANGE:` in footer.
110+
111+
### CLI Design Principles
112+
113+
From [cpplain/cli-design](https://github.com/cpplain/cli-design):
114+
115+
- **Obvious Over Clever**: Make intuitive paths easiest
116+
- **Helpful Over Minimal**: Provide clear guidance and error messages
117+
- **Consistent Over Special**: Follow CLI conventions
118+
- All destructive operations support `--dry-run`
119+
120+
### Code Standards
121+
122+
- Use `PrintVerbose()` for debug output (hidden unless --verbose)
123+
- Use `PrintErrorWithHint()` for user-facing errors with actionable hints
124+
- Expand paths with `ExpandPath()` to handle `~/` notation
125+
- Validate paths early using `validation.go` functions
126+
- Always support JSON output mode (`--output json`) for scripting
127+
128+
## Common Tasks
129+
130+
### Adding a New Command
131+
132+
1. Add command name to `suggestCommand()` in main.go
133+
2. Add case in main switch statement
134+
3. Create handler function following pattern: `handleXxx(args, globalOptions)`
135+
4. Create FlagSet with `-h/--help` usage function
136+
5. Implement command logic in `internal/lnk/`
137+
6. Add tests in `internal/lnk/xxx_test.go`
138+
7. Add e2e test if appropriate
139+
140+
### Modifying Configuration
141+
142+
- Configuration struct in `config.go` must remain JSON-serializable
143+
- Update `Validate()` method when adding fields
144+
- Add validation with helpful hints using `NewValidationErrorWithHint()`
145+
146+
### Running Single Test
147+
148+
```bash
149+
go test -v ./internal/lnk -run TestFunctionName
150+
go test -v ./e2e -run TestE2EName
151+
```
152+
153+
## Technical Notes
154+
155+
- Version info injected via ldflags during build (version, commit, date)
156+
- No external dependencies - stdlib only
157+
- Git operations are optional (detected at runtime)
158+
- Manual flag parsing allows global flags before command name

0 commit comments

Comments
 (0)