(
commandArgs: readonly string[],
options?: {
readonly cwd?: string
readonly env?: NodeJS.ProcessEnv
readonly columns?: number
readonly lines?: number
},
)
| 138 | } |
| 139 | |
| 140 | export function spawnPtyContractSession( |
| 141 | commandArgs: readonly string[], |
| 142 | options?: { |
| 143 | readonly cwd?: string |
| 144 | readonly env?: NodeJS.ProcessEnv |
| 145 | readonly columns?: number |
| 146 | readonly lines?: number |
| 147 | }, |
| 148 | ): PtyContractSession { |
| 149 | const scriptPath = resolveScriptBinary() |
| 150 | if (!scriptPath) { |
| 151 | throw new Error('required command not found: script') |
| 152 | } |
| 153 | |
| 154 | const columns = String(options?.columns ?? Number(DEFAULT_COLUMNS)) |
| 155 | const lines = String(options?.lines ?? Number(DEFAULT_LINES)) |
| 156 | const proc = Bun.spawn( |
| 157 | [scriptPath, '-qefc', shellJoinArgs(commandArgs), '/dev/null'], |
| 158 | { |
| 159 | cwd: options?.cwd, |
| 160 | env: createDeterministicPtyEnv(options?.env, columns, lines), |
| 161 | stdin: 'pipe', |
| 162 | stdout: 'pipe', |
| 163 | stderr: 'pipe', |
| 164 | }, |
| 165 | ) |
| 166 | |
| 167 | let rawText = '' |
| 168 | let visibleText = '' |
| 169 | const waiters: Array<{ |
| 170 | readonly regex: RegExp |
| 171 | readonly resolve: (match: RegExpMatchArray) => void |
| 172 | readonly reject: (error: Error) => void |
| 173 | readonly timer: ReturnType<typeof setTimeout> |
| 174 | }> = [] |
| 175 | |
| 176 | function maybeResolveWaiters(): void { |
| 177 | for (let index = waiters.length - 1; index >= 0; index -= 1) { |
| 178 | const waiter = waiters[index] |
| 179 | const match = rawText.match(waiter.regex) |
| 180 | if (!match) { |
| 181 | continue |
| 182 | } |
| 183 | clearTimeout(waiter.timer) |
| 184 | waiters.splice(index, 1) |
| 185 | waiter.resolve(match) |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | async function drainStream( |
| 190 | stream: ReadableStream<Uint8Array>, |
| 191 | onChunk: (chunk: string) => void, |
| 192 | ): Promise<string> { |
| 193 | const reader = stream.getReader() |
| 194 | const decoder = new TextDecoder() |
| 195 | let text = '' |
| 196 | |
| 197 | while (true) { |
no test coverage detected