Merge nucleic/mellow-ember-shrew into dev
This commit is contained in:
@@ -116,11 +116,13 @@ struct SettingsView: View {
|
||||
|
||||
Section {
|
||||
Toggle("Show lock events", isOn: $showLockEvents)
|
||||
Toggle("Show raw events", isOn: $showRaw)
|
||||
Toggle("Show advanced detail", isOn: $showRaw)
|
||||
} header: {
|
||||
Text("Transcript")
|
||||
} footer: {
|
||||
Text("")
|
||||
Text("Advanced detail surfaces per-turn token counts, rate-limit notices, turn "
|
||||
+ "markers, and raw events. Hidden by default so consecutive tool calls "
|
||||
+ "read as one group.")
|
||||
}
|
||||
|
||||
Section {
|
||||
|
||||
@@ -265,17 +265,31 @@ final class IncrementalTranscriptProjection {
|
||||
spans[result.toolCallID]?.resultSeen = true
|
||||
case .toolCallInputDelta, .fileChange, .approvalResolved, .codexUsage:
|
||||
break // refs (if any) tracked above; creates nothing
|
||||
case .turnCompleted, .runFinished:
|
||||
case .runFinished:
|
||||
creations[r] = .separator
|
||||
lastBoundary = r
|
||||
case .sessionStarted, .usage, .rateLimit, .approvalRequested, .error:
|
||||
case .turnCompleted:
|
||||
// The turn marker is a debug row now (held aside from tool runs by
|
||||
// `rendersNothing`, then filtered from display), so it's transparent to the seam —
|
||||
// like a droppable lock note, a seam can't rest on it. It still closes the ids of
|
||||
// its turn, so keep it as a boundary.
|
||||
creations[r] = .transparent
|
||||
lastBoundary = r
|
||||
case .sessionStarted, .approvalRequested, .error:
|
||||
creations[r] = .separator
|
||||
case .usage, .rateLimit:
|
||||
// Debug rows (token tallies, rate-limit notices): held aside from tool runs and
|
||||
// filtered from display, so — like a droppable lock note — they're transparent to
|
||||
// the seam rather than a hard separator it can rest on.
|
||||
creations[r] = .transparent
|
||||
case .note(let note):
|
||||
if note.lockEvent && !showLockEvents { break }
|
||||
if let lock = note.lock, !lock.paths.isEmpty { creations[r] = .transparent }
|
||||
else { creations[r] = .separator }
|
||||
case .raw:
|
||||
if showRaw { creations[r] = .separator }
|
||||
// Shown only with advanced detail, and even then a debug row held aside from tool
|
||||
// runs — so transparent to the seam, not a separator.
|
||||
if showRaw { creations[r] = .transparent }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,25 @@ struct TranscriptItem: Identifiable, Equatable {
|
||||
return false
|
||||
}
|
||||
|
||||
/// Items that draw no visible row. They must not break a run of tool calls when coalescing:
|
||||
/// an invisible row sitting between two calls would otherwise split them into two cards.
|
||||
var rendersNothing: Bool { isEmptyThinking }
|
||||
/// Diagnostic, debug-level rows: per-turn token tallies, rate-limit notices, turn markers, and
|
||||
/// unrecognized raw passthrough events. Hidden by default to keep the transcript clean — they're
|
||||
/// the "token counts and other lines between tool calls" that fragmented a run of cards — and
|
||||
/// surfaced only when "advanced detail" (`showRaw`) is on. Prose, thinking, tool calls,
|
||||
/// session-start, approvals, run outcome, and errors are never debug. Mirrors the Mac's
|
||||
/// `TranscriptItem.isDebug`.
|
||||
var isDebug: Bool {
|
||||
switch kind {
|
||||
case .usage, .rateLimit, .turnBoundary, .raw: return true
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
/// Items that draw no visible row (once debug rows are filtered out for display). They must not
|
||||
/// break a run of tool calls when coalescing: a debug/invisible row sitting between two calls
|
||||
/// would otherwise split them into two cards with a gap. Such rows are held aside during
|
||||
/// coalescing and re-emitted after the block, so consecutive tool cards stay one contiguous
|
||||
/// group. Mirrors the Mac's `rendersNothing` (`isDebug || isEmptyThinking`).
|
||||
var rendersNothing: Bool { isDebug || isEmptyThinking }
|
||||
}
|
||||
|
||||
/// One tool call's coalesced lifecycle: start → input deltas → complete → result → file changes.
|
||||
@@ -169,10 +185,19 @@ enum TranscriptProjection {
|
||||
var patches: [(toolCallID: String, lock: NoteLock)] = []
|
||||
let flat = foldLockNotes(flatItems(topLevel, showRaw: showRaw, showLockEvents: showLockEvents),
|
||||
worktreeRoot: root, priorEdits: priorEdits, priorLockPatches: &patches)
|
||||
let items = coalesceToolRuns(flat).map {
|
||||
let coalesced = coalesceToolRuns(flat).map {
|
||||
attachSubagentChildren($0, byParent: byParent, depth: 0,
|
||||
showRaw: showRaw, showLockEvents: showLockEvents)
|
||||
}
|
||||
// Drop the diagnostic rows (token tallies, rate-limit notices, turn markers, raw
|
||||
// passthrough) unless "advanced detail" is on. `coalesceToolRuns` already held them aside
|
||||
// from any tool run (they're `rendersNothing`), so removing them here leaves consecutive
|
||||
// tool cards as one contiguous block instead of a stack fragmented by token-count lines.
|
||||
// Filtering this shared choke point — rather than the view — keeps the incremental
|
||||
// projector's `fold(prefix) ++ fold(tail)` byte-identical to `fold(whole)`: a debug row is
|
||||
// never a tool edit or lock target, so the filter distributes cleanly over the seam and the
|
||||
// per-segment `edits`/`priorLockPatches` bookkeeping below is unaffected.
|
||||
let items = showRaw ? coalesced : coalesced.filter { !$0.isDebug }
|
||||
let edits = flat.compactMap { item -> PriorEdit? in
|
||||
guard case .tool(let group) = item.kind else { return nil }
|
||||
let paths = editedPaths(toolName: group.name, input: group.input)
|
||||
|
||||
Reference in New Issue
Block a user