Merge nucleic/humble-dewy-weasel-eren into dev

This commit is contained in:
2026-08-04 23:13:58 -07:00
parent a8874ac736
commit 2337b022fe
2 changed files with 15 additions and 1 deletions
@@ -67,7 +67,9 @@ struct ApprovalCardView: View {
// A destructive action (rm, force-push, reset --hard, …) offers no remembered
// allow: every one must be a deliberate, one-off approval, never granted in a
// way that lets the next one through unseen. Mirrors the Mac.
if approval.risk != .destructive, !store.capabilities.allowAlwaysScopes.isEmpty {
if approval.risk != .destructive,
approval.toolName != "mcp__nucleic__copy_artifact",
!store.capabilities.allowAlwaysScopes.isEmpty {
Menu("Allow always…") {
ForEach(store.capabilities.allowAlwaysScopes, id: \.self) { scope in
Button(alwaysLabel(scope)) {
@@ -31,6 +31,7 @@ enum SandboxToolDisplay {
// The wire name is Claude Code's, but the shell behind it is nash.
case "Bash": "Nash"
case "BashOutput": "Nash output"
case "copy_artifact": "Copy artifact"
case "mac_vm_exec", "mac_vm_control": "macOS VM"
case "mac_vm_computer", "mac_vm_computer_batch": "macOS VM screen"
case "mac_vm_clear_notifications": "macOS VM notifications"
@@ -56,6 +57,7 @@ enum SandboxToolDisplay {
/// the way the Mac's status line does.
static func gerund(for toolName: String) -> String? {
switch bareName(toolName) {
case "copy_artifact": "Copying an artifact…"
case "mac_vm_exec": "Running on a macOS VM…"
case "linux_vm_exec": "Running on a Linux VM…"
case "linux_container": "Running in a Linux container…"
@@ -73,6 +75,7 @@ enum SandboxToolDisplay {
/// for a lifecycle op — so the glyph carries the same distinction the label does.
static func icon(for toolName: String) -> String? {
switch bareName(toolName) {
case "copy_artifact": "doc.on.doc"
case "mac_vm_exec": "macwindow"
case "linux_vm_exec": "server.rack"
case "linux_container": "shippingbox"
@@ -90,6 +93,15 @@ enum SandboxToolDisplay {
/// case the caller falls back to the generic input gist.
static func detail(for toolName: String, input: JSONValue) -> String? {
switch bareName(toolName) {
case "copy_artifact":
let source = string(input, "source").map(singleLine)
let destination = string(input, "destination").map(singleLine)
switch (source, destination) {
case let (.some(source), .some(destination)): return "\(source) → \(destination)"
case let (.some(source), .none): return source
case let (.none, .some(destination)): return destination
case (.none, .none): return nil
}
case "mac_vm_exec", "linux_vm_exec":
return string(input, "command").map { "$ \(singleLine($0))" }
case "mac_vm_computer", "linux_vm_computer":