Files
orca/src/cli/handlers/worktree-gitlab-link-context.ts
T
Neil abd1fcf217 fix(cli): worktree create sends the host --project/--host selected (#31066)
* fix(cli): worktree create sends the host --project/--host selected

Codex review 6 #6: the CLI picked the right setup but sent only its repo id,
so a repo id set up on two hosts failed as selector_ambiguous; and
--project-host-setup ignored --host when setup ids repeated.

worktree.create gains optional repoHostId (older hosts drop it and keep the
old behaviour); the runtime narrows the repo selector to that host.

* refactor(runtime): the repo selector carries its host through every lookup

Review follow-up (Codex + Opus on #31066): a separate repoHostId was dropped
by the startup-agent lookup, the CLI's GitLab link check and the create
dedupe key. RuntimeRepoSelector now carries the host with the selector, so
showRepo/resolveRepoSelector and startup-agent resolution keep it; the
create dedupe key includes it; repo.show gains the same optional
repoHostId; the CLI spreads one CliRepoTarget into every repo lookup.
Handler-level tests cover worktree.create (plain, startupAgent,
startupDraft), agent.launch, repo.show and the dedupe key.

* test(runtime): drop a needless cast in the agent.launch host test; fold an import
2026-10-20 02:57:14 -07:00

55 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { parseRemoteProjectRefCandidate } from '../../main/gitlab/project-ref-parser'
import type { Repo } from '../../shared/repo-types'
import type { RuntimeWorktreeRecord } from '../../shared/runtime-types'
import { parseGitLabIssueOrMRLink, type ProjectSlug } from '../../shared/new-workspace/gitlab-links'
import { RuntimeClientError, type RuntimeClient } from '../runtime-client'
import type { CliRepoTarget } from '../worktree-project-target'
export async function assertGitLabLinkFlagProjectsMatch(
flags: Map<string, string | boolean>,
client: RuntimeClient,
target: CliRepoTarget | { worktree: string }
): Promise<void> {
const projects = ['gitlab-issue', 'gitlab-mr'].flatMap((name) => {
const value = flags.get(name)
const link =
typeof value === 'string' && /^https?:\/\//i.test(value.trim())
? parseGitLabIssueOrMRLink(value)
: null
return link ? [link.slug] : []
})
if (projects.length === 0) {
return
}
let project: ProjectSlug | null = null
let repoTarget: CliRepoTarget
if ('worktree' in target) {
const result = await client.call<{ worktree: RuntimeWorktreeRecord }>('worktree.show', target)
const context = result.result.worktree.linkedTaskSourceContext
const identity = context?.providerIdentity
if (context?.provider === 'gitlab' && identity?.provider === 'gitlab' && identity.webUrl) {
project = parseRemoteProjectRefCandidate(identity.webUrl)
}
repoTarget = { repo: `id:${result.result.worktree.repoId}` }
} else {
repoTarget = target
}
if (!project) {
const result = await client.call<{ repo: Repo }>('repo.show', repoTarget)
const remoteUrl = result.result.repo.gitRemoteIdentity?.remoteUrl
project = remoteUrl ? parseRemoteProjectRefCandidate(remoteUrl) : null
}
// Numeric slots cannot retain a pasted URL's foreign host or project.
if (
!project ||
projects.some((link) => link.host !== project.host || link.path !== project.path)
) {
throw new RuntimeClientError(
'invalid_argument',
'The GitLab URL must match the workspace source project or the repository’s stored remote. Use a number for an item in that project; URLs cannot choose a different project.'
)
}
}