# Changelog ## v4.2.0 — it updates itself, and it runs without the .exe ### Automatic updates - **The app now installs new versions on its own.** It checks on startup, downloads the new `.exe` in the background, **verifies its SHA256** against the `SHA256SUMS.txt` published in the release, and installs it **when you close AppCloner**. Nothing is ever swapped underneath you while you are using it. There is a "Restart now" button if you would rather not wait, and a *Install updates automatically* switch in Preferences. - **Why an external helper does the swap.** The obvious approach, renaming the running `.exe` from inside the program, was measured on Windows 11 and **is not reliable**: two identical attempts gave different results, one renaming fine and the other failing with `WinError 32`. And in the attempt that did rename, the old process **exited 1 instead of 0** (the control run, untouched, exited 0), because a PyInstaller *onefile* executable re-launches itself as a child process **by path**. So a short PowerShell helper waits for AppCloner's PID to disappear, moves the new file over the old one, and relaunches only if asked. - **Nothing is destroyed if it fails.** The old executable stays where it is, the downloaded one stays downloaded, and the helper reopens the app either way. The outcome is written to a file the app reads on the next start, so a failed update is reported instead of leaving you thinking you are up to date. - **Nothing is installed that cannot be checked.** A download whose hash does not match the published one is deleted, not kept "just in case". A release with no `SHA256SUMS.txt` is refused. To be clear about what this protects: a corrupted or tampered download in transit, not a compromised GitHub account. - **It refuses where self-updating would be wrong**, and says why: from source (`git pull`), installed through winget (`winget upgrade`, so winget keeps its inventory straight), or installed in Program Files, where the folder is not writable. Writability is *tested* by writing a probe file, not guessed from the path. - Version comparison now pads to three numbers. Without that, `(4, 1)` sorts below `(4, 1, 0)` and a release tagged `v4.1` would have looked newer than the installed 4.1.0, offering the same update forever. - New command: `appcloner --update` checks, downloads and verifies; add `--now` to install it as soon as the process exits. ### A version that runs without the .exe - **`AppCloner.py` at the root of the project: double-click it.** For anyone whose browser blocks the executable, whose antivirus deletes it, who gets a SmartScreen warning about an unsigned binary, or whose network refuses `.exe` downloads. It checks the Python version, offers to install the two packages it needs with pip **into your user folder** after asking, hides the console before the window opens, and passes any arguments through. - Every failure ends in a dialog, never in a console that vanishes. A `Traceback` that disappears in a blink tells nobody anything. - Without `pystray` there is no tray icon but the app still opens, so a package that fails to build does not block the launcher. - Releases now also ship a `AppCloner-vX.Y.Z-python.zip` with just what you need to run it that way. ### Releasing - A `Release` workflow builds, tests, smoke-tests the exe, generates `SHA256SUMS.txt` and the Python zip, and opens a **draft** release when a `vX.Y.Z` tag is pushed. It refuses if the tag does not match `__version__`. Automatic updates depend on the exe and its checksum coming from the same run; doing that by hand invites publishing a hash that does not match the binary, which breaks every user's update at once. ## v4.1.0 — duplicating a clone, for real The whole release is about the thing people do most and that worked worst: you already have a clone set up, and you want another one. ### "Duplicate" was broken in every released version `CloneStore.duplicate` excluded `name` from the field dictionary it splatted into `Clone(...)` and then assigned it afterwards — but `Clone` declares `name` with no default, so construction raised `TypeError: missing 1 required positional argument: 'name'` before anything was created. The menu entry existed, did nothing and reported nothing. Fixed, and now covered by tests. ### Duplicating brings the account with it - **Copy the session.** The new clone can start with the original's session already inside: it opens straight into the same account, with no sign-in. This is what "duplicate" was supposed to mean, and doing it by hand (copying the profile folder) fails for reasons that are not obvious: - **Single-instance locks travel in a plain copy.** Chromium and Electron leave a `lockfile` (and `Singleton*` where present) naming the machine and PID that holds the profile; Firefox leaves `parent.lock`; every LevelDB store leaves a `LOCK`. Copied as-is, the new app thinks that profile is already in use and hands off to the live window or opens read-only. They are now skipped and the app recreates them. - **Junctions are not part of the session.** A clone's profile contains links that re-attach the app's real install folder. `copytree` copies the *contents* of a link, so duplicating a clone of an app installed under `%LOCALAPPDATA%` would have dragged the whole program inside the new profile. - **Cache is skipped by default** (opt-in checkbox), which is what makes the copy seconds instead of minutes. - Cookies survive: Chromium's cookie encryption key is protected with the *user's* DPAPI, not the folder's, so a copy between two profiles of the same Windows user decrypts fine. - **The source must be closed**, and that is now checked per *profile*, not per app: having your normal Chrome open no longer blocks duplicating a Chrome clone that is closed. The check probes the profile's own lock file. - **Real progress bar with cancel** — a browser profile is gigabytes, and an indeterminate spinner there tells you nothing. - **Copy a session between two clones that already exist** (clone menu, Duplicate, *Copy another clone's session into this one*), for when one clone has the right setup and another has the right account. ### Duplicating is where you can see it - A duplicate button on every card, and **Ctrl+D**. - **Names continue the numbering**: "Claude cuenta 4" becomes "Claude cuenta 5", "WhatsApp" becomes "WhatsApp 2". No more "X (copia) (copia)"; existing names are avoided, and stacked copy suffixes are stripped. - **Several copies at once**, with the names shown before anything is created. - **A different colour automatically** — the least-used accent of the palette, so two clones of the same app are not identical in the grid. - Duplicate from the details sheet, and duplicate a whole multi-selection. ### Also fixed - **Desktop shortcuts were reported as failures when they had been created.** The `.lnk` is saved *before* the AppUserModelID is set, and on some Windows builds that last step fails on its own (the shell object has no `SetProperty`). Its empty `catch` swallowed the exception but left `$?` false, so `powershell -Command` exited 1 and `check=True` treated the whole thing as a failure: the shortcut sat on the desktop while `shortcut_path` was stored as `null`. The result is now judged by the artefact — the file — not by the exit code. ### Other additions - **Paste an app to clone it (Ctrl+V)**, or the sidebar button. It takes both "Copy as path" (text) and a plain Ctrl+C on the icon (`CF_HDROP`, which Tk cannot read at all and made the clipboard look empty), and resolves `.lnk` shortcuts to the executable they point at. - **Ctrl+A** selects everything currently shown. - **Search covers notes and group**, not just name, executable and tags: with twenty clones of one app the notes are what you actually remember. - The details sheet says **which clone this one was duplicated from**, whether its session was copied, and **how many other clones share the same app**. - Help gained the three questions this release exists to answer, plus the full shortcut list. ## v4.0.0 — the launch engine, rebuilt This release is about the three things people actually complained about: clones that **died**, clones that **lost capabilities** the original app had, and clones that **didn't even show the app's icon**. All three had concrete root causes. ### Clones no longer die on launch - **The real executable is now launched.** The strategy was picked by looking at one executable and then a *different* one was launched. Two disguises caused it: Squirrel's `Update.exe` (what Discord and GitHub Desktop shortcuts point at) and the Squirrel **stub** — a ~350 KB `App.exe` in the install root that only relaunches the real versioned binary and exits. Launching either one meant the clone "died" a second after opening, or worse, opened with no isolation at all while the UI claimed it was reliable. All target resolution now lives in one place (`core/target.py`) and every path — flags, environment, icon, tracking — derives from the same resolved exe. - **Microsoft Store (MSIX) apps are activated properly.** Their `.exe` lives in a permission-protected folder and starting it directly can fail or strip the app's package identity. AppCloner now reads the package manifest, computes its AUMID and activates it through `IApplicationActivationManager`, which also returns the PID so the clone can still be tracked and closed. - **Startup is actually watched.** The code promised to detect a process that died instantly and never did it. Now a clone's first seconds are monitored off the UI thread and the outcome is explained: alive, *handed off* to an already-open window (exit 0 — previously reported as success while nothing opened), or dead with its exit code translated (missing DLL, needs administrator, access denied…). - Stale paths are repaired by version number rather than folder date, so an update that touches the old folder last no longer picks the wrong version. - `--user-data-dir="D:\my folder"` kept its quotes and reached the app literally, pointing it at a path that does not exist. Quoted values are now unwrapped. - A target that is not an app at all (`powershell.exe`, `cmd.exe`, `Update.exe`, `java.exe`…) is now called out instead of silently producing a clone that never opens a window. ### Clones keep the original app's capabilities - **An app installed inside `%LOCALAPPDATA%` or `%APPDATA%` no longer loses its own files.** Redirecting those variables to an empty folder hid the app's own installation from itself — the exact cause of "the clone opens but half of it is missing". Its install folder is now re-attached with a directory junction (no administrator rights needed), so the app finds everything while its session data still goes to the clone. - **WebView2 gets its own data folder.** Many modern desktop apps embed a web panel and keep the session there, so every clone was sharing one login. New clones isolate it; existing clones keep their current behaviour and can opt in from the clone panel — switching it on moves the data folder and would sign you out. - More Electron/Chromium runtimes are detected (`icudtl.dat`, `resources.pak`, `v8_context_snapshot.bin`…), so fewer apps fall back to environment redirection, which does not isolate a Chromium at all. - A profile flag you typed by hand is no longer duplicated and silently ignored. - `AppData\Local\Temp` is created, as it exists in every real Windows profile. - Your own environment variables are still applied last, but if one overrides the isolation you get told, and `Diagnostics` now shows them instead of hiding them. ### Clones look like the app they clone - **Icon extraction worked on no machine at all.** `PrivateExtractIconsW` was requested from `shell32.dll`, which does not export it — it lives in `user32.dll`. Every extraction raised `AttributeError`, was swallowed, and fell back to a blurry 32 px path or to a letter avatar. Icons now come out at 256 px. - **Store apps get their real icon.** It is not embedded in the `.exe` at all; it is declared in `AppxManifest.xml`, and the best variant (up to 256 px) is now read from the package. - **Desktop shortcuts show the app, not Python.** `IconLocation` resolved to the launcher (`pythonw.exe` / `AppCloner.exe`) for every clone, because the cached icon is a PNG and Windows only draws `.ico` there. A true multi-resolution `.ico` (16→256) is now generated per clone, with a small dot in the clone's colour so two clones of the same app are distinguishable at a glance. - Each clone gets its **own AppUserModelID**, so they no longer collapse into a single taskbar button with one icon. - The icon cache is keyed by path *plus* size and date, so it refreshes when the app updates; imported configs and restored backups no longer keep a dead icon path from another machine. ### Data safety - **A live clone's session is no longer wiped.** If the tracked process ended but the app was still running, an ephemeral clone (or `on close: wipe session`) destroyed a session in use. Now any surviving process of that app cancels the wipe. In "another Windows account" mode, where other users' processes cannot be inspected, nothing is ever wiped. - Restoring from Trash no longer loses the session: the existing profile is set aside and only discarded once the restore succeeded, and a failed move keeps the Trash copy instead of deleting both. - Junctions are removed before measuring, packaging, moving or deleting a profile, so a clone's size, its backup `.zip` and its Trash copy never swallow the app's whole installation. (`os.path.islink()` returns **False** for junctions.) - `Clear cache` refuses to run while the clone is open, no longer deletes `Service Worker` / `CacheStorage` (which hold app state, not cache), and now reaches every Chromium profile instead of only `Default`. - Deleting a clone waits for its process to really exit and removes its scheduled task, which otherwise threw an error every day at its hour. - The event log is written under a lock, trimmed atomically and only when it grows, instead of rewriting the whole file on every single event. ### Honesty and diagnosis - **"Revisar y reparar"** (clone menu): fixes the path, re-extracts the icon, regenerates shortcuts and reports the isolation method and what it found. - The isolation checker no longer declares victory because eight files exist. For apps with a profile flag it looks for the app's actual session data; it separates "not isolated" from "no data yet"; and it says plainly when folder-based checking cannot confirm anything. - `--help` and `--version` now print help instead of opening the manager window. - New tests cover the blind spot that let all of this through: the suite checked that the real executable was *found*, never that it was the one *launched*. ## v3.1.0 - Refreshed visual design: soft card shadows, gradient rails, gradient title underline, subtle gradient background, crisp icons, richer avatars. - Default UI language is now English (still switchable to 5 more languages). - "Support the project" button and donation links. ### Hardening (bugs, data-loss and security) - Data safety: portable `.exe` now stores data in `%LOCALAPPDATA%\AppCloner` (auto-migrated) so moving/updating the exe no longer loses clones; sending a running clone to Trash no longer destroys its profile on a failed move; profiles/templates/settings are written atomically with a `.bak` fallback. - Security: fixed a PowerShell command-injection via clone name in toast notifications; restore now blocks zip-slip path traversal in backups; system binaries (powershell/taskkill/cipher/schtasks) are invoked by absolute path; the access PIN is now enforced on the CLI/shortcut launch path too. - Isolation: Sandboxie mode uses a separate box per clone; the "other Windows account" mode uses the target account's own profile (no environment leak); Discord/Squirrel shortcuts resolve to the real app exe; the isolation checker no longer counts Temp files as proof of isolation. - Stability: the clone list is written under a lock (no more corruption from background jobs racing the poll); process detection validates the PID's image (no killing an unrelated process after PID reuse); disk-size scans run off the UI thread; single-instance guard prevents two managers clobbering the store. - UX: clone cards respond to clicks across the whole card; Delete no longer fires while typing in search; permanent Trash deletion asks for confirmation. - Packaging: version unified to 3.1.0 across pyproject/Inno/winget; CI smoke-tests the built exe and publishes SHA256SUMS; dependency versions capped. ## v3.0.0 Big expansion across 24 improvement areas. - Isolation: Sandboxie-Plus mode, launch under another Windows account, and a real per-clone isolation checker. - UI: third view (icons), groups with headers, multi-select with bulk actions, and a much larger clone context menu. - First run: welcome wizard that detects apps and creates suggested clones. - Accessibility: UI scale, high contrast, reduce motion, Windows accent color. - Ease: "Clone with AppCloner" in File Explorer, Trash with restore. - Automation: launch profiles, scheduled openings (Task Scheduler), on-close actions, CLI (`--launch`, `--profile`, `--clone`). - Windows integration: system tray, native notifications, monitors. - Reliability: event log, config backup and recovery. - Security: per-clone PIN, EFS profile encryption, guest (ephemeral) clone. - Storage: per-clone disk size, clear cache, limit warning. - Backups: export/restore a clone with its session as `.acbackup`. - Auto-update: notice when a new GitHub release exists. - Distribution: Inno Setup installer, winget manifest, code-signing hook. - Monitoring: RAM and process count per clone, total usage time. - Windows: open on a specific monitor, remember window position/size. - Network: proxy and user-agent per clone (browsers). - Templates: create clones from a base config; save a clone as a template. - Organization: groups, archive, reorder. - Quality: pytest tests, GitHub Actions CI, ruff. - Community: shareable compatibility recipes, issue templates. ## v2.0.0 Professional redesign (light/dark/system theme), ~25 features, "sometimes won't open" fix, 6 languages, and Microsoft Store app support (Claude). ## v1.0.0 First version: folder/flag cloning, dark UI, packaged .exe.