@@ -382,10 +382,18 @@ VxCoreError BundledFolderManager::DeleteFolder(const std::string &folder_path) {
382382 }
383383
384384 try {
385+ // Move content folder to recycle bin instead of permanent delete
386+ VxCoreError move_error = MoveToRecycleBin (fs::path (content_path));
387+ if (move_error != VXCORE_OK) {
388+ VXCORE_LOG_WARN (" Failed to move folder to recycle bin, falling back to delete: %s" ,
389+ content_path.c_str ());
390+ fs::remove_all (content_path);
391+ }
392+
393+ // Always permanently delete the config folder (vx.json metadata)
385394 if (fs::exists (config_path)) {
386395 fs::remove_all (fs::path (config_path).parent_path ());
387396 }
388- fs::remove_all (content_path);
389397
390398 // Write-through to MetadataStore
391399 if (auto *store = notebook_->GetMetadataStore (); store && !folder_id.empty ()) {
@@ -824,7 +832,14 @@ VxCoreError BundledFolderManager::DeleteFile(const std::string &file_path) {
824832 try {
825833 std::string content_path = GetContentPath (folder_path);
826834 fs::path fs_file_path = fs::path (content_path) / file_name;
827- fs::remove (fs_file_path);
835+
836+ // Move to recycle bin instead of permanent delete
837+ VxCoreError move_error = MoveToRecycleBin (fs_file_path);
838+ if (move_error != VXCORE_OK) {
839+ VXCORE_LOG_WARN (" Failed to move file to recycle bin, falling back to delete: %s" ,
840+ fs_file_path.string ().c_str ());
841+ fs::remove (fs_file_path);
842+ }
828843
829844 // Write-through to MetadataStore
830845 if (auto *store = notebook_->GetMetadataStore (); !file_id.empty ()) {
@@ -1541,4 +1556,80 @@ void BundledFolderManager::SyncFolderToStore(const std::string &folder_path,
15411556 config.id .c_str (), folder_path.c_str ());
15421557}
15431558
1559+
1560+ std::string BundledFolderManager::GetRecycleBinPath () const {
1561+ return ConcatenatePaths (notebook_->GetMetadataFolder (), " recycle_bin" );
1562+ }
1563+
1564+ std::string BundledFolderManager::GenerateUniqueRecycleBinName (const std::string &name) const {
1565+ fs::path recycle_bin_path (GetRecycleBinPath ());
1566+ fs::path dest_path = recycle_bin_path / name;
1567+
1568+ if (!fs::exists (dest_path)) {
1569+ return name;
1570+ }
1571+
1572+ // Extract base name and extension
1573+ std::string base_name = name;
1574+ std::string extension;
1575+ size_t dot_pos = name.find_last_of (' .' );
1576+ if (dot_pos != std::string::npos && dot_pos > 0 ) {
1577+ base_name = name.substr (0 , dot_pos);
1578+ extension = name.substr (dot_pos);
1579+ }
1580+
1581+ // Try _1, _2, _3, etc. until we find a unique name
1582+ int suffix = 1 ;
1583+ while (true ) {
1584+ std::string new_name = base_name + " _" + std::to_string (suffix) + extension;
1585+ dest_path = recycle_bin_path / new_name;
1586+ if (!fs::exists (dest_path)) {
1587+ return new_name;
1588+ }
1589+ ++suffix;
1590+ if (suffix > 10000 ) {
1591+ // Safety limit to prevent infinite loop
1592+ VXCORE_LOG_ERROR (" GenerateUniqueRecycleBinName: Too many conflicts for %s" , name.c_str ());
1593+ return base_name + " _" + std::to_string (GetCurrentTimestampMillis ()) + extension;
1594+ }
1595+ }
1596+ }
1597+
1598+ VxCoreError BundledFolderManager::MoveToRecycleBin (const std::filesystem::path &source_path) {
1599+ if (!fs::exists (source_path)) {
1600+ VXCORE_LOG_WARN (" MoveToRecycleBin: Source does not exist: %s" , source_path.string ().c_str ());
1601+ return VXCORE_ERR_NOT_FOUND;
1602+ }
1603+
1604+ fs::path recycle_bin_path (GetRecycleBinPath ());
1605+
1606+ // Ensure recycle bin directory exists
1607+ try {
1608+ if (!fs::exists (recycle_bin_path)) {
1609+ fs::create_directories (recycle_bin_path);
1610+ VXCORE_LOG_INFO (" MoveToRecycleBin: Created recycle bin at %s" ,
1611+ recycle_bin_path.string ().c_str ());
1612+ }
1613+ } catch (const std::exception &e) {
1614+ VXCORE_LOG_ERROR (" MoveToRecycleBin: Failed to create recycle bin: %s" , e.what ());
1615+ return VXCORE_ERR_IO;
1616+ }
1617+
1618+ // Generate unique name in recycle bin
1619+ std::string original_name = source_path.filename ().string ();
1620+ std::string unique_name = GenerateUniqueRecycleBinName (original_name);
1621+ fs::path dest_path = recycle_bin_path / unique_name;
1622+
1623+ // Move the file/folder to recycle bin
1624+ try {
1625+ fs::rename (source_path, dest_path);
1626+ VXCORE_LOG_INFO (" MoveToRecycleBin: Moved %s to %s" , source_path.string ().c_str (),
1627+ dest_path.string ().c_str ());
1628+ return VXCORE_OK;
1629+ } catch (const std::exception &e) {
1630+ VXCORE_LOG_ERROR (" MoveToRecycleBin: Failed to move %s: %s" , source_path.string ().c_str (),
1631+ e.what ());
1632+ return VXCORE_ERR_IO;
1633+ }
1634+ }
15441635} // namespace vxcore
0 commit comments