Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/windows-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ jobs:
dotnet-version: 10.0.x
- name: Test core library
run: dotnet test tests/Meridian.Core.Tests/Meridian.Core.Tests.csproj --configuration Release
- name: Test portable ZIP packaging
shell: pwsh
run: ./scripts/test-packaging.ps1

app-build:
name: Build Windows 11 (${{ matrix.architecture }})
Expand Down Expand Up @@ -66,6 +69,9 @@ jobs:
New-Item -ItemType Directory -Force -Path $out | Out-Null
$publishPath = (Resolve-Path $publish).Path
$outputPath = (Resolve-Path $out).Path
foreach ($state in @('meridian-portable.flag', 'data')) {
if (Test-Path -LiteralPath (Join-Path $publishPath $state)) { throw "Installer input contains portable state: $state" }
}
$iscc = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe"
& $iscc "packaging/Meridian.iss" "/DPublishDir=$publishPath" "/DOutputDir=$outputPath" "/DAllowedArch=${{ matrix.inno_arch }}"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
Expand All @@ -78,6 +84,13 @@ jobs:
if-no-files-found: error
retention-days: 14

- name: Mark portable publish output
shell: pwsh
run: |
$publish = "src/Meridian.App/bin/${{ matrix.architecture }}/Release/net10.0-windows10.0.22000.0/${{ matrix.runtime }}/publish"
$marker = Join-Path $publish 'meridian-portable.flag'
[IO.File]::Open($marker, [IO.FileMode]::CreateNew).Dispose()

- name: Upload portable publish output
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ These features are **implemented on the main development branch**. They are not
| **Favorites groups** | Sidebar favorites can be filed into named groups: right-click a favorite → **Move to group** to file it, create a group, or move it back to the ungrouped favorites. Group headers collapse and expand (remembered between sessions); right-click a header to create, rename, or delete a group — deleting a group never deletes its favorites, which return to the ungrouped list. Favorites saved before groups existed simply appear ungrouped. |
| **Folder tree** | Each pane has an optional folder tree (the **Tree** toggle beside the layout buttons): a ~260px column rooted at the current drive, folders only, loaded as you expand it. It follows the pane — expanding to and selecting the current folder after every navigation — selecting a folder in the tree opens it in the pane, and it accepts drops like the other targets. On/off is remembered per pane. |
| **Drive inspection and eject** | Right-click a sidebar drive → **Inspect drive…** for its volume label, type, file system, capacity, and free space, exactly as Windows reports them. Removable drives also offer **Eject**, which asks Windows to safely remove the drive and reports in plain words when a program is still using it. |
| **Live folder refresh** | An open folder refreshes itself when its contents change on disk — a file saved by an editor, created by another program, renamed, or deleted — without pressing F5. Watching is done by the bundled **WatchKit** library (`watch_kit.dll`, shipped beside `Meridian.exe`), using native Windows change notifications with an automatic polling fallback; changes are coalesced, so a burst of activity refreshes the pane once. If the library is unavailable (including the ARM64 build, which carries no x64 DLL), folders simply behave as before, with manual refresh. While a transfer job is running, watch refreshes stand down and the panes refresh when the job finishes, as they already did. |
| **Live folder refresh** | Windows directory notifications refresh open folders when files are created, saved, renamed, or deleted. Bursts share a refresh, and an overflow triggers a reload because some changes may have been missed. If notifications are unavailable, press F5 to refresh manually. Watch refreshes stand down while a transfer runs, and affected panes refresh when it finishes. |
| **Image thumbnails** | In Grid and Tiles views, thumbnails for BMP, PPM, PNG, and JPEG files are decoded by the bundled **ThumbKit** library (`thumb_kit.dll`, shipped beside `Meridian.exe`) and cached on disk under `%LOCALAPPDATA%\Meridian\thumbcache`, so they survive restarts. Every other format — and any file ThumbKit cannot decode, such as a progressive JPEG — uses the Windows shell thumbnails exactly as before. |
| **Breadcrumb path bar** | Each pane's path is a breadcrumb bar: one button per level from the drive root (or network share) down to the current folder — click any level to jump there. Clicking the empty stretch of the bar, or pressing `Ctrl+L`, swaps in a text box holding the full path: Enter opens it, Escape returns to the breadcrumbs. Long folder names compress with an ellipsis and show their full path as a tooltip. Segments accept drops (onto that level's folder); the bar's empty stretch drops into the current folder. |
| **Preview block** | Each pane has a preview block at its bottom, replacing the old right-side details panel: a large preview of the selected item (an image preview, the opening of a text file, or a folder treatment with its measured size and counts), its name, type, created and modified dates, and size, plus photo details and the "Opens in" app where they exist. With nothing selected it describes the current folder. Its header line always shows the folder's item count and total size — folders count only once measured, never walked just for the line — and the selection's count and size while anything is selected. Each pane's block collapses on its own chevron and remembers its state; a details panel you had open becomes both blocks expanded. |
Expand Down Expand Up @@ -196,7 +196,7 @@ See the full [innovation-first roadmap](docs/ROADMAP.md).
- **Windows displays an unknown-publisher warning?** The preview installer is unsigned. Verify the repository and build provenance before deciding whether to run it; don't disable system-wide security protections.
- **App does not start?** Confirm Windows 11 build 22000+, choose the architecture matching your device, extract the *entire* portable artifact before launching `Meridian.exe`, and include the OS build, architecture, artifact run URL, and exact error when reporting a bug.
- **A file operation fails?** Check source/destination access and collisions. Meridian intentionally refuses known overwrites; after a partial batch, inspect the destination before retrying. Do not delete a `.meridian-*.partial` path before determining whether it contains recoverable data.
- **Portable settings?** The current workspace file is stored under `%LOCALAPPDATA%\\Meridian\\workspace.json`; a completely self-contained portable settings mode is not yet verified.
- **Portable workspaces?** Extract the portable ZIP to a writable folder. Its `meridian-portable.flag` keeps session and named workspace files in the sibling `data` folder. Other preferences and diagnostics still use per-user locations.

