Skip to content

Commit 8864d98

Browse files
committed
refactor: remove session deletion features
1 parent 2060d5d commit 8864d98

68 files changed

Lines changed: 150 additions & 4829 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ across `src-tauri/src/{providers,provider,indexer.rs,db,models.rs}` and
6060
for its own fields. Provider identity and metadata are bridged through a
6161
`Provider` enum + descriptor (`provider/`), so **adding a provider is a
6262
cross-layer change**, not just a parser: enum + catalog + Tauri asset-scope
63-
allowlist + frontend provider type + theme/snapshot fallback + resume/trash
63+
allowlist + frontend provider type + theme/snapshot fallback + resume
6464
behavior + tests. Exhaustive `match` on `Provider` makes the compiler surface
6565
most of these.
6666
- **Indexing** (`indexer.rs`) is incremental: providers short-circuit unchanged

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Your data stays local. SessionView builds a local index for search and analytics
3838
- **Search without digging through folders**: global full-text search plus in-session find.
3939
- **Understand the work**: token timelines, tool-call mix, context/cache pressure, cost trends, and model breakdowns.
4040
- **Resume fast**: reopen a session in the matching terminal agent when the source tool supports it.
41-
- **Keep history tidy**: rename, favorite, export, trash/restore, hide noisy folders, and manage batches.
41+
- **Keep history organized**: rename, favorite, export, and hide noisy folders.
4242
- **Stay keyboard-friendly**: navigate tabs, panes, search, and common actions without leaving the keyboard.
4343

