(
streamUrl: string,
initialPrompt?: AsyncIterable<string>,
replayUserMessages?: boolean,
)
| 42 | private keepAliveTimer: ReturnType<typeof setInterval> | null = null |
| 43 | |
| 44 | constructor( |
| 45 | streamUrl: string, |
| 46 | initialPrompt?: AsyncIterable<string>, |
| 47 | replayUserMessages?: boolean, |
| 48 | ) { |
| 49 | const inputStream = new PassThrough({ encoding: 'utf8' }) |
| 50 | super(inputStream, replayUserMessages) |
| 51 | this.inputStream = inputStream |
| 52 | this.url = new URL(streamUrl) |
| 53 | |
| 54 | // Prepare headers with session token if available |
| 55 | const headers: Record<string, string> = {} |
| 56 | const sessionToken = getSessionIngressAuthToken() |
| 57 | if (sessionToken) { |
| 58 | headers['Authorization'] = `Bearer ${sessionToken}` |
| 59 | } else { |
| 60 | logForDebugging('[remote-io] No session ingress token available', { |
| 61 | level: 'error', |
| 62 | }) |
| 63 | } |
| 64 | |
| 65 | // Add environment runner version if available (set by Environment Manager) |
| 66 | const erVersion = process.env.CLAUDE_CODE_ENVIRONMENT_RUNNER_VERSION |
| 67 | if (erVersion) { |
| 68 | headers['x-environment-runner-version'] = erVersion |
| 69 | } |
| 70 | |
| 71 | // Provide a callback that re-reads the session token dynamically. |
| 72 | // When the parent process refreshes the token (via token file or env var), |
| 73 | // the transport can pick it up on reconnection. |
| 74 | const refreshHeaders = (): Record<string, string> => { |
| 75 | const h: Record<string, string> = {} |
| 76 | const freshToken = getSessionIngressAuthToken() |
| 77 | if (freshToken) { |
| 78 | h['Authorization'] = `Bearer ${freshToken}` |
| 79 | } |
| 80 | const freshErVersion = process.env.CLAUDE_CODE_ENVIRONMENT_RUNNER_VERSION |
| 81 | if (freshErVersion) { |
| 82 | h['x-environment-runner-version'] = freshErVersion |
| 83 | } |
| 84 | return h |
| 85 | } |
| 86 | |
| 87 | // Get appropriate transport based on URL protocol |
| 88 | this.transport = getTransportForUrl( |
| 89 | this.url, |
| 90 | headers, |
| 91 | getSessionId(), |
| 92 | refreshHeaders, |
| 93 | ) |
| 94 | |
| 95 | // Set up data callback |
| 96 | this.isBridge = process.env.CLAUDE_CODE_ENVIRONMENT_KIND === 'bridge' |
| 97 | this.isDebug = isDebugMode() |
| 98 | this.transport.setOnData((data: string) => { |
| 99 | this.inputStream.write(data) |
| 100 | if (this.isBridge && this.isDebug) { |
| 101 | writeToStdout(data.endsWith('\n') ? data : data + '\n') |
nothing calls this directly
no test coverage detected