(sessionData: SessionResource)
| 365 | * @returns Validation result with status and repo information |
| 366 | */ |
| 367 | export async function validateSessionRepository(sessionData: SessionResource): Promise<RepoValidationResult> { |
| 368 | const currentParsed = await detectCurrentRepositoryWithHost(); |
| 369 | const currentRepo = currentParsed ? `${currentParsed.owner}/${currentParsed.name}` : null; |
| 370 | const gitSource = sessionData.session_context.sources.find((source): source is GitSource => source.type === 'git_repository'); |
| 371 | if (!gitSource?.url) { |
| 372 | // Session has no repo requirement |
| 373 | logForDebugging(currentRepo ? 'Session has no associated repository, proceeding without validation' : 'Session has no repo requirement and not in git directory, proceeding'); |
| 374 | return { |
| 375 | status: 'no_repo_required' |
| 376 | }; |
| 377 | } |
| 378 | const sessionParsed = parseGitRemote(gitSource.url); |
| 379 | const sessionRepo = sessionParsed ? `${sessionParsed.owner}/${sessionParsed.name}` : parseGitHubRepository(gitSource.url); |
| 380 | if (!sessionRepo) { |
| 381 | return { |
| 382 | status: 'no_repo_required' |
| 383 | }; |
| 384 | } |
| 385 | logForDebugging(`Session is for repository: ${sessionRepo}, current repo: ${currentRepo ?? 'none'}`); |
| 386 | if (!currentRepo) { |
| 387 | // Not in a git repo, but session requires one |
| 388 | return { |
| 389 | status: 'not_in_repo', |
| 390 | sessionRepo, |
| 391 | sessionHost: sessionParsed?.host, |
| 392 | currentRepo: null |
| 393 | }; |
| 394 | } |
| 395 | |
| 396 | // Compare both owner/repo and host to avoid cross-instance mismatches. |
| 397 | // Strip ports before comparing hosts — SSH remotes omit the port while |
| 398 | // HTTPS remotes may include a non-standard port (e.g. ghe.corp.com:8443), |
| 399 | // which would cause a false mismatch. |
| 400 | const stripPort = (host: string): string => host.replace(/:\d+$/, ''); |
| 401 | const repoMatch = currentRepo.toLowerCase() === sessionRepo.toLowerCase(); |
| 402 | const hostMatch = !currentParsed || !sessionParsed || stripPort(currentParsed.host.toLowerCase()) === stripPort(sessionParsed.host.toLowerCase()); |
| 403 | if (repoMatch && hostMatch) { |
| 404 | return { |
| 405 | status: 'match', |
| 406 | sessionRepo, |
| 407 | currentRepo |
| 408 | }; |
| 409 | } |
| 410 | |
| 411 | // Repo mismatch — keep sessionRepo/currentRepo as plain "owner/repo" so |
| 412 | // downstream consumers (e.g. getKnownPathsForRepo) can use them as lookup keys. |
| 413 | // Include host information in separate fields for display purposes. |
| 414 | return { |
| 415 | status: 'mismatch', |
| 416 | sessionRepo, |
| 417 | currentRepo, |
| 418 | sessionHost: sessionParsed?.host, |
| 419 | currentHost: currentParsed?.host |
| 420 | }; |
| 421 | } |
| 422 | |
| 423 | /** |
| 424 | * Handles teleporting from a code session ID. |
no test coverage detected