4444
## Session Analytics
@@ -68,7 +68,7 @@ When a tool exposes enough information, SessionView can also resume the selected
6868
Grab the latest build from [**Releases**](https://github.com/tyql688/sessionview/releases):
6969

7070
| Platform | File |
71-
|----------|------|
71+
| ---------- | ------ |
7272
| macOS | `.dmg` |
7373
| Windows | `.exe` (NSIS installer) |
7474
| Linux | `.deb` / `.AppImage` |

README.zh-CN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ AI 编程工具会在你的机器上留下很多有价值的上下文:决策
3838
- **不用翻目录也能搜索**:全局全文搜索,加上当前会话内查找。
3939
- **看懂一次工作的形状**:Token 时间线、工具调用分布、上下文/缓存压力、成本趋势和模型拆分。
4040
- **快速恢复现场**:源工具支持时,可以直接在对应终端代理中继续会话。
41-
- **整理历史**:重命名、收藏、导出、回收站/恢复、屏蔽吵闹目录和批量操作
41+
- **整理历史**:重命名、收藏、导出和屏蔽吵闹目录
4242
- **键盘友好**:标签页、分栏、搜索和常用动作都能用键盘完成。
4343

4444
## 会话分析
@@ -68,7 +68,7 @@ SessionView 当前读取 Claude Code、Codex CLI、Antigravity、Kimi Code、Cur
6868
[**Releases**](https://github.com/tyql688/sessionview/releases) 下载最新构建:
6969

7070
| 平台 | 文件 |
71-
|------|------|
71+
| ------ | ------ |
7272
| macOS | `.dmg` |
7373
| Windows | `.exe`(NSIS 安装包) |
7474
| Linux | `.deb` / `.AppImage` |

src-tauri/src/commands/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ mod session_tail;
44
mod sessions;
55
mod settings;
66
mod terminal;
7-
pub mod trash;
87
mod usage;
98

109
use std::collections::{HashMap, HashSet};
@@ -53,7 +52,6 @@ pub use search::*;
5352
pub use sessions::*;
5453
pub use settings::*;
5554
pub use terminal::*;
56-
pub use trash::*;
5755
pub use usage::*;
5856

5957
pub(crate) fn load_session_detail_for_tests(

src-tauri/src/commands/sessions.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ use crate::db::Database;
99
use crate::error::{CommandError, CommandResult};
1010
use crate::models::{Message, Provider, SessionDetail, SessionMeta, TokenTotals};
1111
use crate::services::load_cancel;
12+
use crate::services::load_session_meta;
1213
use crate::services::session_view::{
1314
build_session_turn_outline, session_window_bounds, subagent_meta_title, with_load_guard,
1415
LoadRequest, SessionTurnOutline,
1516
};
16-
use crate::services::{load_session_meta, SessionLifecycleService};
1717

1818
use super::session_tail::try_tail_fast_path;
1919
use super::AppState;
@@ -378,17 +378,6 @@ pub async fn get_child_session_counts(
378378
.map_err(CommandError::from)
379379
}
380380

381-
#[tauri::command]
382-
pub async fn delete_session(session_id: String, state: State<'_, AppState>) -> CommandResult<()> {
383-
let state = state.inner().clone();
384-
tokio::task::spawn_blocking(move || {
385-
SessionLifecycleService::new(&state.db).purge_session(&session_id)
386-
})
387-
.await
388-
.context("task join error")?
389-
.map_err(CommandError::from)
390-
}
391-
392381
#[tauri::command]
393382
pub async fn rename_session(
394383
session_id: String,

src-tauri/src/commands/trash.rs

Lines changed: 0 additions & 101 deletions
This file was deleted.

src-tauri/src/db/queries/sessions.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,6 @@ impl Database {
170170
Ok(out)
171171
}
172172

173-
pub(crate) fn count_sessions_for_source(
174-
&self,
175-
provider_key: &str,
176-
source_path: &str,
177-
) -> Result<u64, rusqlite::Error> {
178-
let conn = self.lock_read()?;
179-
conn.query_row(
180-
"SELECT COUNT(*) FROM sessions WHERE provider = ?1 AND source_path = ?2",
181-
params![provider_key, source_path],
182-
|row| row.get(0),
183-
)
184-
}
185-
186173
pub(crate) fn provider_session_counts(&self) -> Result<HashMap<String, u64>, rusqlite::Error> {
187174
let conn = self.lock_read()?;
188175
let mut stmt = conn.prepare("SELECT provider, COUNT(*) FROM sessions GROUP BY provider")?;

src-tauri/src/db/sync.rs

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,6 @@ fn should_delete_provider_snapshot(
221221
current_count <= 10 || (alive_count as f64 / current_count as f64) > 0.5
222222
}
223223

224-
fn should_delete_source_snapshot(current_count: u64, scan_count: u64) -> bool {
225-
scan_count == 0 || current_count <= 10 || (scan_count as f64 / current_count as f64) > 0.5
226-
}
227-
228224
impl Database {
229225
pub fn sync_provider_snapshot(
230226
&self,
@@ -279,43 +275,6 @@ impl Database {
279275
})
280276
}
281277

282-
pub(crate) fn sync_source_snapshot(
283-
&self,
284-
provider: &Provider,
285-
source_path: &str,
286-
sessions: &[ParsedSession],
287-
) -> Result<(), rusqlite::Error> {
288-
let provider_key = provider.key().to_string();
289-
let ids: HashSet<String> = sessions
290-
.iter()
291-
.map(|parsed| parsed.meta.id.clone())
292-
.collect();
293-
294-
let current_count = self.count_sessions_for_source(&provider_key, source_path)?;
295-
let scan_count = sessions.len() as u64;
296-
// For single-source sync, scan_count==0 is a valid signal (file deleted).
297-
// Only apply ratio guard when both sides are non-zero.
298-
let should_delete = should_delete_source_snapshot(current_count, scan_count);
299-
300-
if !should_delete {
301-
log::warn!(
302-
"provider {provider:?} source {source_path:?} scan returned {scan_count} sessions but DB has {current_count}, skipping destructive sync");
303-
}
304-
305-
self.with_transaction(|conn| {
306-
upsert_parsed_sessions_on(conn, sessions)?;
307-
308-
if should_delete {
309-
delete_missing_sessions_for_source(conn, &provider_key, source_path, &ids)?;
310-
conn.execute(
311-
"DELETE FROM favorites WHERE session_id NOT IN (SELECT id FROM sessions)",
312-
[],
313-
)?;
314-
}
315-
Ok(())
316-
})
317-
}
318-
319278
pub(crate) fn rename_session(&self, id: &str, new_title: &str) -> Result<(), rusqlite::Error> {
320279
let conn = self.lock_write()?;
321280
conn.execute(
@@ -365,16 +324,6 @@ impl Database {
365324
Ok(())
366325
}
367326

368-
/// Delete this session and all its children from DB.
369-
pub(crate) fn delete_session(&self, id: &str) -> Result<(), rusqlite::Error> {
370-
let conn = self.lock_write()?;
371-
conn.execute("DELETE FROM favorites WHERE session_id IN (SELECT id FROM sessions WHERE parent_id = ?1)", params![id])?;
372-
conn.execute("DELETE FROM sessions WHERE parent_id = ?1", params![id])?;
373-
conn.execute("DELETE FROM favorites WHERE session_id = ?1", params![id])?;
374-
conn.execute("DELETE FROM sessions WHERE id = ?1", params![id])?;
375-
Ok(())
376-
}
377-
378327
/// Replace all token stats for a session. Called during indexing.
379328
/// Deletes existing rows first, then inserts new per-(date, model) aggregates.
380329
/// Also refreshes the denormalized totals on `sessions` so list/search

src-tauri/src/db/sync/tests.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,6 @@ fn provider_snapshot_delete_guard_counts_preserved_sources_as_alive() {
6868
));
6969
}
7070

71-
#[test]
72-
fn source_snapshot_delete_guard_treats_empty_scan_as_deleted_file() {
73-
assert!(super::should_delete_source_snapshot(100, 0));
74-
}
75-
76-
#[test]
77-
fn source_snapshot_delete_guard_uses_ratio_for_non_empty_scans() {
78-
assert!(super::should_delete_source_snapshot(100, 51));
79-
assert!(!super::should_delete_source_snapshot(100, 50));
80-
}
81-
8271
#[test]
8372
fn replace_token_stats_clears_existing_rows_when_empty() {
8473
let dir = TempDir::new().unwrap();

src-tauri/src/indexer.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,9 @@ impl Indexer {
130130
let pricing_catalog = self.cached_pricing_catalog();
131131
let now_millis = epoch_millis(SystemTime::now())?;
132132

133-
let excluded = crate::trash_state::shared_deleted_ids();
134133
let provider_refs = self.selected_providers(filter);
135-
let works = self.collect_provider_work(
136-
&provider_refs,
137-
pricing_catalog.as_ref(),
138-
&excluded,
139-
force_parse,
140-
)?;
134+
let works =
135+
self.collect_provider_work(&provider_refs, pricing_catalog.as_ref(), force_parse)?;
141136

142137
// Phase 2 (sequential, DB writer): commit each provider's snapshot.
143138
// SQLite has a single writer mutex; serializing here avoids contention
@@ -206,7 +201,6 @@ impl Indexer {
206201
&self,
207202
providers: &[&dyn SessionProvider],
208203
pricing_catalog: Option<&PricingCatalog>,
209-
excluded: &HashSet<String>,
210204
force_parse: bool,
211205
) -> ServiceResult<Vec<ProviderWork>> {
212206
// Phase 1 (parallel, CPU/IO): scan each provider's files and compute
@@ -215,17 +209,14 @@ impl Indexer {
215209
// scan), so providers don't share state and can run in parallel.
216210
providers
217211
.par_iter()
218-
.map(|provider| {
219-
self.scan_provider_work(*provider, pricing_catalog, excluded, force_parse)
220-
})
212+
.map(|provider| self.scan_provider_work(*provider, pricing_catalog, force_parse))
221213
.collect()
222214
}
223215

224216
fn scan_provider_work(
225217
&self,
226218
provider: &dyn SessionProvider,
227219
pricing_catalog: Option<&PricingCatalog>,
228-
excluded: &HashSet<String>,
229220
force_parse: bool,
230221
) -> ServiceResult<ProviderWork> {
231222
let provider_kind = provider.provider();
@@ -250,13 +241,8 @@ impl Indexer {
250241
let outcome = provider.scan_incremental(&known).map_err(|e| {
251242
ServiceError::ScanProvider(provider_kind.key().to_string(), e.to_string())
252243
})?;
253-
let mut sessions = outcome.parsed;
244+
let sessions = outcome.parsed;
254245
let unchanged_source_paths = outcome.unchanged_source_paths;
255-
256-
if !excluded.is_empty() {
257-
sessions.retain(|session| !excluded.contains(&session.meta.id));
258-
}
259-
260246
let stats_batch = build_token_stats_batch(provider, &sessions, pricing_catalog);
261247

262248
Ok(ProviderWork {
@@ -319,7 +305,7 @@ impl Indexer {
319305
}
320306
self.db
321307
.set_meta("usage_last_refreshed_at", &chrono::Utc::now().to_rfc3339())
322-
.map_err(|e| ServiceError::StoreUsageLastRefreshed(e.to_string()))?;
308+
.map_err(|error| ServiceError::StoreUsageLastRefreshed(error.to_string()))?;
323309
Ok(())
324310
}
325311

0 commit comments

Comments
 (0)