Merge nucleic/calm-yarn-robin-cmec into dev
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import NucleicProtocol
|
||||||
|
|
||||||
|
/// Pretty rendering of an `ExitPlanMode` tool call — the phone echo of the Mac's `ExitPlanModeCard`.
|
||||||
|
/// The agent calls `ExitPlanMode` to present the plan it wrote on its way out of plan mode; the raw
|
||||||
|
/// tool card reads as escaped JSON with an unrendered Markdown blob, so instead we render the plan
|
||||||
|
/// body as formatted Markdown under a "Plan" header. The plan is on the call input, so the card
|
||||||
|
/// shows the moment the call arrives — before, and regardless of, the user's approval. Mirrors
|
||||||
|
/// `AskUserQuestionResultCard`'s accent-tinted card so a presented plan reads as a first-class moment.
|
||||||
|
struct ExitPlanModeCard: View {
|
||||||
|
let plan: ExitPlanMode.Plan
|
||||||
|
|
||||||
|
private var accent: Color { Palette.accent }
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 10) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: "list.bullet.clipboard")
|
||||||
|
.font(.caption).foregroundStyle(accent).frame(width: 15)
|
||||||
|
Text("Plan")
|
||||||
|
.font(.callout.weight(.medium))
|
||||||
|
Spacer(minLength: 0)
|
||||||
|
}
|
||||||
|
MarkdownText(markdown: plan.markdown)
|
||||||
|
.textSelection(.enabled)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 12).padding(.vertical, 10)
|
||||||
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
.background(accent.opacity(0.06))
|
||||||
|
.overlay(RoundedRectangle(cornerRadius: 8).strokeBorder(accent.opacity(0.16), lineWidth: 1))
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -581,6 +581,7 @@ enum ToolGlyph {
|
|||||||
case "Task", "Agent", ToolGroup.orchestraSubagentToolName: 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 ExitPlanMode.toolName: return "list.bullet.clipboard"
|
||||||
case HostCommandSummary.hostExecToolName: return "desktopcomputer"
|
case HostCommandSummary.hostExecToolName: return "desktopcomputer"
|
||||||
default: return "wrench.and.screwdriver"
|
default: return "wrench.and.screwdriver"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ struct ToolGroup: Equatable {
|
|||||||
name == "Task" || name == "Agent" || name == Self.orchestraSubagentToolName
|
name == "Task" || name == "Agent" || name == Self.orchestraSubagentToolName
|
||||||
}
|
}
|
||||||
var isAskUserQuestion: Bool { name == "AskUserQuestion" }
|
var isAskUserQuestion: Bool { name == "AskUserQuestion" }
|
||||||
|
var isExitPlanMode: Bool { name == ExitPlanMode.toolName }
|
||||||
|
|
||||||
/// 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
|
||||||
/// detect a git-commit pipeline that should read as a structured commit card at the row level,
|
/// detect a git-commit pipeline that should read as a structured commit card at the row level,
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ struct TranscriptRow: View {
|
|||||||
SubagentCard(group: group)
|
SubagentCard(group: group)
|
||||||
} else if let card = answeredQuestionCard(group) {
|
} else if let card = answeredQuestionCard(group) {
|
||||||
card
|
card
|
||||||
|
} else if let plan = planCard(group) {
|
||||||
|
plan
|
||||||
} else if let card = gitCommitRowCard(group) {
|
} else if let card = gitCommitRowCard(group) {
|
||||||
card
|
card
|
||||||
} else if group.isHostExec {
|
} else if group.isHostExec {
|
||||||
@@ -78,6 +80,15 @@ struct TranscriptRow: View {
|
|||||||
return AskUserQuestionResultCard(questions: questions, answers: answers)
|
return AskUserQuestionResultCard(questions: questions, answers: answers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The plan an `ExitPlanMode` call presents, rendered as formatted Markdown rather than the
|
||||||
|
/// escaped-JSON blob the generic tool card would show — the phone echo of the Mac's `planCard`.
|
||||||
|
/// Nil for any other tool (which keeps the normal collapsible card) and for a call with no plan
|
||||||
|
/// text. The plan is on the call input, so it shows whether or not the user has approved it yet.
|
||||||
|
private func planCard(_ group: ToolGroup) -> ExitPlanModeCard? {
|
||||||
|
guard group.isExitPlanMode, let plan = ExitPlanMode.plan(from: group.input) else { return nil }
|
||||||
|
return ExitPlanModeCard(plan: plan)
|
||||||
|
}
|
||||||
|
|
||||||
/// A git-commit `Bash` pipeline rendered as the structured commit card the Mac shows at the row
|
/// A git-commit `Bash` pipeline rendered as the structured commit card the Mac shows at the row
|
||||||
/// level (subject + Markdown body + the new hash + "Show command"), or nil for any non-commit
|
/// level (subject + Markdown body + the new hash + "Show command"), or nil for any non-commit
|
||||||
/// call — which keeps the normal collapsible tool card. Mirrors the Mac's `gitCommitCard`.
|
/// call — which keeps the normal collapsible tool card. Mirrors the Mac's `gitCommitCard`.
|
||||||
|
|||||||
Reference in New Issue
Block a user