Add Markdown Formatting
Nucleic-Session: 23936B4B-52E9-43F5-908B-C7919A5BD6DD Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -106,14 +106,72 @@ struct HostCommandBreakdown: View {
|
|||||||
if let dir = summary.workingDirectory {
|
if let dir = summary.workingDirectory {
|
||||||
detailRow(icon: "folder", lines: ["in \(dir)"])
|
detailRow(icon: "folder", lines: ["in \(dir)"])
|
||||||
}
|
}
|
||||||
ForEach(Array(summary.invocations.enumerated()), id: \.element.id) { index, inv in
|
steps
|
||||||
if index > 0 { Divider().overlay(Color.primary.opacity(0.08)) }
|
|
||||||
invocationView(inv)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// At most this many steps render in the compact chain list before the rest fold into a
|
||||||
|
/// "+N more" tail — so a long `cmd1 && cmd2 && …` pipeline can't grow the card unbounded
|
||||||
|
/// (the exact command shown alongside is always the complete source of truth).
|
||||||
|
private static let maxVisibleSteps = 7
|
||||||
|
|
||||||
|
/// The invocations, rendered to fit the chain length: a lone command gets the full block
|
||||||
|
/// (program + actions + every env/flag/operand spelled out); a *chain* collapses to one
|
||||||
|
/// compact line per command so a long pipeline stays short, not a tall stack of blocks.
|
||||||
|
@ViewBuilder private var steps: some View {
|
||||||
|
if summary.invocations.count <= 1 {
|
||||||
|
if let only = summary.invocations.first { invocationView(only) }
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
|
ForEach(Array(summary.invocations.prefix(Self.maxVisibleSteps))) { inv in
|
||||||
|
stepRow(inv)
|
||||||
|
}
|
||||||
|
let hidden = summary.invocations.count - Self.maxVisibleSteps
|
||||||
|
if hidden > 0 {
|
||||||
|
Text("+\(hidden) more step\(hidden == 1 ? "" : "s")")
|
||||||
|
.font(.caption2).foregroundStyle(.tertiary)
|
||||||
|
.padding(.leading, 22)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One command in a chain, compacted to a single line: a step glyph, the program + actions
|
||||||
|
/// emphasized, then a truncated tail of its env/flags/operands. A destructive/elevated step is
|
||||||
|
/// tinted and glyphed in the danger color so it still stands out.
|
||||||
|
private func stepRow(_ inv: HostCommandSummary.Invocation) -> some View {
|
||||||
|
let risky = inv.destructive || inv.elevated
|
||||||
|
let tail = stepTail(inv)
|
||||||
|
return HStack(alignment: .firstTextBaseline, spacing: 8) {
|
||||||
|
Image(systemName: stepGlyph(inv))
|
||||||
|
.font(.caption2).foregroundStyle(risky ? Palette.danger : accent).frame(width: 14)
|
||||||
|
(Text(inv.headline)
|
||||||
|
.font(.caption.monospaced().weight(.semibold))
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
+ Text(tail.isEmpty ? "" : " " + tail)
|
||||||
|
.font(.caption.monospaced())
|
||||||
|
.foregroundColor(.secondary))
|
||||||
|
.lineLimit(1).truncationMode(.middle)
|
||||||
|
.textSelection(.enabled)
|
||||||
|
Spacer(minLength: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The trailing detail of a compacted step — its env, flags, and operands joined on one line,
|
||||||
|
/// truncated by the row. The literal command carries the untruncated form.
|
||||||
|
private func stepTail(_ inv: HostCommandSummary.Invocation) -> String {
|
||||||
|
(inv.env.map(\.display) + inv.flags.map(\.display) + inv.arguments).joined(separator: " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The leading glyph for a compacted step: a delete/elevation marker takes priority so the
|
||||||
|
/// risky step is unmistakable; otherwise a plain terminal glyph.
|
||||||
|
private func stepGlyph(_ inv: HostCommandSummary.Invocation) -> String {
|
||||||
|
if inv.destructive { return "trash" }
|
||||||
|
if inv.elevated { return "lock.shield" }
|
||||||
|
return "terminal"
|
||||||
|
}
|
||||||
|
|
||||||
/// The deterministic, command-derived purpose — labeled so the user knows it's *Nucleic's*
|
/// The deterministic, command-derived purpose — labeled so the user knows it's *Nucleic's*
|
||||||
/// reading of the command, not the agent's claim about it.
|
/// reading of the command, not the agent's claim about it.
|
||||||
private var purposeRow: some View {
|
private var purposeRow: some View {
|
||||||
|
|||||||
Reference in New Issue
Block a user