mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
fix(agent-hooks): route the first-work branch rename by the repo's execution host (#27080)
* fix(agent-hooks): route the first-work branch rename by the repo's execution host * fix(agent-hooks): state runtime branch ownership without overclaiming server wiring --------- Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
This commit is contained in:
@@ -21,7 +21,7 @@ const {
|
||||
gitExecFileAsyncMock: vi.fn(),
|
||||
resolveLocalGitUsernameMock: vi.fn(async () => 'you'),
|
||||
getSshGitUsernameMock: vi.fn(async () => 'you'),
|
||||
getSshGitProviderMock: vi.fn(() => undefined),
|
||||
getSshGitProviderMock: vi.fn((_connectionId: string): unknown => undefined),
|
||||
generateBranchNameMock: vi.fn(),
|
||||
resolveTextGenerationParamsMock: vi.fn(),
|
||||
prepareLocalEnvMock: vi.fn(async () => ({ ok: true as const })),
|
||||
@@ -65,6 +65,14 @@ import {
|
||||
} from './first-work-branch-rename-test-harness'
|
||||
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'
|
||||
|
||||
const REMOTE_REPO_BASE: Repo = {
|
||||
id: REPO_ID,
|
||||
path: '/repo',
|
||||
displayName: 'repo',
|
||||
badgeColor: '',
|
||||
addedAt: 0
|
||||
}
|
||||
|
||||
function makeDeps(overrides: Partial<FirstWorkBranchRenameDeps> = {}) {
|
||||
return makeBranchRenameDeps(vi.fn, overrides)
|
||||
}
|
||||
@@ -733,4 +741,44 @@ describe('maybeAutoRenameBranchOnFirstWork', () => {
|
||||
expect(provider.renameCurrentBranch).toHaveBeenCalledWith('/repo/wt', 'you/fix-auth')
|
||||
expect(onRenamed).toHaveBeenCalledWith(REPO_ID)
|
||||
})
|
||||
|
||||
it('routes a row that names its SSH owner only as executionHostId to that target', async () => {
|
||||
const provider = {
|
||||
exec: vi.fn(gitResponder({ currentBranch: 'you/Nautilus', hasUpstream: false })),
|
||||
renameCurrentBranch: vi.fn(async () => undefined),
|
||||
executeCommitMessagePlan: vi.fn()
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(provider)
|
||||
const repo: Repo = { ...REMOTE_REPO_BASE, executionHostId: 'ssh:ssh-1' }
|
||||
const { deps } = makeDeps({ getRepo: () => repo })
|
||||
|
||||
await maybeAutoRenameBranchOnFirstWork(workingEvent(), deps)
|
||||
|
||||
expect(getSshGitProviderMock).toHaveBeenCalledWith('ssh-1')
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
expect(provider.renameCurrentBranch).toHaveBeenCalledWith('/repo/wt', 'you/fix-auth')
|
||||
})
|
||||
|
||||
it("never dials a paired server's nested SSH target from this client", async () => {
|
||||
const provider = {
|
||||
exec: vi.fn(gitResponder({ currentBranch: 'you/Nautilus', hasUpstream: false })),
|
||||
renameCurrentBranch: vi.fn(async () => undefined),
|
||||
executeCommitMessagePlan: vi.fn()
|
||||
}
|
||||
getSshGitProviderMock.mockReturnValue(provider)
|
||||
const repo: Repo = {
|
||||
...REMOTE_REPO_BASE,
|
||||
connectionId: 'ssh-1',
|
||||
executionHostId: 'runtime:env-1'
|
||||
}
|
||||
const { deps, onRenamed } = makeDeps({ getRepo: () => repo })
|
||||
|
||||
await maybeAutoRenameBranchOnFirstWork(workingEvent(), deps)
|
||||
|
||||
expect(getSshGitProviderMock).not.toHaveBeenCalled()
|
||||
expect(provider.exec).not.toHaveBeenCalled()
|
||||
expect(gitExecFileAsyncMock).not.toHaveBeenCalled()
|
||||
expect(generateBranchNameMock).not.toHaveBeenCalled()
|
||||
expect(onRenamed).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -14,7 +14,8 @@ import { getCommitMessageModelDiscoveryHostKey } from '../../shared/commit-messa
|
||||
import { computeBranchName, getConfiguredBranchPrefix } from '../ipc/worktree-logic'
|
||||
import { gitExecFileAsync } from '../git/runner'
|
||||
import { getSshGitUsername, resolveLocalGitUsername } from '../git/git-username'
|
||||
import { getSshGitProvider } from '../providers/ssh-git-dispatch'
|
||||
import { resolveGitRouteForHost } from '../providers/execution-host-provider-dispatch'
|
||||
import { getRepoExecutionHostId } from '../../shared/execution-host'
|
||||
import {
|
||||
probeBranchUpstream,
|
||||
renameCurrentBranch,
|
||||
@@ -176,10 +177,15 @@ async function runAutoRename(
|
||||
}
|
||||
const worktreePath = parsed.worktreePath
|
||||
|
||||
const provider = repo.connectionId ? (getSshGitProvider(repo.connectionId) ?? null) : null
|
||||
if (repo.connectionId && !provider) {
|
||||
// Why: a runtime row's connectionId names the server's own SSH target; that host owns the branch, never this client.
|
||||
const route = resolveGitRouteForHost(getRepoExecutionHostId(repo))
|
||||
if (route.kind === 'runtime') {
|
||||
return stop(`branch is owned by ${route.hostId}`)
|
||||
}
|
||||
if (route.kind === 'ssh' && !route.provider) {
|
||||
return retry('ssh provider unavailable')
|
||||
}
|
||||
const provider = route.kind === 'ssh' ? route.provider : null
|
||||
const exec: GitExec = provider
|
||||
? (args) => provider.exec(args, worktreePath)
|
||||
: (args) => gitExecFileAsync(args, { cwd: worktreePath })
|
||||
@@ -212,7 +218,9 @@ async function runAutoRename(
|
||||
}
|
||||
|
||||
const settings = deps.getSettings()
|
||||
const hostKey = getCommitMessageModelDiscoveryHostKey(repo.connectionId ?? null)
|
||||
const hostKey = getCommitMessageModelDiscoveryHostKey(
|
||||
route.kind === 'ssh' ? route.connectionId : null
|
||||
)
|
||||
const resolvedParams = resolveTextGenerationParams(settings, hostKey, 'branchName', repo)
|
||||
if (!resolvedParams.ok) {
|
||||
// Why: a generation-step failure (vs a benign skip) is user-actionable, so surface it on the card.
|
||||
|
||||
Reference in New Issue
Block a user