From d2817f60fa07e49503e95320103949d4d2185fbb Mon Sep 17 00:00:00 2001 From: Andrew Blakeslee Moore Date: Tue, 16 Jun 2026 00:11:11 -0700 Subject: [PATCH] Merge nucleic/rustic-north-koala into dev --- .../Views/ApprovalCardView.swift | 18 ++++++++++----- .../NucleicRemote/Views/TranscriptRow.swift | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/NucleicRemote/NucleicRemote/Views/ApprovalCardView.swift b/NucleicRemote/NucleicRemote/Views/ApprovalCardView.swift index c1405eb..f07b28c 100644 --- a/NucleicRemote/NucleicRemote/Views/ApprovalCardView.swift +++ b/NucleicRemote/NucleicRemote/Views/ApprovalCardView.swift @@ -33,13 +33,19 @@ struct ApprovalCardView: View { .background(approval.risk.color.opacity(0.2), in: Capsule()) .foregroundStyle(approval.risk.color) } - Text(approval.input.compactSummary) - .font(.caption.monospaced()) - .lineLimit(8) - .textSelection(.enabled) - .padding(8) - .frame(maxWidth: .infinity, alignment: .leading) + // Full, untruncated content in a bounded scroll view — the user must be + // able to read exactly what they are granting, so long commands/paths/inputs + // scroll instead of being clipped to a few lines. + if !approval.input.approvalDetail.isEmpty { + ScrollView([.horizontal, .vertical]) { + Text(approval.input.approvalDetail) + .font(.caption.monospaced()) + .textSelection(.enabled) + .padding(8) + } + .frame(maxWidth: .infinity, maxHeight: 200, alignment: .leading) .background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 8)) + } if requiresBiometric && !biometricPassed { Button { diff --git a/NucleicRemote/NucleicRemote/Views/TranscriptRow.swift b/NucleicRemote/NucleicRemote/Views/TranscriptRow.swift index aaac024..a15be01 100644 --- a/NucleicRemote/NucleicRemote/Views/TranscriptRow.swift +++ b/NucleicRemote/NucleicRemote/Views/TranscriptRow.swift @@ -82,4 +82,27 @@ extension JSONValue { case .null: return "null" } } + + /// The full, **untruncated** content of a tool input for the approval card — + /// the user must see exactly what they are granting before allowing. Unlike + /// `compactSummary` (a one-line gist that drops values for complex objects) this + /// returns the primary field verbatim, falling back to the pretty-printed input + /// so nothing is hidden. The caller scrolls; it never clips. + var approvalDetail: String { + switch self { + case .string(let s): return s + case .object(let o): + if let primary = o["command"]?.stringValue + ?? o["file_path"]?.stringValue + ?? o["path"]?.stringValue + ?? o["notebook_path"]?.stringValue + ?? o["url"]?.stringValue + ?? o["query"]?.stringValue { + return primary + } + return o.isEmpty ? "" : prettyString() + case .null: return "" + default: return prettyString() + } + } }