From b8eed05ef1df8a747e8de30209684ace51ee79eb Mon Sep 17 00:00:00 2001 From: onevcat Date: Mon, 20 Jul 2026 19:34:36 +0900 Subject: [PATCH] Rewrite hand-off copy in plain language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The popover's read-only info line becomes the explanation under the Hand Off row itself — one button, highlighted as a whole on hover. The wording now states the outcome directly ('Pass this task to another agent in a new tab', plus 'codex will summarize its progress first' when the session is resumable) instead of the jargon 'codex will brief the incoming agent'. The same vocabulary flows through the HUD: 'Only save progress' target row, 'Collect progress summary from codex' stage, 'Saving progress' / 'Progress saved' brief-only states, and the finished subtitle. Docs updated to match. --- docs/components/command-palette.md | 4 +- docs/components/handoff.md | 34 ++++++++-------- .../Reducer/HandoffHudFeature.swift | 2 +- .../Views/HandoffHudOverlayView.swift | 21 +++++----- .../Views/AgentsToolbarButton.swift | 40 +++++++++---------- .../Views/WorktreeDetailToolbarViews.swift | 2 +- .../Views/WorktreeDetailView.swift | 5 ++- 7 files changed, 56 insertions(+), 52 deletions(-) diff --git a/docs/components/command-palette.md b/docs/components/command-palette.md index f09ef5c9..ab4e6dc2 100644 --- a/docs/components/command-palette.md +++ b/docs/components/command-palette.md @@ -47,8 +47,8 @@ selected worktree has a pull request). source. Same-titled commands can coexist; disabled commands do not appear. - **Handoff** (every runnable workspace, repository/worktree, or plain folder): a single **Hand Off…** row opens the staged Hand Off HUD, where you choose - the receiving agent (or update the brief only) and watch the run with Skip - and Cancel available during the source agent's briefing turn. Same flow as + the receiving agent (or save progress only) and watch the run with Skip and + Cancel available while the source agent summarizes its progress. Same flow as the toolbar Agents capsule. See [handoff](handoff.md). - **Debug** (Debug builds only): toast/update/dock simulations. diff --git a/docs/components/handoff.md b/docs/components/handoff.md index 9bc0b58d..63ecbcf0 100644 --- a/docs/components/handoff.md +++ b/docs/components/handoff.md @@ -130,26 +130,28 @@ for targets that have never run `prowl handoff save` or `prowl handoff to`. A capsule button left of the branch title identifies the selected pane's detected agent (badge and name — live status stays with the terminal and -the Active Agents panel). Clicking it opens a popover that previews what a -hand-off will do — "codex will brief the incoming agent first" when the -native session is resumable — and carries **Hand Off…**, which opens a -centered HUD. Future agent actions land in the same popover. The capsule is -disabled when no agent is detected in the selected pane. +the Active Agents panel). Clicking it opens a popover whose hand-off row +explains the action in place — "Pass this task to another agent in a new +tab", plus "codex will summarize its progress first" when the native session +is resumable — and opens a centered HUD. Future agent actions land in the +same popover. The capsule is disabled when no agent is detected in the +selected pane. The HUD runs in two steps: 1. **Choose** — pick the receiving agent (the current agent stays listed as a - fresh-session restart) or **Only brief, don't hand off**, which updates the - artifact without launching anything. Rows state read-only launch facts, - e.g. when an explicitly observed unrestricted mode carries over. There are - no other options; launch configuration follows the same adapter rules as - `prowl handoff to`. -2. **Run** — staged progress: collect the brief from the source agent, save - context, archive, launch. While the source agent writes its brief you can - **Skip** (continue immediately with the existing notes and fresh repo - state, `preparation=skipped`) or **Cancel** (abort entirely — the artifact - is untouched and nothing is logged, like Ctrl-C on the CLI). After the - brief the remaining steps are sub-second and cannot be interrupted. + fresh-session restart) or **Only save progress, don't hand off**, which + updates the artifact without launching anything. Rows state read-only + launch facts, e.g. when an explicitly observed unrestricted mode carries + over. There are no other options; launch configuration follows the same + adapter rules as `prowl handoff to`. +2. **Run** — staged progress: collect a progress summary from the source + agent, save context, archive, launch. While the source agent writes its + summary you can **Skip** (continue immediately with the existing notes and + fresh repo state, `preparation=skipped`) or **Cancel** (abort entirely — + the artifact is untouched and nothing is logged, like Ctrl-C on the CLI). + After the summary the remaining steps are sub-second and cannot be + interrupted. The Command Palette (`⌘P`) offers the same flow as a single **Hand Off…** row for any selected workspace, git repository, worktree, or plain folder; diff --git a/supacode/Features/HandoffHud/Reducer/HandoffHudFeature.swift b/supacode/Features/HandoffHud/Reducer/HandoffHudFeature.swift index 6c9914c6..2f512d15 100644 --- a/supacode/Features/HandoffHud/Reducer/HandoffHudFeature.swift +++ b/supacode/Features/HandoffHud/Reducer/HandoffHudFeature.swift @@ -115,7 +115,7 @@ struct HandoffHudFeature { targets.append( HandoffTargetOption( kind: .briefOnly, - title: "Only brief, don't hand off", + title: "Only save progress, don't hand off", subtitle: "Saves the current state for a later hand-off", isCurrentAgent: false ) diff --git a/supacode/Features/HandoffHud/Views/HandoffHudOverlayView.swift b/supacode/Features/HandoffHud/Views/HandoffHudOverlayView.swift index 4ba08413..a183d91c 100644 --- a/supacode/Features/HandoffHud/Views/HandoffHudOverlayView.swift +++ b/supacode/Features/HandoffHud/Views/HandoffHudOverlayView.swift @@ -95,12 +95,12 @@ private struct HandoffHudCard: View { case .agent: return "Handing off to \(run.target.title)" case .briefOnly: - return "Updating the brief" + return "Saving progress" } case .finished(.handedOff(let name)): return "Handed off to \(name)" case .finished(.briefSaved): - return "Brief updated" + return "Progress saved" case .finished(.failed): return "Hand off failed" } @@ -110,16 +110,17 @@ private struct HandoffHudCard: View { switch store.phase { case .choosing: if store.source.preparationRequest != nil { - return "\(store.source.displayName) will brief the incoming agent first" + return "Pass this task to another agent in a new tab. " + + "\(store.source.displayName) will summarize its progress first." } - return "Hands this task to another agent in a new tab" + return "Pass this task to another agent in a new tab." case .running(let run): if run.stage == .briefing { - return "\(store.source.displayName) is writing a brief for the next agent" + return "\(store.source.displayName) is summarizing its progress" } return "Preparing the hand-off…" case .finished(.handedOff): - return "The receiving agent starts from the hand-off notes in a new tab" + return "The receiving agent picks up the task in a new tab" case .finished(.briefSaved): return "The current state is saved for a later hand-off" case .finished(.failed(let message)): @@ -192,7 +193,7 @@ private struct HandoffHudChooseView: View { case .agent: return "Hand Off to \(target.title)" case .briefOnly: - return "Update Brief" + return "Save Progress" } } } @@ -264,7 +265,7 @@ private struct HandoffTargetRow: View { case .agent: return "Hand this task to \(target.title) in a new tab" case .briefOnly: - return "Update the hand-off notes without launching another agent" + return "Save the agent's progress for a later hand-off without launching anything" } } } @@ -290,7 +291,7 @@ private struct HandoffHudRunView: View { HStack { if run.stage == .briefing { - Text("This can take a moment while \(sourceDisplayName) writes its brief.") + Text("This can take a moment while \(sourceDisplayName) summarizes its progress.") .font(.caption) .foregroundStyle(.secondary) } @@ -345,7 +346,7 @@ private struct HandoffHudRunView: View { private func stageTitle(_ stage: HandoffStage) -> String { switch stage { case .briefing: - return "Collect brief from \(sourceDisplayName)" + return "Collect progress summary from \(sourceDisplayName)" case .saving: return "Save context" case .archiving: diff --git a/supacode/Features/Repositories/Views/AgentsToolbarButton.swift b/supacode/Features/Repositories/Views/AgentsToolbarButton.swift index 1a452386..530f28bd 100644 --- a/supacode/Features/Repositories/Views/AgentsToolbarButton.swift +++ b/supacode/Features/Repositories/Views/AgentsToolbarButton.swift @@ -9,7 +9,8 @@ struct AgentsCapsuleState: Equatable { /// the assembler with the same two-step token fallback the Active Agents /// panel uses, so a wrapper process name never loses the brand icon. let iconSource: TabIconSource? - /// Behavior preview shown as the popover's read-only first line. + /// Plain-language explanation of the hand-off action, shown under its + /// title in the popover row; varies with the source session's state. let infoLine: String } @@ -113,53 +114,52 @@ struct AgentsToolbarButton: View { } } -/// The agent-actions popover: a read-only behavior preview line and the -/// action list. Rows follow menu conventions (full-width highlight on -/// hover) so future actions slot in as additional rows. +/// The agent-actions popover. Each action is one full row — title with a +/// plain-language explanation underneath, highlighted together on hover — +/// so future actions slot in as additional rows. private struct AgentsPopoverContent: View { let capsule: AgentsCapsuleState let onHandOff: () -> Void var body: some View { - VStack(alignment: .leading, spacing: 6) { - Text(capsule.infoLine) - .font(.caption) - .foregroundStyle(.secondary) - .padding(.horizontal, 10) - .padding(.top, 10) - - Divider() - .padding(.horizontal, 6) - + VStack(alignment: .leading, spacing: 0) { AgentsPopoverRow( title: "Hand Off…", + subtitle: capsule.infoLine, systemImage: "arrow.left.arrow.right", action: onHandOff ) - .padding(.horizontal, 6) - .padding(.bottom, 6) } - .frame(width: 260, alignment: .leading) + .padding(6) + .frame(width: 280, alignment: .leading) } } private struct AgentsPopoverRow: View { let title: String + let subtitle: String let systemImage: String let action: () -> Void @State private var isHovered = false var body: some View { Button(action: action) { - HStack(spacing: 8) { + HStack(alignment: .top, spacing: 8) { Image(systemName: systemImage) .frame(width: 16) + .padding(.top, 2) .accessibilityHidden(true) - Text(title) + VStack(alignment: .leading, spacing: 2) { + Text(title) + Text(subtitle) + .font(.caption) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + } Spacer(minLength: 0) } .padding(.horizontal, 8) - .padding(.vertical, 5) + .padding(.vertical, 6) .contentShape(.rect) } .buttonStyle(.plain) diff --git a/supacode/Features/Repositories/Views/WorktreeDetailToolbarViews.swift b/supacode/Features/Repositories/Views/WorktreeDetailToolbarViews.swift index c20eae35..445b7560 100644 --- a/supacode/Features/Repositories/Views/WorktreeDetailToolbarViews.swift +++ b/supacode/Features/Repositories/Views/WorktreeDetailToolbarViews.swift @@ -251,7 +251,7 @@ private struct WorktreeToolbarPreview: View { agentsCapsule: AgentsCapsuleState( displayName: "codex", iconSource: CommandIconMap.iconForFirstToken("codex"), - infoLine: "codex will brief the incoming agent first" + infoLine: "Pass this task to another agent in a new tab. codex will summarize its progress first." ), statusToast: nil, pullRequest: nil, diff --git a/supacode/Features/Repositories/Views/WorktreeDetailView.swift b/supacode/Features/Repositories/Views/WorktreeDetailView.swift index 1c188258..119e1f46 100644 --- a/supacode/Features/Repositories/Views/WorktreeDetailView.swift +++ b/supacode/Features/Repositories/Views/WorktreeDetailView.swift @@ -403,8 +403,9 @@ struct WorktreeDetailView: View { displayName: agent.displayName, iconSource: iconSource, infoLine: resumable - ? "\(agent.displayName) will brief the incoming agent first" - : "Hands this task to another agent in a new tab" + ? "Pass this task to another agent in a new tab. " + + "\(agent.displayName) will summarize its progress first." + : "Pass this task to another agent in a new tab." ) } -- 2.51.2