source dump of claude code
at main 98 lines 3.1 kB view raw
1import type { SDKMessage } from 'src/entrypoints/agentSdkTypes.js' 2import { checkGate_CACHED_OR_BLOCKING } from '../../../services/analytics/growthbook.js' 3import { isPolicyAllowed } from '../../../services/policyLimits/index.js' 4import { detectCurrentRepositoryWithHost } from '../../detectRepository.js' 5import { isEnvTruthy } from '../../envUtils.js' 6import type { TodoList } from '../../todo/types.js' 7import { 8 checkGithubAppInstalled, 9 checkHasRemoteEnvironment, 10 checkIsInGitRepo, 11 checkNeedsClaudeAiLogin, 12} from './preconditions.js' 13 14/** 15 * Background remote session type for managing teleport sessions 16 */ 17export type BackgroundRemoteSession = { 18 id: string 19 command: string 20 startTime: number 21 status: 'starting' | 'running' | 'completed' | 'failed' | 'killed' 22 todoList: TodoList 23 title: string 24 type: 'remote_session' 25 log: SDKMessage[] 26} 27 28/** 29 * Precondition failures for background remote sessions 30 */ 31export type BackgroundRemoteSessionPrecondition = 32 | { type: 'not_logged_in' } 33 | { type: 'no_remote_environment' } 34 | { type: 'not_in_git_repo' } 35 | { type: 'no_git_remote' } 36 | { type: 'github_app_not_installed' } 37 | { type: 'policy_blocked' } 38 39/** 40 * Checks eligibility for creating a background remote session 41 * Returns an array of failed preconditions (empty array means all checks passed) 42 * 43 * @returns Array of failed preconditions 44 */ 45export async function checkBackgroundRemoteSessionEligibility({ 46 skipBundle = false, 47}: { 48 skipBundle?: boolean 49} = {}): Promise<BackgroundRemoteSessionPrecondition[]> { 50 const errors: BackgroundRemoteSessionPrecondition[] = [] 51 52 // Check policy first - if blocked, no need to check other preconditions 53 if (!isPolicyAllowed('allow_remote_sessions')) { 54 errors.push({ type: 'policy_blocked' }) 55 return errors 56 } 57 58 const [needsLogin, hasRemoteEnv, repository] = await Promise.all([ 59 checkNeedsClaudeAiLogin(), 60 checkHasRemoteEnvironment(), 61 detectCurrentRepositoryWithHost(), 62 ]) 63 64 if (needsLogin) { 65 errors.push({ type: 'not_logged_in' }) 66 } 67 68 if (!hasRemoteEnv) { 69 errors.push({ type: 'no_remote_environment' }) 70 } 71 72 // When bundle seeding is on, in-git-repo is enough — CCR can seed from 73 // a local bundle. No GitHub remote or app needed. Same gate as 74 // teleport.tsx bundleSeedGateOn. 75 const bundleSeedGateOn = 76 !skipBundle && 77 (isEnvTruthy(process.env.CCR_FORCE_BUNDLE) || 78 isEnvTruthy(process.env.CCR_ENABLE_BUNDLE) || 79 (await checkGate_CACHED_OR_BLOCKING('tengu_ccr_bundle_seed_enabled'))) 80 81 if (!checkIsInGitRepo()) { 82 errors.push({ type: 'not_in_git_repo' }) 83 } else if (bundleSeedGateOn) { 84 // has .git/, bundle will work — skip remote+app checks 85 } else if (repository === null) { 86 errors.push({ type: 'no_git_remote' }) 87 } else if (repository.host === 'github.com') { 88 const hasGithubApp = await checkGithubAppInstalled( 89 repository.owner, 90 repository.name, 91 ) 92 if (!hasGithubApp) { 93 errors.push({ type: 'github_app_not_installed' }) 94 } 95 } 96 97 return errors 98}