()
| 138 | * Must be called before Ink mounts. |
| 139 | */ |
| 140 | export function installAsciicastRecorder(): void { |
| 141 | const filePath = getRecordFilePath() |
| 142 | if (!filePath) { |
| 143 | return |
| 144 | } |
| 145 | |
| 146 | const { cols, rows } = getTerminalSize() |
| 147 | const startTime = performance.now() |
| 148 | |
| 149 | // Write the asciicast v2 header |
| 150 | const header = jsonStringify({ |
| 151 | version: 2, |
| 152 | width: cols, |
| 153 | height: rows, |
| 154 | timestamp: Math.floor(Date.now() / 1000), |
| 155 | env: { |
| 156 | SHELL: process.env.SHELL || '', |
| 157 | TERM: process.env.TERM || '', |
| 158 | }, |
| 159 | }) |
| 160 | |
| 161 | try { |
| 162 | // eslint-disable-next-line custom-rules/no-sync-fs -- one-time init before Ink mounts |
| 163 | getFsImplementation().mkdirSync(dirname(filePath)) |
| 164 | } catch { |
| 165 | // Directory may already exist |
| 166 | } |
| 167 | // eslint-disable-next-line custom-rules/no-sync-fs -- one-time init before Ink mounts |
| 168 | getFsImplementation().appendFileSync(filePath, header + '\n', { mode: 0o600 }) |
| 169 | |
| 170 | let pendingWrite: Promise<void> = Promise.resolve() |
| 171 | |
| 172 | const writer = createBufferedWriter({ |
| 173 | writeFn(content: string) { |
| 174 | // Use recordingState.filePath (mutable) so writes follow renames from --resume |
| 175 | const currentPath = recordingState.filePath |
| 176 | if (!currentPath) { |
| 177 | return |
| 178 | } |
| 179 | pendingWrite = pendingWrite |
| 180 | .then(() => appendFile(currentPath, content)) |
| 181 | .catch(() => { |
| 182 | // Silently ignore write errors — don't break the session |
| 183 | }) |
| 184 | }, |
| 185 | flushIntervalMs: 500, |
| 186 | maxBufferSize: 50, |
| 187 | maxBufferBytes: 10 * 1024 * 1024, // 10MB |
| 188 | }) |
| 189 | |
| 190 | // Wrap process.stdout.write to capture output |
| 191 | const originalWrite = process.stdout.write.bind( |
| 192 | process.stdout, |
| 193 | ) as typeof process.stdout.write |
| 194 | process.stdout.write = function ( |
| 195 | chunk: string | Uint8Array, |
| 196 | encodingOrCb?: BufferEncoding | ((err?: Error) => void), |
| 197 | cb?: (err?: Error) => void, |
no test coverage detected