mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 08:03:33 +00:00
fix(skills): trust SSH PTY pane mirrors
This commit is contained in:
@@ -38,10 +38,14 @@ function worktreeMeta(hostId: WorktreeMeta['hostId']): WorktreeMeta {
|
||||
}
|
||||
}
|
||||
|
||||
function session(worktreeId: string, startupCwd?: string): WorkspaceSessionState {
|
||||
function session(
|
||||
worktreeId: string,
|
||||
startupCwd?: string,
|
||||
ptyId: string | null = null
|
||||
): WorkspaceSessionState {
|
||||
return {
|
||||
tabsByWorktree: {
|
||||
[worktreeId]: [{ id: 'tab-1', startupCwd }]
|
||||
[worktreeId]: [{ id: 'tab-1', ptyId, startupCwd }]
|
||||
}
|
||||
} as WorkspaceSessionState
|
||||
}
|
||||
@@ -83,6 +87,74 @@ describe('resolvePaneSkillDiscoveryWorkspace', () => {
|
||||
).toEqual({ connectionId: 'target-1', cwd: '/work/demo-project' })
|
||||
})
|
||||
|
||||
it('accepts a legacy local SSH PTY mirror that omits its startup directory', () => {
|
||||
const worktreeId = 'repo-1::/work/demo-project'
|
||||
const ptyId = 'ssh:target-1@@pty-1'
|
||||
|
||||
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, undefined, ptyId) },
|
||||
{
|
||||
hostId: 'ssh:target-1',
|
||||
session: session(worktreeId, '/work/demo-project', ptyId)
|
||||
}
|
||||
]
|
||||
})
|
||||
).toEqual({ connectionId: 'target-1', cwd: '/work/demo-project' })
|
||||
})
|
||||
|
||||
it('rejects missing startup-directory mirrors with different PTY identities', () => {
|
||||
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, undefined, 'ssh:target-1@@pty-1') },
|
||||
{
|
||||
hostId: 'ssh:target-1',
|
||||
session: session(worktreeId, '/work/demo-project', 'ssh:target-1@@pty-2')
|
||||
}
|
||||
]
|
||||
})
|
||||
).toThrow('pane_skill_discovery_owner_ambiguous')
|
||||
})
|
||||
|
||||
it('rejects a matching PTY identity from a different SSH target', () => {
|
||||
const worktreeId = 'repo-1::/work/demo-project'
|
||||
const ptyId = 'ssh:target-2@@pty-1'
|
||||
|
||||
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, undefined, ptyId) },
|
||||
{
|
||||
hostId: 'ssh:target-1',
|
||||
session: session(worktreeId, '/work/demo-project', ptyId)
|
||||
}
|
||||
]
|
||||
})
|
||||
).toThrow('pane_skill_discovery_owner_ambiguous')
|
||||
})
|
||||
|
||||
it('accepts normalized Windows variants of a mirrored SSH startup directory', () => {
|
||||
const worktreeId = 'repo-1::C:\\Repo'
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
toSshExecutionHostId,
|
||||
type ExecutionHostId
|
||||
} from '../../shared/execution-host'
|
||||
import { parseAppSshPtyId } from '../../shared/ssh-pty-id'
|
||||
import type {
|
||||
FolderWorkspace,
|
||||
ProjectGroup,
|
||||
@@ -174,7 +175,7 @@ function findPaneSession(
|
||||
worktreeId: string,
|
||||
terminalTabId: string | undefined,
|
||||
authoritativeHostId?: ExecutionHostId | null
|
||||
): { hostId: ExecutionHostId; tab: { startupCwd?: string } } | null {
|
||||
): { hostId: ExecutionHostId; tab: { ptyId: string | null; startupCwd?: string } } | null {
|
||||
if (!terminalTabId) {
|
||||
return null
|
||||
}
|
||||
@@ -183,7 +184,7 @@ function findPaneSession(
|
||||
worktreeIdsEqual(candidateWorktreeId, worktreeId)
|
||||
? tabs
|
||||
.filter((tab) => tab.id === terminalTabId)
|
||||
.map((tab) => ({ hostId, tab: { startupCwd: tab.startupCwd } }))
|
||||
.map((tab) => ({ hostId, tab: { ptyId: tab.ptyId, startupCwd: tab.startupCwd } }))
|
||||
: []
|
||||
)
|
||||
)
|
||||
@@ -200,7 +201,7 @@ function findPaneSession(
|
||||
(match) =>
|
||||
match === authoritativeMatch ||
|
||||
(match.hostId === LOCAL_EXECUTION_HOST_ID &&
|
||||
paneSessionsMirror(match.tab, authoritativeMatch.tab))
|
||||
paneSessionsMirror(match.tab, authoritativeMatch.tab, authoritativeMatch.hostId))
|
||||
)
|
||||
) {
|
||||
return authoritativeMatch
|
||||
@@ -211,13 +212,19 @@ function findPaneSession(
|
||||
}
|
||||
|
||||
function paneSessionsMirror(
|
||||
left: { startupCwd?: string },
|
||||
right: { startupCwd?: string }
|
||||
left: { ptyId: string | null; startupCwd?: string },
|
||||
right: { ptyId: string | null; startupCwd?: string },
|
||||
authoritativeHostId: ExecutionHostId
|
||||
): boolean {
|
||||
const leftCwd = left.startupCwd?.trim() || null
|
||||
const rightCwd = right.startupCwd?.trim() || null
|
||||
if (!leftCwd || !rightCwd) {
|
||||
return leftCwd === rightCwd
|
||||
if (leftCwd === rightCwd) {
|
||||
return true
|
||||
}
|
||||
const host = parseExecutionHostId(authoritativeHostId)
|
||||
const pty = left.ptyId && left.ptyId === right.ptyId ? parseAppSshPtyId(left.ptyId) : null
|
||||
return host?.kind === 'ssh' && pty?.connectionId === host.targetId
|
||||
}
|
||||
return normalizeRuntimePathForComparison(leftCwd) === normalizeRuntimePathForComparison(rightCwd)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user