Merge branch 'dev' into canary

This commit is contained in:
2026-07-10 01:03:43 -07:00
5 changed files with 99 additions and 33 deletions
@@ -1,13 +1,13 @@
{ {
"originHash" : "997519e7bf6b3bb52f6f766bab10b0bf950c6beb140aa897dc50ba77eaaa5801", "originHash" : "fa70224ebd92e3bfa55fbdf5bbea5d2a51a1f6402e805a443a323509fbc905ed",
"pins" : [ "pins" : [
{ {
"identity" : "async-http-client", "identity" : "async-http-client",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/swift-server/async-http-client.git", "location" : "https://github.com/swift-server/async-http-client.git",
"state" : { "state" : {
"revision" : "7744c2a035c68ec14726c709f031835e3e30bde1", "revision" : "4603a8036d921ea999fadb742931546c341f4bd7",
"version" : "1.34.0" "version" : "1.35.0"
} }
}, },
{ {
@@ -15,8 +15,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/groue/GRDB.swift.git", "location" : "https://github.com/groue/GRDB.swift.git",
"state" : { "state" : {
"revision" : "9ed8c8457e00ff9c7aedb3bf213f20a2cfdf509e", "revision" : "b83108d10f42680d78f23fe4d4d80fc88dab3212",
"version" : "7.11.0" "version" : "7.11.1"
} }
}, },
{ {
@@ -24,8 +24,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-2.git", "location" : "https://github.com/grpc/grpc-swift-2.git",
"state" : { "state" : {
"revision" : "21fe69ab7ce0e87ac089534733c52f037e74a3eb", "revision" : "28cdd63ef88583ddc67d7bb179eab46fab465ce9",
"version" : "2.4.1" "version" : "2.4.2"
} }
}, },
{ {
@@ -33,8 +33,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-nio-transport.git", "location" : "https://github.com/grpc/grpc-swift-nio-transport.git",
"state" : { "state" : {
"revision" : "e7d463749f9037b047dcd6da4e633718ddc432b8", "revision" : "2ca31f06658ed288a2560e23ad649acbb3d6b3a3",
"version" : "2.8.0" "version" : "2.9.0"
} }
}, },
{ {
@@ -42,8 +42,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-swift-protobuf.git", "location" : "https://github.com/grpc/grpc-swift-protobuf.git",
"state" : { "state" : {
"revision" : "b05885fa9bdd88f1eab2e7162f1ee81340b0da33", "revision" : "176c5a434fd76f6f479848d1a8f7d44967534168",
"version" : "2.4.0" "version" : "2.4.1"
} }
}, },
{ {
@@ -51,8 +51,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/sparkle-project/Sparkle", "location" : "https://github.com/sparkle-project/Sparkle",
"state" : { "state" : {
"revision" : "d46d456107feacc80711b21847b82b07bd9fb46e", "revision" : "b6496a74a087257ef5e6da1c5b29a447a60f5bd7",
"version" : "2.9.3" "version" : "2.9.4"
} }
}, },
{ {
@@ -87,8 +87,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-async-algorithms.git", "location" : "https://github.com/apple/swift-async-algorithms.git",
"state" : { "state" : {
"revision" : "d0b4a06d0f173a2f3be27d3ea21b3c3aa18db440", "revision" : "3da39bbc4e687d4192af7c9cf4eab805745a0b9c",
"version" : "1.1.4" "version" : "1.1.5"
} }
}, },
{ {
@@ -105,8 +105,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-certificates.git", "location" : "https://github.com/apple/swift-certificates.git",
"state" : { "state" : {
"revision" : "bde8ca32a096825dfce37467137c903418c1893d", "revision" : "89fbc3714264cce8db8e4ec51b64e01c3e28c6c5",
"version" : "1.19.1" "version" : "1.19.3"
} }
}, },
{ {
@@ -168,8 +168,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git", "location" : "https://github.com/apple/swift-log.git",
"state" : { "state" : {
"revision" : "92448c359f00ebe36ae97d3bd9086f13c7692b5a", "revision" : "a878e7f8f46cfc0e1125e565b5c08e7d5272dc9a",
"version" : "1.13.2" "version" : "1.14.0"
} }
}, },
{ {
@@ -177,8 +177,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git", "location" : "https://github.com/apple/swift-nio.git",
"state" : { "state" : {
"revision" : "77b84ac2cd2ac9e4ac67d19f045fd5b434f56967", "revision" : "cd3e1152083706d77b223fb29110e590efcc70c0",
"version" : "2.101.0" "version" : "2.101.2"
} }
}, },
{ {
@@ -186,8 +186,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-extras.git", "location" : "https://github.com/apple/swift-nio-extras.git",
"state" : { "state" : {
"revision" : "d2eeec0339074034f11a040a74aa2a341a2c4506", "revision" : "88a51340f59cf181ebde888bd1b749296b3ec029",
"version" : "1.34.1" "version" : "1.34.3"
} }
}, },
{ {
@@ -258,8 +258,8 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git", "location" : "https://github.com/apple/swift-system.git",
"state" : { "state" : {
"revision" : "7502b711c92a17741fa625d722b0ccbd595d8ed1", "revision" : "b5544ba79a70a0cb3563e75bf26dc198d6b40ed3",
"version" : "1.7.2" "version" : "1.7.4"
} }
}, },
{ {
@@ -640,6 +640,12 @@ final class HostConnection {
case .macPairResolved(let deviceID, _): case .macPairResolved(let deviceID, _):
// Answered on this Mac or another device (or timed out) — dismiss the prompt. // Answered on this Mac or another device (or timed out) — dismiss the prompt.
callbacks.macPairResolved(deviceID) callbacks.macPairResolved(deviceID)
case .intelligenceRequest, .credentialNeeded, .credentialUpdate:
// Antimatter runner verbs (docs/ANTIMATTER_RUNNER.md §5–6): a runner host delegating
// intelligence work or asking for / mirroring sealed credentials. Inert here until the
// phone-side executor/vault land — and a host only sends these to clients that
// advertised the matching `WireClientCapabilities`, which this app doesn't yet.
break
case .wireError(let error): case .wireError(let error):
if error.code == .channelMismatch { if error.code == .channelMismatch {
connectivity = .failed(error.message) connectivity = .failed(error.message)
@@ -1672,10 +1672,13 @@ final class RemoteStore: ObservableObject {
// Never originated from here (connection-internal, or handled by dedicated loops). // Never originated from here (connection-internal, or handled by dedicated loops).
// `requestPairingCode`/`cancelPairingCode` are sent straight to the chosen host by // `requestPairingCode`/`cancelPairingCode` are sent straight to the chosen host by
// `requestPairingCode()`/`cancelPairingCode()`, not through this owner-routing switch. // `requestPairingCode()`/`cancelPairingCode()`, not through this owner-routing switch.
// The runner verbs (intelligence results, credential mesh — ANTIMATTER_RUNNER §5–6) will
// ride their own executor/vault loops when the phone side lands; nothing routes them here.
case .hello, .ping, .listPeers, .addressUpdate, .meshRoster, case .hello, .ping, .listPeers, .addressUpdate, .meshRoster,
.registerLiveActivity, .endLiveActivity, .registerPushToStartToken, .setForeground, .registerLiveActivity, .endLiveActivity, .registerPushToStartToken, .setForeground,
.transferOffer, .transferChunk, .transferCommit, .transferCancel, .fetchTranscript, .transferOffer, .transferChunk, .transferCommit, .transferCancel, .fetchTranscript,
.requestPairingCode, .cancelPairingCode, .respondMacPair: .requestPairingCode, .cancelPairingCode, .respondMacPair,
.intelligenceResult, .credentialManifest, .credentialProvision:
break break
} }
} }
@@ -1862,7 +1865,9 @@ final class RemoteStore: ObservableObject {
.transferOffer, .transferChunk, .transferCommit, .transferCancel, .transferOffer, .transferChunk, .transferCommit, .transferCancel,
// "Add a device" mint is handled directly against a live host, not via demoHandle; // "Add a device" mint is handled directly against a live host, not via demoHandle;
// the demo path short-circuits in `requestPairingCode()` with a stand-in code. // the demo path short-circuits in `requestPairingCode()` with a stand-in code.
.requestPairingCode, .cancelPairingCode, .respondMacPair: .requestPairingCode, .cancelPairingCode, .respondMacPair,
// Antimatter runner verbs (ANTIMATTER_RUNNER §5–6) — demo has no runner host.
.intelligenceResult, .credentialManifest, .credentialProvision:
break // passive / already handled by the seeded fixtures (demo has no mesh peers) break // passive / already handled by the seeded fixtures (demo has no mesh peers)
} }
} }
@@ -204,7 +204,10 @@ enum SubagentRunState {
init(group: ToolGroup) { init(group: ToolGroup) {
if !group.finished { self = .running } if !group.finished { self = .running }
else if group.isError { self = .failed } // A `Task` subagent surfaces failure as an error result. A `nucleic_subagent` worker
// instead returns a *non-error* result whose JSON envelope carries `{"ok": false}` (or
// `{"denied": true}`) in-band, so read that too — otherwise a failed worker reads "Done".
else if group.isError || Subagent.workerFailed(group) { self = .failed }
else { self = .done } else { self = .done }
} }
@@ -234,9 +237,14 @@ enum Subagent {
return (raw?.isEmpty == false) ? raw : nil return (raw?.isEmpty == false) ? raw : nil
} }
/// The one-line task the parent handed the subagent (`description`), falling back to the /// The one-line task the parent handed the subagent: a `nucleic_subagent` worker's `task`
/// full `prompt`, then a generic label. /// label, or a `Task` subagent's `description`, falling back to the full `prompt`, then a
/// generic label.
static func taskLabel(_ group: ToolGroup) -> String { static func taskLabel(_ group: ToolGroup) -> String {
if let task = group.input["task"]?.stringValue?
.trimmingCharacters(in: .whitespacesAndNewlines), !task.isEmpty {
return task
}
if let description = group.input["description"]?.stringValue? if let description = group.input["description"]?.stringValue?
.trimmingCharacters(in: .whitespacesAndNewlines), !description.isEmpty { .trimmingCharacters(in: .whitespacesAndNewlines), !description.isEmpty {
return description return description
@@ -258,9 +266,48 @@ enum Subagent {
/// The subagent's returned report, or nil while it's still working / reported nothing. /// The subagent's returned report, or nil while it's still working / reported nothing.
static func report(_ group: ToolGroup) -> String? { static func report(_ group: ToolGroup) -> String? {
guard let result = group.result else { return nil } guard let result = group.result else { return nil }
// A `nucleic_subagent` worker returns a JSON envelope — surface its actual `output` (or
// failure `message`) rather than a one-line gist of the raw `{ok,session_id,…}` object. A
// `Task` subagent returns prose, which falls through to the gist unchanged.
if let worker = workerText(result.resultText), !worker.isEmpty { return worker }
let text = result.compactSummary let text = result.compactSummary
return text.isEmpty ? nil : text return text.isEmpty ? nil : text
} }
/// Whether a `nucleic_subagent` worker result reports failure — a `{"ok": false}` completion
/// or a `{"denied": true}` refusal, both delivered as non-error tool results. False for any
/// other tool (a `Task` subagent, whose failure is an error result handled separately).
static func workerFailed(_ group: ToolGroup) -> Bool {
guard let result = group.result,
let envelope = workerEnvelope(result.resultText) else { return false }
if let denied = envelope["denied"] as? Bool, denied { return true }
if let ok = envelope["ok"] as? Bool { return !ok }
return false
}
/// The human-facing text of a `nucleic_subagent` worker envelope — the worker's `output` on
/// success, or its `message` on failure/denial — or nil when `text` isn't such an envelope
/// (so a `Task` subagent's prose report falls through unchanged).
private static func workerText(_ text: String) -> String? {
guard let envelope = workerEnvelope(text) else { return nil }
if let denied = envelope["denied"] as? Bool, denied {
return envelope["message"] as? String ?? ""
}
guard let ok = envelope["ok"] as? Bool else { return nil }
return ok ? (envelope["output"] as? String ?? "")
: (envelope["message"] as? String ?? "")
}
/// Parses a `nucleic_subagent` result string into its JSON envelope, gated on the envelope's
/// signature keys (`ok` / `denied`) so an arbitrary JSON-shaped tool result isn't mistaken for
/// one. Nil for anything that isn't a worker envelope.
private static func workerEnvelope(_ text: String) -> [String: Any]? {
guard let data = text.data(using: .utf8),
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
object["ok"] != nil || object["denied"] != nil
else { return nil }
return object
}
} }
/// A small leading status glyph for a subagent — a gold spinner while it works, a green check or /// A small leading status glyph for a subagent — a gold spinner while it works, a green check or
@@ -531,7 +578,7 @@ enum ToolGlyph {
case "Edit", "Write", "MultiEdit", "NotebookEdit": return "pencil" case "Edit", "Write", "MultiEdit", "NotebookEdit": return "pencil"
case "Grep", "Glob", "Search": return "magnifyingglass" case "Grep", "Glob", "Search": return "magnifyingglass"
case "WebFetch", "WebSearch": return "globe" case "WebFetch", "WebSearch": return "globe"
case "Task", "Agent": return "person.2" case "Task", "Agent", ToolGroup.orchestraSubagentToolName: return "person.2"
case "TodoWrite": return "checklist" case "TodoWrite": return "checklist"
case "AskUserQuestion": return "questionmark.bubble" case "AskUserQuestion": return "questionmark.bubble"
case HostCommandSummary.hostExecToolName: return "desktopcomputer" case HostCommandSummary.hostExecToolName: return "desktopcomputer"
@@ -76,8 +76,16 @@ struct ToolGroup: Equatable {
struct FilePatch: Equatable { let path: String; let change: FileChange.ChangeKind } struct FilePatch: Equatable { let path: String; let change: FileChange.ChangeKind }
/// Subagent orchestration (`Task`/`Agent`) gets the gold card treatment, like the Mac. /// Nucleic's own Orchestra worker spawn — the qualified `nucleic_subagent` MCP wire name.
var isOrchestration: Bool { name == "Task" || name == "Agent" } /// Unlike a `Task` subagent, a worker runs as its own observed session, so it carries no
/// nested `children` here; its card shows the final output it returned instead.
static let orchestraSubagentToolName = "mcp__nucleic__nucleic_subagent"
/// Subagent orchestration — a `Task`/`Agent` spawn or a `nucleic_subagent` worker — gets the
/// gold card treatment, like the Mac.
var isOrchestration: Bool {
name == "Task" || name == "Agent" || name == Self.orchestraSubagentToolName
}
var isAskUserQuestion: Bool { name == "AskUserQuestion" } var isAskUserQuestion: Bool { name == "AskUserQuestion" }
/// The literal shell command a `Bash` call ran, if any (nil for every other tool). Used to /// The literal shell command a `Bash` call ran, if any (nil for every other tool). Used to