fix(skills): accept mirrored SSH pane session

This commit is contained in:
Brennan Benson
2026-08-05 18:50:13 -07:00
parent 1b5c7ec251
commit 3d46367282
2 changed files with 108 additions and 3 deletions
@@ -1,5 +1,11 @@
import { describe, expect, it } from 'vitest'
import type { FolderWorkspace, ProjectGroup, Repo, WorkspaceSessionState } from '../../shared/types'
import type {
FolderWorkspace,
ProjectGroup,
Repo,
WorktreeMeta,
WorkspaceSessionState
} from '../../shared/types'
import { resolvePaneSkillDiscoveryWorkspace } from './pane-skill-discovery-workspace'
const EMPTY_SESSION = { tabsByWorktree: {} } as WorkspaceSessionState
@@ -16,6 +22,22 @@ function repo(overrides: Partial<Repo> = {}): Repo {
}
}
function worktreeMeta(hostId: WorktreeMeta['hostId']): WorktreeMeta {
return {
hostId,
displayName: 'repo',
comment: '',
linkedIssue: null,
linkedPR: null,
linkedLinearIssue: null,
isArchived: false,
isUnread: false,
isPinned: false,
sortOrder: 0,
lastActivityAt: 1
}
}
function session(worktreeId: string, startupCwd?: string): WorkspaceSessionState {
return {
tabsByWorktree: {
@@ -42,6 +64,63 @@ describe('resolvePaneSkillDiscoveryWorkspace', () => {
).toEqual({ connectionId: 'target-1', cwd: '/remote/repo/packages/app' })
})
it('accepts the legacy local mirror of an authoritative SSH pane session', () => {
const worktreeId = 'repo-1::/work/demo-project'
expect(
resolvePaneSkillDiscoveryWorkspace({
worktreeId,
terminalTabId: 'tab-1',
repos: [repo({ path: '/work/demo-project' })],
projectGroups: [],
folderWorkspaces: [],
worktreeMeta: worktreeMeta('ssh:target-1'),
sessions: [
{ hostId: 'local', session: session(worktreeId, '/work/demo-project') },
{ hostId: 'ssh:target-1', session: session(worktreeId, '/work/demo-project') }
]
})
).toEqual({ connectionId: 'target-1', cwd: '/work/demo-project' })
})
it('rejects duplicate pane sessions on distinct non-local hosts', () => {
const worktreeId = 'repo-1::/remote/repo'
expect(() =>
resolvePaneSkillDiscoveryWorkspace({
worktreeId,
terminalTabId: 'tab-1',
repos: [repo()],
projectGroups: [],
folderWorkspaces: [],
worktreeMeta: worktreeMeta('ssh:target-1'),
sessions: [
{ hostId: 'ssh:target-1', session: session(worktreeId) },
{ hostId: 'ssh:target-2', session: session(worktreeId) }
]
})
).toThrow('pane_skill_discovery_owner_ambiguous')
})
it('rejects a legacy local pane that does not mirror the SSH startup directory', () => {
const worktreeId = 'repo-1::/remote/repo'
expect(() =>
resolvePaneSkillDiscoveryWorkspace({
worktreeId,
terminalTabId: 'tab-1',
repos: [repo()],
projectGroups: [],
folderWorkspaces: [],
worktreeMeta: worktreeMeta('ssh:target-1'),
sessions: [
{ hostId: 'local', session: session(worktreeId, '/local/repo') },
{ hostId: 'ssh:target-1', session: session(worktreeId, '/remote/repo') }
]
})
).toThrow('pane_skill_discovery_owner_ambiguous')
})
it('routes an executionHostId-only SSH repo instead of falling back locally', () => {
expect(
resolvePaneSkillDiscoveryWorkspace({
@@ -38,9 +38,9 @@ export function resolvePaneSkillDiscoveryWorkspace(
): PaneSkillDiscoveryWorkspace {
const scope = parseWorkspaceKey(args.worktreeId)
const worktreeId = scope?.type === 'worktree' ? scope.worktreeId : args.worktreeId
const sessionOwner = findPaneSession(args.sessions, worktreeId, args.terminalTabId)
if (scope?.type === 'folder') {
const sessionOwner = findPaneSession(args.sessions, worktreeId, args.terminalTabId)
const workspace = selectFolderWorkspace(
args.folderWorkspaces.filter((candidate) => candidate.id === scope.folderWorkspaceId),
sessionOwner?.hostId
@@ -72,6 +72,7 @@ export function resolvePaneSkillDiscoveryWorkspace(
throw new Error('pane_skill_discovery_workspace_not_found')
}
const metaHostId = parseOptionalHostId(args.worktreeMeta?.hostId)
const sessionOwner = findPaneSession(args.sessions, worktreeId, args.terminalTabId, metaHostId)
assertMatchingHost(sessionOwner?.hostId, metaHostId)
const knownHostId = sessionOwner?.hostId ?? metaHostId
const repo = selectPaneRepo(candidates, knownHostId)
@@ -171,7 +172,8 @@ function declaredHostId(owner: {
function findPaneSession(
sessions: readonly HostSession[],
worktreeId: string,
terminalTabId: string | undefined
terminalTabId: string | undefined,
authoritativeHostId?: ExecutionHostId | null
): { hostId: ExecutionHostId; tab: { startupCwd?: string } } | null {
if (!terminalTabId) {
return null
@@ -186,11 +188,35 @@ function findPaneSession(
)
)
if (matches.length > 1) {
const authoritativeMatches = authoritativeHostId
? matches.filter((match) => match.hostId === authoritativeHostId)
: []
const authoritativeMatch = authoritativeMatches.length === 1 ? authoritativeMatches[0] : null
// Why: save compatibility mirrors remote tabs locally; only matching local rows yield to persisted ownership.
if (
authoritativeHostId !== LOCAL_EXECUTION_HOST_ID &&
authoritativeMatch &&
matches.every(
(match) =>
match === authoritativeMatch ||
(match.hostId === LOCAL_EXECUTION_HOST_ID &&
paneSessionsMirror(match.tab, authoritativeMatch.tab))
)
) {
return authoritativeMatch
}
throw new Error('pane_skill_discovery_owner_ambiguous')
}
return matches[0] ?? null
}
function paneSessionsMirror(
left: { startupCwd?: string },
right: { startupCwd?: string }
): boolean {
return (left.startupCwd?.trim() || null) === (right.startupCwd?.trim() || null)
}
function selectPaneRepo(candidates: readonly Repo[], hostId: ExecutionHostId | null): Repo {
if (!hostId) {
if (candidates.length !== 1) {