Use native Codex steering and transcript deletion

This commit is contained in:
iris committed 2026-09-09 12:19:11 -04:00
1 parent 00538cc19b
commit 8c88a7e991
12 files changed
+1004 -390

No files matched your search

@@ -140,6 +140,8 @@ data class SessionSummary(
* still there, and re-importing is not a restore.
*/
val keepsOwnTranscript: Boolean,
/** Product whose durable transcript survives an ordinary app deletion. */
val ownTranscriptName: String?,
/** How much the session asks before acting; null when it was never set. */
val permissionMode: String?,
/**
@@ -238,6 +240,7 @@ private fun parseSession(session: JSONObject) =
id = session.getString("id"),
setup = session.getString("setup"),
keepsOwnTranscript = session.optBoolean("keepsOwnTranscript", false),
ownTranscriptName = session.optString("ownTranscriptName").ifEmpty { null },
setupName = session.getString("setupName"),
provider = session.getString("provider"),
title = session.getString("title"),
@@ -1230,10 +1233,10 @@ fun compactSession(settings: ServerSettings, sessionId: String) {
/**
* Removes a session, and optionally the machine's own transcript of the same conversation.
*
* [deleteForeign] is the delete this app cannot otherwise reach: Claude Code keeps its own record
* under `~/.claude/projects`, and leaving it is what makes an ordinary delete recoverable. The
* server does both halves, and does the unrecoverable one first, so a machine it cannot reach
* leaves the session exactly where it was rather than half-deleted.
* [deleteForeign] is the delete this app cannot otherwise reach: coding CLIs keep their own durable
* record, and leaving it is what makes an ordinary delete recoverable. The server does both halves,
* and does the unrecoverable one first, so a machine it cannot reach leaves the session exactly
* where it was rather than half-deleted.
*/
fun deleteSession(settings: ServerSettings, sessionId: String, deleteForeign: Boolean = false) {
val query = if (deleteForeign) "?deleteForeign=true" else ""
@@ -318,17 +318,19 @@ fun SessionListScreen(
// Reset per session, so a toggle turned on for one conversation is not still on for the
// next. Off to begin with: see [deleteSession].
var alsoDeleteForeign by remember(session.id) { mutableStateOf(false) }
// Old servers reported only the capability, when Claude Code was its sole owner.
val transcriptOwner = session.ownTranscriptName ?: "Claude Code"
AlertDialog(
onDismissRequest = { confirmingDelete = null },
title = { Text("Delete \"${session.title}\"?") },
text = {
// Two different acts behind one button, so it says which one this is. What
// separates them is whether the *driver* keeps its own record of the conversation
// -- the Claude Code CLI does, whether this app spawned the session or imported it;
// -- the coding CLIs do, whether this app spawned the session or imported it;
// echo and llama.cpp do not.
//
// This used to branch on `imported`, above a comment asserting that "a session
// started here has no copy anywhere". That was false for every claude-cli session
// started here has no copy anywhere". That was false for every coding-CLI session
// this app spawned, and getting it wrong in that direction is the expensive one:
// "this can't be undone", said of something that can, spends the credibility the
// sentence needs.
@@ -349,12 +351,12 @@ fun SessionListScreen(
// the reassurance being read at the moment it stops being true.
alsoDeleteForeign ->
"Kills the process and deletes both copies of the conversation: " +
"this app's, and Claude Code's own transcript on the " +
"this app's, and $transcriptOwner's own transcript on the " +
"machine. Nothing keeps another, so this can't be undone."
else ->
"Stops the process and deletes this app's copy of the " +
"conversation, including any images, peer messages and " +
"commands recorded only here. Claude Code keeps its own " +
"commands recorded only here. $transcriptOwner keeps its own " +
"transcript on the machine, so the conversation itself " +
"should still be there to import again."
}
@@ -369,7 +371,7 @@ fun SessionListScreen(
// line of text and re-centres whatever shares a row with it.
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
"Delete Claude Code's transcript too",
"Delete $transcriptOwner's transcript too",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f),
)