|
| 1 | +# MiMiNavigator — Codex AI Guidelines |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +MiMiNavigator is a dual-panel file manager for macOS, built with Swift 6.2 and SwiftUI. Inspired by Total Commander and Norton Commander. |
| 5 | + |
| 6 | +## ⚠️ CRITICAL RULES — NEVER VIOLATE |
| 7 | +1. **NEVER commit/push without explicit user request** — Wait for user to explicitly ask |
| 8 | +2. **NEVER add AI signatures in code** — No AI attribution comments or markers |
| 9 | +3. **Always run `Scripts/git_cleanup.zsh`** before any git commit |
| 10 | +4. **Use zsh only** — Never bash or default shell for MiMiNavigator work |
| 11 | +5. **Commit Packages/** submodule changes separately (cd into Packages dir first) |
| 12 | +6. **Git commit messages**: short English, lowercase, no slangy |
| 13 | + |
| 14 | +## 🎯 Development Guidelines |
| 15 | + |
| 16 | +### Code Quality |
| 17 | +- **No file over 400 lines** — extract to new files |
| 18 | +- **English comments only** — no Russian/German in code |
| 19 | +- **`#colorLiteral` for colors** — never hardcoded RGB strings |
| 20 | +- **Logging tags**: `[Component]` format (e.g. `[Rename]`, `[Scan]`, `[FileOps]`, `[Selection]`) |
| 21 | +- **`// MARK: - Name`** directly above every class/struct/enum/non-trivial method |
| 22 | +- **No blank lines inside method bodies** |
| 23 | +- **`nonisolated(unsafe)`** for Swift 6 NSCache statics; for popup event monitors use `PopupEventMonitors` class (three `Any?` fields only) |
| 24 | + |
| 25 | +### Build & Run |
| 26 | +- **Builds only on user's Mac** via osascript (Control your Mac), never on remote |
| 27 | +- Reading, writing, analysis on remote is OK |
| 28 | +- `⌘R` in Xcode or `Scripts/build_debug.zsh` |
| 29 | +- **Before build**: run `zsh Scripts/stamp_version.zsh` to sync version from git tag |
| 30 | + |
| 31 | +### Version Management |
| 32 | +- `Scripts/refreshVersionFile.zsh` — main script: writes `curr_version.asc` + updates `MARKETING_VERSION` in pbxproj from git tag |
| 33 | +- `Scripts/stamp_version.zsh` — thin wrapper calling `refreshVersionFile.zsh` |
| 34 | +- Version in window title reads from `CFBundleShortVersionString` (plist) |
| 35 | +- DEV BUILD badge reads from `curr_version.asc` (date + host) |
| 36 | + |
| 37 | +### Architecture Patterns |
| 38 | +| Pattern | Usage | |
| 39 | +|---------|-------| |
| 40 | +| `@Observable` + `@MainActor` | `AppState`, `MultiSelectionManager`, `TabManager` | |
| 41 | +| `@MainActor` + `@Observable` | `CntMenuCoord` — singleton, all context menu actions | |
| 42 | +| `actor` | `DualDirectoryScanner`, `ArchiveManager`, `FindFilesEngine` | |
| 43 | +| `AsyncStream` | `FindFilesEngine` streaming results | |
| 44 | +| `AutoFitScheduler` | Singleton for sequential column autofit (L→R), no per-view race | |
| 45 | +| `ExternalToolRegistry` | Registry of CLI tools (7z, ffmpeg) with install status + Settings pane | |
| 46 | +| Swift Package (dynamic) | `FavoritesKit`, `LogKit`, `NetworkKit` | |
| 47 | + |
| 48 | +### Firmlink Handling |
| 49 | +macOS firmlinks (`/tmp` ↔ `/private/tmp`, `/var` ↔ `/private/var`, `/etc` ↔ `/private/etc`) cause: |
| 50 | +- `URL.resourceValues(forKeys: [.isDirectoryKey])` returning `isDirectory == false` for `/tmp` |
| 51 | +- `CustomFile.urlValue` storing `/private/tmp/X` while file is at `/tmp/X` |
| 52 | +- Always use `FileManager.fileExists(atPath:isDirectory:)` as fallback for directory checks |
| 53 | +- Use `resolveSourceURL()` pattern for file operations on firmlink paths |
| 54 | + |
| 55 | +### Xcode Project |
| 56 | +- Xcode 16+ filesystem-based structure — files in folders appear in build automatically |
| 57 | +- Never edit `project.pbxproj` to add/remove source files |
| 58 | +- Do edit it automatically when adding/removing packages or targets |
| 59 | + |
| 60 | +### DMG Release |
| 61 | +- `Scripts/notarize_release.zsh <version>` — full pipeline: build → sign → DMG → notarize → staple → GitHub |
| 62 | +- DMG has background image + `/Applications` symlink (drag-to-install UX) |
| 63 | +- `Scripts/generate_dmg_background.zsh` — generates Retina background (requires Pillow) |
| 64 | + |
| 65 | +### Context Menu Architecture |
| 66 | +- `⌥ R-Menu` (Option+right-click) shows alternative operations (File Ops vs. File Type) |
| 67 | +- "File Ops" submenu groups cut/copy/paste/duplicate |
| 68 | +- Background panel menu: paste, new folder, new file, copy path, add to favorites |
| 69 | +- DMG/PKG/ISO/JAR: double-click opens with system; extract only via R-Menu |
| 70 | + |
| 71 | +### Git Workflow |
| 72 | +- Never git push automatically — only commit |
| 73 | +- Iakov pushes manually himself |
| 74 | +- Commit message style: short English, e.g. `"fix rename: firmlink resolve, panel tracking"` |
| 75 | + |
| 76 | +## 📁 Key Directories |
| 77 | + |
| 78 | +``` |
| 79 | +GUI/Sources/ |
| 80 | +├── App/ # Entry point, AppBuildInfo, AppToolbarContent |
| 81 | +├── States/AppState/ # Global state, selection, navigation, refresh |
| 82 | +├── Features/ |
| 83 | +│ ├── Panels/ # File panels, table, rows, ZebraBackgroundFill |
| 84 | +│ ├── Tabs/ # Tab system |
| 85 | +│ ├── Network/ # SMB/AFP discovery |
| 86 | +│ ├── ConvertMedia/ # Convert Media dialog, service, ffmpeg/ImageIO/Lottie |
| 87 | +│ └── ConnectToServer/# SFTP/FTP connectivity |
| 88 | +├── ContextMenu/ |
| 89 | +│ ├── ActionsEnums/ # FileAction, DirectoryAction, etc. |
| 90 | +│ ├── Dialogs/ # RenameDialog, HIGAlertDialog, PackDialog, etc. |
| 91 | +│ ├── Menus/ # Context menus |
| 92 | +│ └── Services/ |
| 93 | +│ ├── Coordinator/ # FileActionsHandler, DirectoryActionsHandler, ActiveDialog |
| 94 | +│ └── FileOperations/ # FileOperationsService + extensions (Delete, Rename, SymLink) |
| 95 | +├── Services/ |
| 96 | +│ ├── Archive/ # VFS, extract, repack |
| 97 | +│ └── Scanner/ # DualDirectoryScanner, FSEventsDirectoryWatcher |
| 98 | +├── FindFiles/ # Search UI and engine |
| 99 | +├── ExternalTools/ # ExternalToolRegistry, install popover, Settings pane |
| 100 | +├── MediaInfo/ # Media info panel (VLC preview migration) |
| 101 | +├── BreadCrumbNav/ # PathAutoCompleteField (NSPanel popup, click-outside dismiss) |
| 102 | +├── HotKeys/ # Keyboard shortcuts |
| 103 | +└── Settings/ # Preferences UI |
| 104 | +
|
| 105 | +Packages/ # git submodule → github.com/senatov/MiMiKits |
| 106 | +├── ArchiveKit/ |
| 107 | +├── FavoritesKit/ |
| 108 | +├── FileModelKit/ # CustomFile model |
| 109 | +├── LogKit/ |
| 110 | +├── NetworkKit/ |
| 111 | +└── ScannerKit/ |
| 112 | +``` |
| 113 | + |
| 114 | +## 🔧 Common Tasks |
| 115 | + |
| 116 | +### Add new file to project |
| 117 | +1. Create file in appropriate directory |
| 118 | +2. Edit `project.pbxproj` to add file reference and build phase |
| 119 | + |
| 120 | +### Run before commit |
| 121 | +```zsh |
| 122 | +cd /Users/senat/Develop/MiMiNavigator |
| 123 | +zsh Scripts/git_cleanup.zsh |
| 124 | +``` |
| 125 | + |
| 126 | +### Update version before build |
| 127 | +```zsh |
| 128 | +zsh Scripts/stamp_version.zsh |
| 129 | +``` |
| 130 | + |
| 131 | +### Log locations |
| 132 | +- Console: SwiftyBeaver to stdout |
| 133 | +- Sandboxed: `~/Library/Containers/Senatov.MiMiNavigator/Data/Library/Application Support/MiMiNavigator/Logs/MiMiNavigator.log` |
| 134 | +- External: `/private/tmp/MiMiNavigator.log` |
| 135 | + |
| 136 | +## ⚠️ Common Mistakes to Avoid |
| 137 | + |
| 138 | +- **Over-Engineering**: Adding "defensive" code not requested. Three similar lines > premature abstraction |
| 139 | +- **Guessing Before Reading**: Always read the file before suggesting changes |
| 140 | +- **Wrong shell**: Must use zsh, not bash |
| 141 | +- **Forgetting Packages/**: Submodule changes need separate commit |
| 142 | +- **Firmlinks**: Never trust `URL.resourceValues` for `/tmp`, `/var`, `/etc` — use FileManager fallback |
| 143 | +- **Scanner race conditions**: Always call `scanner.clearCooldown(for:)` before explicit `refreshFiles` after file operations |
| 144 | +- **Panel detection**: When both panels show same directory, `panelForPath` is ambiguous — pass `panel: PanelSide` explicitly |
| 145 | + |
| 146 | +## Dependencies |
| 147 | + |
| 148 | +- **SwiftyBeaver** — logging |
| 149 | +- **Citadel** — SSH/SFTP (orlandos-nl/Citadel) |
| 150 | +- **p7zip** — archive formats (`brew install p7zip`) |
0 commit comments