refactor(desktop): ChatStore structured split + IDB persistence + stream cancel
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Split monolithic chatStore.ts (908 lines) into 4 focused stores:
- chatStore.ts: facade layer, owns messages[], backward-compatible selectors
- conversationStore.ts: conversation CRUD, agent switching, IndexedDB persistence
- streamStore.ts: streaming orchestration, chat mode, suggestions
- messageStore.ts: token tracking

Key fixes from 3-round deep audit:
- C1: Fix Rust serde camelCase vs TS snake_case mismatch (toolStart/toolEnd/iterationStart)
- C2: Fix IDB async rehydration race with persist.hasHydrated() subscribe
- C3: Add sessionKey to partialize to survive page refresh
- H3: Fix IDB migration retry on failure (don't set migrated=true in catch)
- M3: Fix ToolCallStep deduplication (toolStart creates, toolEnd updates)
- M-NEW-2: Clear sessionKey on cancelStream

Also adds:
- Rust backend stream cancellation via AtomicBool + cancel_stream command
- IndexedDB storage adapter with one-time localStorage migration
- HMR cleanup for cross-store subscriptions
This commit is contained in:
iven
2026-04-03 00:24:16 +08:00
parent da438ad868
commit 0a04b260a4
22 changed files with 1269 additions and 767 deletions

View File

@@ -53,6 +53,7 @@ impl From<zclaw_skills::SkillManifest> for SkillInfoResponse {
///
/// Returns skills from the Kernel's SkillRegistry.
/// Skills are loaded from the skills/ directory during kernel initialization.
// @connected
#[tauri::command]
pub async fn skill_list(
state: State<'_, KernelState>,
@@ -74,6 +75,7 @@ pub async fn skill_list(
///
/// Re-scans the skills directory for new or updated skills.
/// Optionally accepts a custom directory path to scan.
// @connected
#[tauri::command]
pub async fn skill_refresh(
state: State<'_, KernelState>,
@@ -124,6 +126,7 @@ pub struct UpdateSkillRequest {
}
/// Create a new skill in the skills directory
// @connected
#[tauri::command]
pub async fn skill_create(
state: State<'_, KernelState>,
@@ -170,6 +173,7 @@ pub async fn skill_create(
}
/// Update an existing skill
// @connected
#[tauri::command]
pub async fn skill_update(
state: State<'_, KernelState>,
@@ -214,6 +218,7 @@ pub async fn skill_update(
}
/// Delete a skill
// @connected
#[tauri::command]
pub async fn skill_delete(
state: State<'_, KernelState>,
@@ -286,6 +291,7 @@ impl From<zclaw_skills::SkillResult> for SkillResult {
///
/// Executes a skill with the given ID and input.
/// Returns the skill result as JSON.
// @connected
#[tauri::command]
pub async fn skill_execute(
state: State<'_, KernelState>,