Say how big a session is before it is imported
The import list reported a line count, which is the wrong axis: these transcripts embed screenshots as base64, so one line can be a megabyte. On this machine a 69 MB session has 3,427 lines while a 44 MB one has 6,792 — the number on the row said nothing about what continuing the session would cost, and size is the only thing there that predicts it. The session behind the 2026-08-29 incident was 65 MB across 13,000 lines, a line count that looks unremarkable. Shown beside the line count rather than instead of it, since a short file of long lines is exactly the expensive case. Not warned about and not marked: importing a large session is a choice somebody is entitled to make, and flagging it would be the interface nagging about a decision already taken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VETa8afmpWaYezLCqJhDB8
This commit is contained in:
1 parent
362d436d4f
commit
d96bc041a7
4 files changed
+47
-2
No files matched your search
@@ -196,6 +196,14 @@ data class Importable(
|
||||
val title: String,
|
||||
val modified: Double,
|
||||
val lines: Int,
|
||||
/**
|
||||
* Size of the session file in bytes.
|
||||
*
|
||||
* Worth a place on the row because it is the only thing there that predicts what continuing the
|
||||
* session costs, and the line count does not: these transcripts embed screenshots as base64, so
|
||||
* a single line can be a megabyte.
|
||||
*/
|
||||
val bytes: Long,
|
||||
/** Whether [title] is a name somebody chose rather than the last thing said in the session. */
|
||||
val named: Boolean,
|
||||
/**
|
||||
@@ -217,6 +225,7 @@ fun fetchImportable(settings: ServerSettings, setup: String): List<Importable> =
|
||||
title = session.optString("title"),
|
||||
modified = session.optDouble("modified", 0.0),
|
||||
lines = session.optInt("lines", 0),
|
||||
bytes = session.optLong("bytes", 0L),
|
||||
// Absent means an older backend that cannot answer, which is exactly what
|
||||
// "unknown" says -- so the default is the honest one rather than "no".
|
||||
inUse = session.optString("inUse", "unknown"),
|
||||
|
||||
@@ -304,6 +304,15 @@ private fun ImportableList(
|
||||
}
|
||||
}
|
||||
|
||||
/** A byte count at the coarsest unit that still says something, so rows stay comparable. */
|
||||
private fun humanSize(bytes: Long): String? =
|
||||
when {
|
||||
bytes <= 0L -> null
|
||||
bytes >= 1_000_000L -> "${bytes / 1_000_000L} MB"
|
||||
bytes >= 1_000L -> "${bytes / 1_000L} kB"
|
||||
else -> "$bytes B"
|
||||
}
|
||||
|
||||
/** The second line of a row: what this session is, in the order it is worth knowing. */
|
||||
private fun detailOf(session: Importable, importing: String?): String =
|
||||
listOfNotNull(
|
||||
@@ -320,6 +329,10 @@ private fun detailOf(session: Importable, importing: String?): String =
|
||||
// session, the other is only what happened last in it.
|
||||
if (session.named) "named" else null,
|
||||
"${session.lines} lines",
|
||||
// Beside the line count rather than instead of it: the two disagree usefully. A
|
||||
// short file of long lines is a session full of screenshots, and that is the one
|
||||
// that is expensive to carry on with.
|
||||
humanSize(session.bytes),
|
||||
// The tail, not the head: a path is identified by where it ends, and these all share
|
||||
// a long prefix.
|
||||
session.cwd
|
||||
|
||||
Reference in new issue
Block a user