Merge nucleic/mellow-ember-shrew into dev
This commit is contained in:
@@ -116,11 +116,13 @@ struct SettingsView: View {
|
|||||||
|
|
||||||
Section {
|
Section {
|
||||||
Toggle("Show lock events", isOn: $showLockEvents)
|
Toggle("Show lock events", isOn: $showLockEvents)
|
||||||
Toggle("Show raw events", isOn: $showRaw)
|
Toggle("Show advanced detail", isOn: $showRaw)
|
||||||
} header: {
|
} header: {
|
||||||
Text("Transcript")
|
Text("Transcript")
|
||||||
} footer: {
|
} 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 {
|
Section {
|
||||||
|
|||||||
@@ -265,17 +265,31 @@ final class IncrementalTranscriptProjection {
|
|||||||
spans[result.toolCallID]?.resultSeen = true
|
spans[result.toolCallID]?.resultSeen = true
|
||||||
case .toolCallInputDelta, .fileChange, .approvalResolved, .codexUsage:
|
case .toolCallInputDelta, .fileChange, .approvalResolved, .codexUsage:
|
||||||
break // refs (if any) tracked above; creates nothing
|
break // refs (if any) tracked above; creates nothing
|
||||||
case .turnCompleted, .runFinished:
|
case .runFinished:
|
||||||
creations[r] = .separator
|
creations[r] = .separator
|
||||||
lastBoundary = r
|
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
|
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):
|
case .note(let note):
|
||||||
if note.lockEvent && !showLockEvents { break }
|
if note.lockEvent && !showLockEvents { break }
|
||||||
if let lock = note.lock, !lock.paths.isEmpty { creations[r] = .transparent }
|
if let lock = note.lock, !lock.paths.isEmpty { creations[r] = .transparent }
|
||||||
else { creations[r] = .separator }
|
else { creations[r] = .separator }
|
||||||
case .raw:
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Items that draw no visible row. They must not break a run of tool calls when coalescing:
|
/// Diagnostic, debug-level rows: per-turn token tallies, rate-limit notices, turn markers, and
|
||||||
/// an invisible row sitting between two calls would otherwise split them into two cards.
|
/// unrecognized raw passthrough events. Hidden by default to keep the transcript clean — they're
|
||||||
var rendersNothing: Bool { isEmptyThinking }
|
/// 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.
|
/// 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)] = []
|
var patches: [(toolCallID: String, lock: NoteLock)] = []
|
||||||
let flat = foldLockNotes(flatItems(topLevel, showRaw: showRaw, showLockEvents: showLockEvents),
|
let flat = foldLockNotes(flatItems(topLevel, showRaw: showRaw, showLockEvents: showLockEvents),
|
||||||
worktreeRoot: root, priorEdits: priorEdits, priorLockPatches: &patches)
|
worktreeRoot: root, priorEdits: priorEdits, priorLockPatches: &patches)
|
||||||
let items = coalesceToolRuns(flat).map {
|
let coalesced = coalesceToolRuns(flat).map {
|
||||||
attachSubagentChildren($0, byParent: byParent, depth: 0,
|
attachSubagentChildren($0, byParent: byParent, depth: 0,
|
||||||
showRaw: showRaw, showLockEvents: showLockEvents)
|
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
|
let edits = flat.compactMap { item -> PriorEdit? in
|
||||||
guard case .tool(let group) = item.kind else { return nil }
|
guard case .tool(let group) = item.kind else { return nil }
|
||||||
let paths = editedPaths(toolName: group.name, input: group.input)
|
let paths = editedPaths(toolName: group.name, input: group.input)
|
||||||
|
|||||||
Reference in New Issue
Block a user