chore(upstream): sync upstream main#1
Conversation
…w93#854) * feat(uninstall): add per-file deselect at confirm prompt (tw93#852) Press R at the uninstall confirm prompt to open a review picker that lets you opt OUT of individual paths -- preferences, caches, system plists, or the .app bundle itself. Deselecting the .app keeps the bundle on disk and only cleans the leftover files. Reuses the existing paginated_multi_select UI; no new flag, no new command, no config knob. Closes tw93#852. * style(uninstall): re-indent keep_app block, drop bandage comment Pure indentation cleanup of the `if [[ "$keep_app" != "true" ]]` block introduced for tw93#852. Body now indents one level inside the gate so future readers see the scope correctly. Drops the `# end if keep_app != true` comment that was masking the missing indent. Zero behavior change. All uninstall tests green. * test(uninstall): satisfy shellcheck SC2016/SC2181 in review_files bats
Route sudo-required uninstall paths into the invoking user's Trash without calling sudo trash. The trash location follows the effective user, so running the trash CLI under sudo moves large app bundles into /var/root/.Trash, where macOS accounts for them as System Data instead of the real user's Trash. For paths that need admin rights, resolve the invoking user's home defensively, reject unsafe root homes, create or reuse ~/.Trash with user ownership and 700 permissions, refuse symlinked or non-directory Trash paths before privileged writes, sanitize destination names, handle conflicts with timestamp/PID/suffix names, and use sudo mv -n for the single privileged operation. After a successful move, repair ownership on the moved item on a best-effort basis so restored Trash items behave like user files. Keep the existing permanent-delete fallback when Trash routing fails, so uninstall still completes instead of silently skipping selected files. Normal user-owned paths continue to prefer the trash CLI and then Finder/AppleScript. Add regression tests with fake trash, sudo, and osascript binaries to verify sudo-required Trash deletes use sudo mv -n into the invoking user's Trash, reject symlinked Trash directories, handle destination conflicts with unique names, and never call sudo trash, trash, or osascript for sudo-required paths. Validation: bash -n lib/core/file_ops.sh; bats tests/file_ops_mole_delete.bats; scripts/test.sh passed with 756 tests, 0 failures, 15 skipped. Go tests were skipped because Go is not installed; shellcheck was skipped because shellcheck is not installed.
Pin stable updates to the resolved release tag and require downloaded Go helpers to match the release SHA256SUMS before installing.
Record optimize sudo availability once and make sudo-required tasks skip cleanly when access is denied or tests run in no-auth mode.
Avoid collecting sensitive developer data, validate bundle identifiers before path matching, and keep user-owned ByHost cleanup off sudo.
Collapse the seven-emoji icon zoo into two: 📁 for top-level directories, 👀 for hidden-space insights. The previous mix of 📋 💾 🔨 📲 🐳 📱 📥 varied in render width across terminals and added no information. A broom (🧹) was tried first but mis-signalled "all of these are cleanable", which is wrong for Xcode Archives, iOS Backups, and Old Downloads. Rename App Library to User Library to mirror System Library and avoid confusion with /Applications. Path unchanged.
write_install_channel_metadata used `[[ -n "$h" ]] && printf ...` to
optionally append the commit hash. On the stable channel the hash is
always empty, so the conditional returned 1 and propagated as the
exit code of the surrounding `{ ... } > "$tmp_file"` block, which the
caller then read as an I/O failure and warned "Could not write install
channel metadata". The metadata file was never written.
Switch to a plain `if [[ -n "$h" ]]; then printf ...; fi` so only an
actual write failure can trip the warning. Add a regression test in
tests/install_checksum.bats covering both the stable empty-hash path
and the nightly hash-present path.
Co-authored-by: unnipv <unnimonpv@gmail.com>
Adds per-file selection before uninstall removal and preserves deletion-side effects only for files the user kept selected.\n\nMaintainer patch: rebuild sudo/brew prompts after selection and cover leftover-only deselection.
Discovers app-related Group Containers through the signed Team ID plus bundle-domain prefix, keeps same-Team unrelated containers out, and broadens diagnostic report matching.\n\nMaintainer patch: rebased on the file selector flow and narrowed Team ID discovery before merge.
Preserve Gradle DSL hash cache integrity by normalizing file-level cleanup targets to the containing hash directory. Verification: - ./scripts/check.sh --format - MOLE_TEST_NO_AUTH=1 bats tests/regression.bats tests/clean_dev_caches.bats - MOLE_TEST_NO_AUTH=1 MOLE_TEST_JOBS=2 BATS_FORMATTER=tap ./scripts/test.sh
Harden uninstall scanning against PATH stat shims, avoid GUI-app-owned dotdir false positives, and add explicit zero-size purge artifact visibility. Also relax the normalize_paths_for_cleanup performance regression test threshold to avoid CI runner timing noise while still catching O(n²) regressions. Verification: - ./scripts/check.sh --format - MOLE_TEST_NO_AUTH=1 bats tests/uninstall_scan_bash32.bats tests/clean_hints.bats tests/purge.bats tests/completion.bats - MOLE_TEST_NO_AUTH=1 bats tests/regression.bats - go test ./cmd/... - MOLE_TEST_NO_AUTH=1 MOLE_TEST_JOBS=2 BATS_FORMATTER=tap ./scripts/test.sh
… or cask exists (tw93#872) (tw93#879) * fix(clean): skip orphan hint for dotdirs owned by GUI app or cask (tw93#872) `show_orphan_dotdir_hint_notice` now adds a fifth ownership gate that exempts a hidden home directory when an installed `.app` bundle or a Homebrew cask shares a name token with it. Without this, `~/.bridge` (Proton Mail Bridge live data) is flagged as orphan because there is no `bridge` binary on PATH and no LaunchAgent referencing it. The existing gates (allowlist, whitelist, `command -v`, LaunchAgents grep) only cover CLI-style owners. New helper `dotdir_has_owning_gui_app NAME`: - Scans `.app` filenames in /Applications, /Applications/Setapp, \$HOME/Applications, plus `brew list --cask` output. - Tokenizes both sides on non-alphanumeric chars, lowercases. `Proton Mail Bridge.app` -> proton, mail, bridge. `proton-mail-bridge` -> proton, mail, bridge. - Requires token length >= 4 on both sides to avoid matching `.ai-old` against `AI.app`. - Caches the token list at \$HOME/.cache/mole/installed_app_tokens_cache (5-minute TTL, same pattern as scan_installed_apps). The new gate is inserted between the LaunchAgents grep and the size calculation in `show_orphan_dotdir_hint_notice`. Tests in tests/clean_hints.bats cover: - dotdir matched by fake .app -> not flagged - dotdir matched by fake brew cask -> not flagged - dotdir with no matching app/cask -> still flagged - short app tokens (<4 chars) do not exempt the dotdir * fix(clean): use POSIX character classes in tr (shellcheck SC2018/SC2019) Replace `tr 'A-Z' 'a-z'` with `tr '[:upper:]' '[:lower:]'` in the helpers added by the previous commit. The locale-aware form is what shellcheck and the repo's check.sh require.
- merge upstream/main into origin main sync branch - resolve fork-specific Moleui URLs and README conflicts - preserve upstream uninstall and checksum fixes
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf9d61fa39
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| MOLE_SFR_USER_FILES="$_fs_all_user" | ||
| MOLE_SFR_SYSTEM_FILES="$_fs_sys" | ||
| if ! select_files_for_removal "$_fs_an"; then |
There was a problem hiding this comment.
Bypass file picker for non-interactive uninstall
When uninstall is launched without a TTY, this new selector still runs before the later dry-run/non-interactive confirmation bypass. The desktop app calls mole uninstall --dry-run --yes ... and mole uninstall --yes ... from apps/desktop/main.js via spawn, which provides a piped stdin and no terminal; _sfr_multi_select then waits in read_key for input that never arrives, so the desktop dry-run/execute flow hangs before removing or previewing anything. Non-interactive callers with closed stdin instead skip all selected apps. Please auto-select the preselected files or skip this menu when ! -t 0 || ! -t 1/--yes/dry-run GUI mode is in effect.
Useful? React with 👍 / 👎.
Summary
Tests