77 lines
5.4 KiB
Markdown
77 lines
5.4 KiB
Markdown
---
|
|
id: hard-delete-session-jsonl
|
|
title: Hard-delete session JSONL on conversation delete
|
|
scenario: gateway-backend-communication
|
|
taskType: runtime-bridge
|
|
intent: Remove the on-disk session transcript (and its sibling artefacts) when the user deletes a conversation, instead of soft-deleting it via rename.
|
|
touchedAreas:
|
|
- electron/main/ipc-handlers.ts
|
|
- electron/api/routes/sessions.ts
|
|
- electron/utils/session-files.ts
|
|
- src/stores/chat/session-actions.ts
|
|
- src/stores/chat.ts
|
|
- tests/unit/session-delete-route.test.ts
|
|
- harness/specs/tasks/hard-delete-session-jsonl.md
|
|
- AGENTS.md
|
|
expectedUserBehavior:
|
|
- Confirming "Delete" in the sidebar conversation menu removes <id>.jsonl, <id>.deleted.jsonl and any <id>.jsonl.reset.* siblings from the agent's sessions folder.
|
|
- OpenClaw's trajectory artefacts for the same session id are removed too — both the local <id>.trajectory.jsonl flight recorder and the <id>.trajectory-path.json pointer sidecar.
|
|
- When the pointer's runtimeFile points outside the sessions/ folder (the OPENCLAW_TRAJECTORY_DIR override), that off-disk runtime file is also unlinked so no orphan trajectory remains anywhere on disk.
|
|
- The session entry is removed from sessions.json so OpenClaw sessions.list stops returning it.
|
|
- The sidebar list, sessionLabels and sessionLastActivity for the deleted key are cleared in the renderer store.
|
|
- Any pending optimistic user message cache for the deleted session key is cleared so a later history reload cannot resurrect deleted chat bubbles.
|
|
- Token usage history reported by the Dashboard stops including the deleted session.
|
|
requiredProfiles:
|
|
- fast
|
|
- comms
|
|
requiredTests:
|
|
- tests/unit/session-delete-route.test.ts
|
|
- tests/unit/chat-session-actions.test.ts
|
|
acceptance:
|
|
- Renderer continues to use src/lib/host-api.ts and src/lib/api-client.ts; no new direct ipcRenderer or Gateway HTTP calls.
|
|
- IPC channel name session:delete and HTTP route POST /api/sessions/delete are unchanged in shape.
|
|
- Both the IPC handler in electron/main/ipc-handlers.ts and the HTTP mirror in electron/api/routes/sessions.ts unlink the same set of files for a given session id, sharing electron/utils/session-files.ts so the disk contract cannot drift.
|
|
- The handler tolerates ENOENT (file already gone) and still updates sessions.json so the sidebar stops listing the entry.
|
|
- Renderer delete-session paths clear any in-memory pending optimistic user messages for the deleted key before subsequent history loads run.
|
|
- agentId from the sessionKey is validated against /^[A-Za-z0-9][A-Za-z0-9_-]*$/ in both surfaces and any sessionFile resolved to a path outside the agent sessions/ directory is refused (defence-in-depth against a corrupt sessions.json).
|
|
- Absolute-path detection accepts POSIX paths, Windows backslash paths (C:\...) and Windows forward-slash paths (C:/...) so the sweep works on every supported OS.
|
|
- The sweep also unlinks <id>.trajectory.jsonl and <id>.trajectory-path.json sidecars produced by OpenClaw's runtime trajectory writer.
|
|
- When <id>.trajectory-path.json carries the openclaw-trajectory-pointer schema and an absolute .jsonl runtimeFile that lives outside the sessions/ folder, the off-disk runtime trajectory is unlinked too (covers the OPENCLAW_TRAJECTORY_DIR override). Pointers with the wrong schema, a non-.jsonl runtimeFile, or a non-absolute runtimeFile are ignored and no extra files are touched.
|
|
docs:
|
|
required: true
|
|
---
|
|
|
|
Conversation deletion in ClawX runs entirely on the Main process — the
|
|
OpenClaw Gateway does not expose a `sessions.delete` RPC. Historically the
|
|
operation was a soft delete: the live `<id>.jsonl` transcript was renamed to
|
|
`<id>.deleted.jsonl` so `sessions.list` would skip it. This task replaces
|
|
that rename with a true `unlink` plus a sibling sweep that also removes
|
|
`<id>.deleted.jsonl` (legacy soft-delete leftovers) and `<id>.jsonl.reset.*`
|
|
(reset snapshots produced by `sessions.reset`).
|
|
|
|
Both backends (the IPC handler used by the refactored chat store and the
|
|
HTTP route used by the legacy chat store) share the same disk contract via
|
|
`electron/utils/session-files.ts`, which centralises:
|
|
|
|
- sessions.json entry resolution across the three observed shapes,
|
|
- cross-platform absolute-path detection (POSIX, Windows `C:\...` and
|
|
Windows `C:/...`) using `path.isAbsolute` + `path.win32.isAbsolute`,
|
|
- a defence-in-depth scope check that refuses any `sessionFile` whose
|
|
resolved directory escapes the agent's `sessions/` folder,
|
|
- the sibling sweep (`.jsonl`, `.deleted.jsonl`, `.jsonl.reset.*`,
|
|
`.trajectory.jsonl`, `.trajectory-path.json`) with ENOENT tolerance, and
|
|
- the trajectory pointer-follow that handles OpenClaw's
|
|
`OPENCLAW_TRAJECTORY_DIR` override: when the pointer is well-formed
|
|
(`traceSchema === "openclaw-trajectory-pointer"` and `runtimeFile` is
|
|
an absolute `.jsonl` outside sessions/), the off-disk runtime file is
|
|
unlinked too. Malformed or unsafe pointers are ignored.
|
|
|
|
Renderer surface is untouched: the confirm dialog in `Sidebar.tsx`, the
|
|
`useChatStore.deleteSession` API, and the host-api/api-client boundary all
|
|
continue to work without changes. The only user-visible effect is that
|
|
deleted conversations no longer leave hidden `.deleted.jsonl` files behind
|
|
and no longer contribute to Dashboard token-usage history. Deletion also
|
|
clears renderer-only pending optimistic user messages keyed by the deleted
|
|
session so the UI cannot rehydrate a locally staged message after the
|
|
transcript and sidebar entry have been removed.
|