Skip to content

feat: send a deleted bot's or crew's folder to the Recycle Bin when asked - #60

Merged
httpsphl merged 11 commits into
mainfrom
feat/delete-recycle
Sep 30, 2026
Merged

httpsphl merged 11 commits into
mainfrom
feat/delete-recycle

Conversation

@httpsphl

Copy link
Copy Markdown
Owner

Top of the stack: on #58, which is on #56, which is on #54 and #55. Merge those first, with merge commits; this PR's own commits are the last four, from feat(platform): move a folder to the Recycle Bin, never deleting it for good.

What

The delete confirmation gets an unchecked box, "Move this folder to the Recycle Bin" (for a crew, "Move the crew's folders to the Recycle Bin"). Left alone, nothing changes: the folder stays. Checked, the folder Botloft made goes to the Windows Recycle Bin, where it can still be got back.

  • What goes: for a bot, its own folder. For a crew, the crew's folder in Botloft, whole: shared and every bot's folder. A work folder the owner chose is never moved; if it was chosen inside the crew's folder, nothing is moved and the app says why.
  • Daemon: bots.delete and crews.delete take recycleFolder. The method answers at once, as before. The folder moves afterwards, off the server's workers, and is tried again for up to 10 s while the process that was just killed still holds its files. folder.recycled {path, error} tells the apps how it ended.
  • Never deleted for good. The move uses the shell's IFileOperation. Without being allowed to ask, the shell destroys what the bin cannot take, so a progress sink aborts any item that arrives without TSF_DELETE_RECYCLE_IF_POSSIBLE. What cannot go to the bin stays where it is, and the owner is told.
  • App: the box, the text of the confirmation changing with it (the crew's shows the crew's own folder instead of shared), and a notice if the folder could not go: "The folder … did not go to the Recycle Bin and is still there", with the reason. The Archived list in Settings gets the box too, since it uses the same confirmation.
  • One new direct dependency, windows-core, already in the lock file: the code windows::core::implement writes names it. Two more features of windows (Win32_UI_Shell, Win32_UI_Shell_Common).
  • Spec 5, 7.6, 11.2, 11.3, 14 (what was seen on Windows 11) and 15.1.

Tests

  • platform/windows/recycle/tests.rs, against the real Recycle Bin on Windows 11 25H2: a folder goes whole and is found in the bin's $I record with its files; a folder with paths past 260 characters goes whole, with its deepest file; a folder with a file held open fails and stays as it was, then goes once the file is let go; a missing folder is an error. Each test takes its own folder out of the bin again, so a run leaves nothing behind (checked: no leftovers after the runs).
  • crates/botloftd/tests/delete_folders.rs, with a fake trash: the bot's folder goes and folder.recycled says so; without the option nothing is moved or said; a folder in use is tried again; a folder the bin refuses stays, is not tried again, and the bot is deleted all the same; a crew's folder goes whole while the owner's own work folder stays; a crew whose chosen work folder is inside its folder keeps everything.
  • features/bots/delete.test.tsx, with FakeBotloft: the box is off by default and the call carries no option; checked, the text changes and the call asks for it; the notice when the folder could not go; the crew's folder and the chosen-work-folder wording.
  • cargo fmt, clippy -D warnings, cargo test --workspace and pnpm check (213 tests) pass.

Checked in the preview (pnpm dev, FakeBotloft, Portuguese): the box in the confirmation and its text changing.

Still to see with real Claude Code

With the dev daemon and a real bot that has worked in its folder:

  • Delete it in the middle of a turn with the box checked: the folder leaves %USERPROFILE%\Botloft\<crew>\ within a few seconds, shows up in the Recycle Bin under its name, and "Restore" puts it back.
  • The same for a crew with two running bots.

Delete is the last action of the bot's menu (header and right-click) and of the crew's menu. The confirmation names the bot or crew and says what goes (the conversation, routines and tasks, for good) and what stays (the folder, with its path). A message from a bot that left, archived or deleted, reads as from a bot no longer in the crew.
The other lists leave archived crews and bots out, so nothing showed them. archive.list returns both, the latest archived first, for the app to list and delete.
Settings gets an Archived part: the crews and the bots the owner archived, which the rest of the app does not show, with the same delete confirmation as the menus. The confirmation is now a component of its own (DeleteBot, DeleteCrew) and says "leaves" instead of "stops now" for what was already stopped.
…or good

With the shell's IFileOperation on a thread of its own (it needs a single-threaded apartment). A progress sink aborts any item the shell would destroy instead of recycling, so what the bin cannot take stays where it is. The tests use the real Recycle Bin, check the folder is in it and take it out again.
…n when asked

bots.delete and crews.delete take recycleFolder. The method answers at once; the folder moves afterwards, off the server's workers, tried again while the process that was just killed still holds its files, and folder.recycled tells the apps how it ended. Only a folder under the workspaces goes, and never one that holds a work folder the owner chose.
… Recycle Bin

Unchecked by default: the folder stays. Checked, the confirmation says the folder goes to the Recycle Bin, where it can still be got back, and a notice tells the owner if it could not go.
The bin records the long path, and the temporary folder of the CI runner comes in the short one (RUNNER~1), so the tests did not find the folder they had just moved.
@httpsphl
httpsphl enabled auto-merge September 30, 2026 17:23
@httpsphl
httpsphl merged commit 4556340 into main Sep 30, 2026
3 checks passed
@httpsphl httpsphl mentioned this pull request Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant