Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion panel/Panel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2743,12 +2743,25 @@ final class PanelController: NSObject, NSApplicationDelegate, PanelKeyDelegate,
let session = sessions.sessions.first(where: { $0.pid == pid }),
let bundleID = bundleID(for: session.terminalApp) else { return }
hidePanel()
// session.tabId is the per-tab identity our terminal integrations
// captured, but the underlying value differs per terminal — so it
// has to reach AppActivator via the parameter that terminal's
// activation path reads. VSCode/Cursor/Antigravity store
// VSCODE_IPC_HOOK_CLI (→ ipcHook, disambiguates windows for
// --reuse-window); iTerm2 stores its session GUID (→ sessionID,
// selects the exact pane). Ghostty/Warp/Terminal fall back to
// projectPath / AX tab-title and need neither. Without this the
// captured tabId was dropped and focus landed on whatever window
// the app last had frontmost.
let ipcHook = VSCodeIntegration.isVSCodeHosted(session.terminalApp) ? session.tabId : nil
let sessionID = session.terminalApp?.contains("iTerm") == true ? session.tabId : nil
DispatchQueue.global(qos: .userInitiated).async {
AppActivator.activate(
bundleID: bundleID,
windowTitle: session.projectName,
ipcHook: nil,
ipcHook: ipcHook,
projectPath: session.projectPath,
sessionID: sessionID,
sendApproval: false,
agent: session.agent
)
Expand Down
22 changes: 20 additions & 2 deletions panel/SessionStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,24 @@ final class SessionStore: ObservableObject {
"iTerm2", "iTerm", "Terminal", "Warp", "WarpTerminal", "ghostty", "Ghostty",
]

// Resolve a raw `ps` process name to the canonical terminal-app name the
// rest of the app keys off (bundleID lookup, iTerm enrichment, focus).
// Most terminals present with a stable name already in `terminalApps`.
// iTerm2 3.5+ is the exception: each session runs under a detached
// `iTermServer-<version>` daemon (session restoration) parented to
// launchd, not under the iTerm2 app — so the process name is
// version-suffixed (e.g. "iTermServer-3.6.11") and never equals "iTerm2",
// and the app itself isn't in the parent chain to walk up to. Left
// unmapped, those sessions get no terminalApp — which drops their tab
// enrichment and makes Enter-to-focus a silent no-op. Map the daemon back
// to "iTerm2" so every downstream check (which matches "iTerm2" exactly or
// via contains("iTerm")) recognises it.
private static func canonicalTerminalApp(_ processName: String) -> String? {
if terminalApps.contains(processName) { return processName }
if processName.hasPrefix("iTermServer") { return "iTerm2" }
return nil
}

private static func readProcessTable() -> [Int: ProcessInfo] {
let output = runProcess("/bin/ps", ["-axww", "-o", "pid=,ppid=,comm="])
var result: [Int: ProcessInfo] = [:]
Expand Down Expand Up @@ -473,9 +491,9 @@ final class SessionStore: ObservableObject {
let info = processTable[next]
else { break }
let base = (info.command as NSString).lastPathComponent
if terminalApps.contains(base) {
if let canonical = canonicalTerminalApp(base) {
chain.terminalPID = next
chain.terminalApp = base
chain.terminalApp = canonical
return chain
}
current = info.parentPID
Expand Down
6 changes: 5 additions & 1 deletion shared/AppActivator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,11 @@ struct AppActivator {
repeat with t in tabs of w
repeat with s in sessions of t
try
if (id of s as text) is target then
-- Match on `unique id` (the persistent session GUID that
-- both ITERM_SESSION_ID and our tab enrichment carry);
-- keep `id` as a fallback for iTerm2 versions where the
-- two properties diverge.
if ((unique id of s) as text) is target or ((id of s) as text) is target then
tell w to select
tell t to select
tell s to select
Expand Down