See [known limitations and verification status](docs/VERIFICATION_REPORT.md), [security reporting](docs/SECURITY.md), and [contributing instructions](docs/CONTRIBUTING.md).

Expand Down Expand Up @@ -273,7 +273,7 @@ Automated builds are not a substitute for testing actual devices, Windows shell
- **Copied or moved something?** Check Transfer History in the Transfers strip — many finished copies and moves can be undone from there while their results are unchanged. Renames have no undo; inspect both locations before manually reversing one.
- **Copy failed?** Check for `.meridian-*.partial` leftovers; verify contents and that no operation is using them before removing anything.
- **Startup failed?** Check `%LOCALAPPDATA%\Meridian\last-error.log` if present and keep the complete published folder, including `Meridian.pri`.
- **Settings/privacy:** `%LOCALAPPDATA%\Meridian\workspace.json` stores paths, bookmark/tab labels and active-tab selection. Portable copies also use this location. Diagnostics can contain paths; see the [user guide](docs/USER_GUIDE.md#local-data-and-privacy).
- **Settings/privacy:** Session state stores paths, bookmark/tab labels and active-tab selection. Installed and unmarked copies use `%LOCALAPPDATA%\Meridian`. The marked portable ZIP keeps session and named workspaces in its sibling `data` folder. Diagnostics can contain paths. See the [user guide](docs/USER_GUIDE.md#local-data-and-privacy).

Uninstalling Meridian does **not** reverse file operations.

Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Workspace tabs are paired left/right folder locations; switching tabs refreshes

## Persistence and diagnostics

`src/Meridian.App/Services/WorkspaceStore.cs` stores `%LOCALAPPDATA%\Meridian\workspace.json`: left/right locations, bookmark names/paths, paired tab names/locations and active-tab index. Drop Shelf, sort/filter settings, durable operation history and alternate layouts are not included. Installed and portable copies share this per-user location.
`src/Meridian.App/Services/WorkspaceStore.cs` stores `workspace.json`: left/right locations, bookmark names/paths, paired tab names/locations and active-tab index. Drop Shelf, sort/filter settings, durable operation history and alternate layouts are not included. Installed and unmarked copies use `%LOCALAPPDATA%\Meridian`. For a marked portable ZIP, workspace storage routes session and named workspace files to the sibling `data` folder. It validates bounded legacy input before copying, publishes without replacing an existing file, and records one receipt per file. Other stores keep their existing paths.

Writes serialize to a unique temporary sibling, then replace the preferences file. This preference replacement is separate from no-overwrite user file operations. A semaphore serializes writes in one store instance, not across processes. Missing/malformed/unreadable state falls back where handled; unavailable tab paths can also produce navigation errors. UI persistence is best-effort, without a versioned migration database or cross-process transaction guarantee. Loading is capped at 1 MiB, JSON depth 16, 128 tabs and 512 bookmarks; invalid entries, relative paths, control characters and excessive labels are rejected before UI restoration. Saving validates the snapshot and encoded size before replacing the old file; save warnings are retained by tab/bookmark actions. Tests compile the actual UI-independent workspace-store source into the core test project and use isolated files; these are not interactive UI tests.

Expand Down
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Folder panes use filesystem change notifications and combine bursts into a refresh. If live watching is unavailable, use Refresh to reload the folder.
- The portable ZIP keeps session and named workspace files beside the app under `data`. On first use it copies valid legacy files when the corresponding portable files are absent.

- Batch rename with preview and undo: select multiple files or folders and rename them all at once from the Rename command or F2. Every new name is checked before anything is renamed, collisions are flagged in the preview, and the whole batch runs as a transfer job in the Transfers queue — progress shows in the strip, ordinary item errors do not stop the others; a persistence or recovery failure stops the batch, and every finished rename can be undone from Transfer History.
- Color tags: mark files and folders with a colored indicator (red, orange, yellow, green, blue, purple, gray or none) from the right-click menu in either pane. Tags persist across sessions and travel with the item row wherever it is shown.

Expand Down
2 changes: 1 addition & 1 deletion docs/COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Operating system

- **Windows 11, build 22000 or newer.** Windows 10 is not supported: Meridian uses WinUI 3 windowing and APIs that assume the Windows 11 baseline.
- **Architectures:** x64 and ARM64. Both are built by CI; the x64 build is the one exercised by the published startup smoke test. On ARM64, the bundled WatchKit/ThumbKit libraries are x64 binaries and are not loaded — folder watching falls back to polling and thumbnails come from the Windows shell, with no other feature difference.
- **Architectures:** CI builds x64 and ARM64. The published startup smoke test exercises x64. Live folder refresh uses Windows notifications through .NET on either architecture, with manual refresh available if the watcher fails. ARM64 uses Windows shell thumbnails because the bundled ThumbKit DLL is x64. ARM64 runtime acceptance remains open.
- **Privileges:** none. The installer and the program run per-user with no administrator rights.

## Files and locations
Expand Down
2 changes: 1 addition & 1 deletion docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ What Meridian does today, on the current release. The [user guide](USER_GUIDE.md
- **Columns layout** — an optional Miller-columns view per pane, alongside Details, Grid, and Tiles.
- **Breadcrumb path bar** — click any level to jump there, `Ctrl+L` or a click on the empty stretch to type a path instead; segments accept drops.
- **Home page** — drives with usage bars and the standard Places, shown per pane.
- **Live folder refresh** — open folders update themselves when their contents change on disk (WatchKit, with a polling fallback).
- **Live folder refresh** — Windows directory notifications update open folders. Press F5 where notifications are unavailable.
- **Image thumbnails** in Grid and Tiles views (ThumbKit for BMP/PPM/PNG/JPEG, the Windows shell for everything else), cached on disk.
- **Listing controls** — per-pane filter and sort; find in pane (`Ctrl+F`) with a match-position readout; toggles for file extensions and hidden items; hide rules by name pattern (`*.tmp`, `.bak`, `Thumbs.db`) from Settings.
- **Header readouts** — the active pane's path and its drive's free space, plus a clipboard chip naming what the clipboard holds for pasting.
Expand Down
8 changes: 6 additions & 2 deletions docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ Run the Setup program. It installs per-user into `%LOCALAPPDATA%\Programs\Meridi

## Portable

Extract the zip anywhere and run `Meridian.exe`. Extract the *whole* zip: `Meridian.exe` needs the files beside it (including `watch_kit.dll` and `thumb_kit.dll`) in the same folder.
Extract the whole zip and run `Meridian.exe` from the extracted folder. Keep the supplied files together, including `thumb_kit.dll` in the x64 build.

Extract the release ZIP or the CI portable artifact to a writable folder and keep `meridian-portable.flag` beside the executable. Manual developer publish output is unmarked and uses the installed workspace location.

## Your data

Settings, the saved workspace, scripts, the thumbnail cache, and logs live under `%LOCALAPPDATA%\Meridian` for both the installed and portable builds. See [MIGRATION](MIGRATION.md) for what happens to it across versions.
Marked portable builds keep session and named workspaces in the sibling `data` folder. Installed and unmarked builds keep both files under `%LOCALAPPDATA%\Meridian`. Settings, scripts, the thumbnail cache, and logs use their existing per-user locations in either mode. See [MIGRATION](MIGRATION.md) for how to preserve this data across versions.

Run one Meridian process per portable folder when saving workspaces. Workspace writes are coordinated within one process. Separate processes can overwrite one another's later edits, as they can with installed state.

## Uninstall

Expand Down
4 changes: 3 additions & 1 deletion docs/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ Upgrading is installing the new build over the old one (or replacing the portabl
- **Scripts** in `%LOCALAPPDATA%\Meridian\Scripts` are yours: the bundled starter pack is seeded only when the folder is first created and is never overwritten by an upgrade. The KK starter file `KK\Export\CusPSVars.xml` is created only when missing.
- **Caches** (folder sizes, thumbnails) are disposable by design; any version may rebuild them.

For the marked portable ZIP, keep the sibling `data` folder when updating or moving the application. Each workspace file can be imported once from the previous per-user location if the corresponding portable file is missing and the legacy file is valid. Meridian keeps the original legacy bytes and does not replace existing portable workspace files during import. Keep the migration receipts beside the workspace files to preserve the import decision across resets.

## Moving to a new PC

Copy `%LOCALAPPDATA%\Meridian` to the same place on the new PC to bring settings, workspace, and scripts along. Paths that do not exist on the new machine are skipped gracefully.
Copy the marked portable application and its sibling `data` folder together to move its workspace files. Copy `%LOCALAPPDATA%\Meridian` to the same place on the new PC to bring settings, scripts, and installed workspace files along. Paths that do not exist on the new machine are skipped gracefully.

## Downgrading

Expand Down
2 changes: 1 addition & 1 deletion docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Startup writes a milestone log to `%LOCALAPPDATA%\Meridian\startup.log`; each li

## A folder does not refresh by itself

Live refresh uses the bundled WatchKit library with a polling fallback. While a transfer is running, refreshes pause and the panes update when the job finishes. Press `F5` to refresh manually at any time.
Live refresh uses Windows directory notifications. If a folder cannot be watched or its watcher stops, press `F5` to refresh manually. During a transfer, the affected panes refresh when the job finishes.

## Windows warns about an unknown publisher

Expand Down
4 changes: 3 additions & 1 deletion docs/USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ Foresight, Consequence Engine contracts and Storage Reclaimer inventory/planning
| `%LOCALAPPDATA%\Meridian\last-error.log` | Most recent successfully recorded unhandled/startup exception as bounded JSON (128 KiB maximum), with UTC timestamp and truncation indicators. Replaced on the next successful record; failed logging can leave an older record. Not a full operation journal. Can include local paths |
| In memory | Drop Shelf and transient operation results; not restored after restart |

Portable and installed copies use the same per-user state location. There is no implemented telemetry or mandatory account. Local/UNC paths can cause normal Windows network filesystem access, and opening a file delegates to its configured application; offline-first does not mean every OS or external handler is network-isolated. Review diagnostics before sharing them. Close Meridian and back up `workspace.json` before removing it to reset saved state. Uninstall does not reverse file operations or promise removal of per-user preferences/logs.
The portable ZIP contains `meridian-portable.flag` beside the executable. Keep it in place and extract to a writable folder. Meridian saves `workspace.json` and `named-workspaces.json` under the sibling `data` directory. On first use, it can copy valid legacy workspace files from the per-user location when the corresponding portable file is absent. It leaves the original files in place. Keep the migration receipts in `data` to prevent reimporting legacy state after a reset. If state is unreadable or the folder is blocked, Meridian reports the problem and keeps workspace writes in the portable location. Back up unreadable state before repairing it. Installed builds, developer builds, and unmarked copies continue to use the per-user workspace location.

Other portable settings, caches, and diagnostics continue to use their existing locations. Meridian has no telemetry or mandatory account. Local/UNC paths can cause normal Windows network filesystem access, and opening a file delegates to its configured application. Review diagnostics before sharing them. Close Meridian and back up `workspace.json` before removing it to reset saved state. Uninstall does not reverse file operations or promise removal of per-user preferences or logs.

## Troubleshooting and recovery

Expand Down
Loading
Loading