From eefca3e1178644e2e098cd0a7e0e785eae786931 Mon Sep 17 00:00:00 2001 From: onevcat Date: Thu, 30 Jul 2026 01:07:56 +0900 Subject: [PATCH] fix: build palette launch items for the focused Canvas card Fourth review round: the Launch Agent item factory only looked at selectedTerminalWorktree, which is nil in Canvas, so the palette showed no launch rows there even though the launch action itself already resolves to the focused card. The factory now mirrors the action's target resolution (selected terminal worktree, else the action-target worktree the palette already threads through). Canvas regression test included. Claude-Session: https://claude.ai/code/session_011y9A9ZLzhQ84EWXiQ5La5b --- docs-ai/053-agent-profiles/000-plan.md | 3 +++ .../Reducer/CommandPaletteFeature.swift | 27 ++++++++++++++----- .../AppFeatureAgentProfileTests.swift | 23 ++++++++++++++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/docs-ai/053-agent-profiles/000-plan.md b/docs-ai/053-agent-profiles/000-plan.md index 0c396b01..7f0db1b2 100644 --- a/docs-ai/053-agent-profiles/000-plan.md +++ b/docs-ai/053-agent-profiles/000-plan.md @@ -330,6 +330,9 @@ agent 列表不变。 ## Amendments +- 2026-07-30 — Review 四轮(P2):palette 的 Launch Agent 条目工厂改用与 launch + action 相同的 action-target 解析(selectedTerminalWorktree ?? Canvas 聚焦卡), + Canvas 模式下条目不再缺席;补 Canvas 聚焦卡回归测试。 - 2026-07-30 — Review 三轮(P2/P3):(a) surface 的 launch 身份增加 runtime,config root 只对**同 runtime 的检测**生效——bound pane 内手动启动其他 agent 时不再张冠 李戴、也不再压制默认布局扫描;(b) 删除确认的判断从"当前 bindsDedicatedHome 意愿" diff --git a/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift b/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift index dffafa52..14b0aa13 100644 --- a/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift +++ b/supacode/Features/CommandPalette/Reducer/CommandPaletteFeature.swift @@ -262,7 +262,12 @@ struct CommandPaletteFeature { } items.append(contentsOf: customCommandItems(customCommands)) items.append(contentsOf: handoffCommandItems(repositories)) - items.append(contentsOf: agentProfileLaunchItems(repositories)) + items.append( + contentsOf: agentProfileLaunchItems( + repositories, + actionTargetWorktreeID: worktreeActionTargetID + ) + ) if let terminalWorktree = repositories.selectedTerminalWorktree { items.append( CommandPaletteItem( @@ -532,12 +537,20 @@ private func customCommandItems(_ commands: [EffectiveCustomCommand]) -> [Comman } } -/// Launch rows for enabled agent profiles: the selected worktree's -/// Recommended profile first, then list order. Dispatches the same single -/// profile-launch action as the toolbar Agents menu (docs-ai 053) — the -/// palette is an entry point, never a second launch path. Internal for tests. -func agentProfileLaunchItems(_ repositories: RepositoriesFeature.State) -> [CommandPaletteItem] { - guard let worktree = repositories.selectedTerminalWorktree else { return [] } +/// Launch rows for enabled agent profiles: the target worktree's Recommended +/// profile first, then list order. Dispatches the same single profile-launch +/// action as the toolbar Agents menu (docs-ai 053) — the palette is an entry +/// point, never a second launch path. The target mirrors the launch action's +/// resolution: the selected terminal worktree in Normal mode, the focused +/// Canvas card otherwise. Internal for tests. +func agentProfileLaunchItems( + _ repositories: RepositoriesFeature.State, + actionTargetWorktreeID: Worktree.ID? = nil +) -> [CommandPaletteItem] { + let target = + repositories.selectedTerminalWorktree + ?? actionTargetWorktreeID.flatMap { repositories.worktree(for: $0) } + guard let worktree = target else { return [] } @Shared(.userGlobalSettings) var globalSettings let profiles = globalSettings.agentProfiles let enabled = profiles.filter(\.isEnabled) diff --git a/supacodeTests/AppFeatureAgentProfileTests.swift b/supacodeTests/AppFeatureAgentProfileTests.swift index 568c7c8b..5c7e4428 100644 --- a/supacodeTests/AppFeatureAgentProfileTests.swift +++ b/supacodeTests/AppFeatureAgentProfileTests.swift @@ -124,6 +124,29 @@ struct AppFeatureAgentProfileTests { } } + @Test(.dependencies) func paletteBuildsLaunchItemsForFocusedCanvasCard() { + let worktree = makeWorktree() + var repositories = makeRepositoriesState(worktree: worktree) + // Canvas: no selected terminal worktree, only the focused card passed as + // the action target. + repositories.selection = nil + let storage = SettingsTestStorage() + let localStorage = RepositoryLocalSettingsTestStorage() + withDependencies { + $0.settingsFileStorage = storage.storage + $0.repositoryLocalSettingsStorage = localStorage.storage + } operation: { + let profile = AgentProfile(name: "Codex", runtime: .codex) + @Shared(.userGlobalSettings) var settings + $settings.withLock { $0.agentProfiles = [profile] } + + #expect(agentProfileLaunchItems(repositories).isEmpty) + let items = agentProfileLaunchItems(repositories, actionTargetWorktreeID: worktree.id) + #expect(items.map(\.title) == ["Launch Agent: Codex"]) + #expect(items.first?.subtitle?.contains(worktree.name) == true) + } + } + @Test func launchedSurfaceEntryShowsProfileName() { var entry = ActiveAgentEntry( id: UUID(), -- 2.51.2