The file-manager provides a comprehensive dependency management system for code repositories. When you add a file to a group, the system automatically resolves and includes all its dependencies, creating a complete, working subset of your codebase. The system distinguishes between files you explicitly choose (root files) and files added automatically as dependencies, ensuring your explicit choices are always respected.
Dependency Resolution: The system automatically adds all required dependencies when you add a file. For example, adding user_controller.go that requires user_model.go and database.go will automatically include all three files in the group. The system uses iterative depth-first search to detect circular dependencies and prevents adding files that would create dependency cycles.
Smart File Management: Files exist in two states - AVAILABLE (can be added to groups) or ASSIGNED (already in a group). This prevents race conditions and ensures files can only be in one group at a time. When removing files, the system intelligently determines which dependencies are still needed by other files, removing only truly unused dependencies while preserving shared ones.
Root File Protection: Files you explicitly add to a group are protected from automatic removal. This means if you add database.go directly to a group, it won't be automatically removed even if the files that originally needed it are removed. This allows for incremental development where you can build complex systems by adding files piece by piece without worrying about shared dependencies being accidentally removed.
Robust Error Handling: The system validates all dependencies exist before making any changes, preventing partial group states. If any part of an operation fails, a complete rollback mechanism ensures no files are left in an inconsistent state. Input validation protects against security risks.
Architecture: The system uses a clean service-oriented architecture with dedicated services for validation, cycle detection, and dependency tracking. This separation of concerns makes the code maintainable, testable, and extensible. Each service handles one specific aspect of the system, making it easy to modify behavior or add new features without affecting other components.
The file-manager includes a comprehensive command-line interface that supports both interactive and scripted workflows. The interactive editor provides a curses-like interface where you can browse available files, add or remove them from groups, and see real-time dependency information. For automation and scripting, direct commands allow adding, removing, and listing files without user interaction.
Commands Available:
add <file>- Add a file to the current group with automatic dependency resolutionremove <file>- Remove a file from the group with intelligent cleanuplist- Show available files and current group contents with dependency countsedit [group]- Open interactive editor for a specific groupsave- Persist current group state to JSON fileload- Restore group state from JSON file
Persistence: Group states are automatically saved to JSON files, allowing you to save your work and restore it later. Each group maintains its own state file, enabling multiple independent project configurations. The JSON format is human-readable and can be version controlled or shared with team members.
- Go 1.21 or later
cd go_project
go mod tidy
go build -o file-manager main.go./file-manager edit [group-name]This opens an interactive editor where you can:
- List available files and group contents
- Add files to the group (with automatic dependency resolution)
- Remove files from the group (with smart dependency cleanup)
- View file dependency information
- Save and load group states
- View group summaries
./file-manager add [file-path] --group [group-name]./file-manager remove [file-path] --group [group-name]./file-manager list --group [group-name]./file-manager save --group [group-name]./file-manager load --group [group-name]Represents a single file with its dependencies:
type ProjectFile struct {
Path string // File path
Status FileStatus // AVAILABLE or ASSIGNED
Requires map[string]bool // Required dependencies
}Manages a collection of related files:
type ProjectGroup struct {
Name string // Group name
IncludedFiles map[string]bool // Files in group
FileDependencies map[string]map[string]bool // File -> dependencies
ReverseDependencies map[string]map[string]bool // Dependency -> files
RootFiles map[string]bool // User-added files
}Container for repository files and groups:
type Project struct {
Name string // Project name
Files map[string]*ProjectFile // All files in project
}When a file is added to a group:
- Validation: Check file status and cycle detection
- Dependency Resolution: Recursively add all required dependencies
- Rollback on Failure: Restore state if any dependency fails
- Status Updates: Mark all added files as ASSIGNED
When a file is removed from a group:
- Dependency Check: Verify file can be safely removed
- Smart Cleanup: Remove unused dependencies
- Root File Protection: Preserve user-added files
- Status Updates: Mark removed files as AVAILABLE
Implements iterative depth-first search to detect:
- Direct cycles: A requires A
- Mutual cycles: A requires B, B requires A
- Longer cycles: A → B → C → A
- Detection: Iterative DFS algorithm prevents infinite loops
- Prevention: Operations fail gracefully with clear error messages
- Examples: A→B→A, A→B→C→A
- Shared Dependencies: Multiple files can depend on the same file
- Smart Removal: Only removes dependencies when count reaches 0
- Protection: Prevents removal of shared dependencies still needed
- Validation: Checks all required dependencies exist before adding
- Graceful Failure: Clean rollback on missing dependencies
- Status Preservation: File status remains unchanged on failure
- Add Failure Rollback: Complete state restoration on dependency failures
- Consistency Guarantees: All data structures remain synchronized
- Atomic Operations: Either all dependencies succeed or nothing is added
- Deep Nesting: Supports arbitrarily deep dependency hierarchies
- Partial Failures: Handles failures at any level in the chain
- Rollback Propagation: Failures trigger rollbacks up the entire chain
The file-manager implements a comprehensive error handling system with typed errors, graceful failure recovery, and detailed error reporting. The system uses Go's error wrapping to provide context while maintaining clean error boundaries.
The system defines four main error types in the internal/errs package:
- Purpose: Input validation failures
- Examples: Empty file paths, invalid characters, path length limits
- Fields:
Field(which field failed),Msg(description) - Usage: CLI exit code 2, prevents invalid operations
- Purpose: Business logic conflicts
- Examples: File not available, circular dependencies, duplicate operations
- Fields:
Msg(conflict description) - Usage: CLI exit code 4, indicates user action conflicts
- Purpose: Missing resources
- Examples: File not found, group not found
- Fields:
Resource(type),Key(identifier) - Usage: CLI exit code 3, indicates missing resources
- Purpose: Dependency resolution failures
- Examples: Missing dependencies, dependency conflicts
- Fields:
File(source file),Missing(missing dependencies) - Usage: CLI exit code 2, indicates dependency issues
All operations are atomic - either they succeed completely or fail completely:
- File Addition: All dependencies added or none
- File Removal: All cleanup performed or none
- Status Updates: Only updated after successful operations
- State Changes: Only committed after validation passes
The system continues operating even when individual operations fail:
- Interactive Mode: Errors are displayed but editor remains functional
- Command Mode: Commands fail with appropriate exit codes
- State Persistence: Failed operations don't corrupt saved states
Error messages provide actionable guidance:
# Clear error with suggestion
Error: file 'main.go' not found in project
# User knows to check file exists and is in project
# Specific validation error
Error: invalid dependency.path: contains invalid characters (.. or ~)
# User knows to fix the dependency pathThe test suite provides comprehensive coverage including:
- Unit Tests: Individual component testing for all core types and methods
- Edge Case Tests: Comprehensive scenarios including circular dependencies, missing dependencies, and complex dependency chains
- Integration Tests: CLI and persistence functionality (partial)
- Error Handling: Rollback mechanisms and failure scenarios
- ✅ Complete dependency management with automatic resolution
- ✅ Intelligent file removal with shared dependency protection
- ✅ Comprehensive edge case handling
- ✅ Robust error handling and rollback mechanisms
- ✅ CLI interface with interactive and command-line modes
- ✅ JSON state serialization and persistence
- ✅ Type-safe implementation with comprehensive test coverage
- Memory Usage: All files and dependencies kept in memory
- Performance: O(1) file lookups using hash maps, O(k) dependency operations where k is dependency count
- Architecture: Service-oriented design with dedicated components for validation, cycle detection, and dependency tracking
- Database Integration: Persistent storage for large file sets
- Parallel Processing: Concurrent dependency resolution for complex graphs
- Caching: Dependency tree caching for frequently accessed patterns
- Batching: Bulk ops and eventual consistency concepts
- Design Colaborator: I brainstormed with chatgpt how to handle edge cases like cycles and eventually asked Cursor to implement it.
- Error handling: I asked Cursor to implemeny a taxonomy of domain errors (Validation, Dependency, Conflict, NotFound) and exit-code mapping for the CLI. I then implemented and tested this pattern, which made error paths both more robust and testable.
- Testing: After writing my own tests with the help of cursor, I used it to run a “mutation testing mindset” exercise, where it generated possible bugs. I turned those into high-signal test cases, replacing shallow coverage tests with assertions that would catch real regressions. This raised my suite to ~100% meaningful coverage.
- Carefully reviewed and fixed each and every line of code: Every suggestion and implementation was validated, edited, and improved by me.