(s: unknown)
| 289 | } |
| 290 | |
| 291 | function dehydrateValue(s: unknown): unknown { |
| 292 | if (typeof s !== 'string') { |
| 293 | return s |
| 294 | } |
| 295 | const cwd = getCwd() |
| 296 | const configHome = getClaudeConfigHomeDir() |
| 297 | let s1 = s |
| 298 | .replace(/num_files="\d+"/g, 'num_files="[NUM]"') |
| 299 | .replace(/duration_ms="\d+"/g, 'duration_ms="[DURATION]"') |
| 300 | .replace(/cost_usd="\d+"/g, 'cost_usd="[COST]"') |
| 301 | // Note: We intentionally don't replace all forward slashes with path.sep here. |
| 302 | // That would corrupt XML-like tags (e.g., </system-reminder> -> <\system-reminder>). |
| 303 | // The [CONFIG_HOME] and [CWD] replacements below handle path normalization. |
| 304 | .replaceAll(configHome, '[CONFIG_HOME]') |
| 305 | .replaceAll(cwd, '[CWD]') |
| 306 | .replace(/Available commands:.+/, 'Available commands: [COMMANDS]') |
| 307 | // On Windows, paths may appear in multiple forms: |
| 308 | // 1. Forward-slash variants (Git, some Node APIs) |
| 309 | // 2. JSON-escaped variants (backslashes doubled in serialized JSON within messages) |
| 310 | if (process.platform === 'win32') { |
| 311 | const cwdFwd = cwd.replaceAll('\\', '/') |
| 312 | const configHomeFwd = configHome.replaceAll('\\', '/') |
| 313 | // jsonStringify escapes \ to \\ - match paths embedded in JSON strings |
| 314 | const cwdJsonEscaped = jsonStringify(cwd).slice(1, -1) |
| 315 | const configHomeJsonEscaped = jsonStringify(configHome).slice(1, -1) |
| 316 | s1 = s1 |
| 317 | .replaceAll(cwdJsonEscaped, '[CWD]') |
| 318 | .replaceAll(configHomeJsonEscaped, '[CONFIG_HOME]') |
| 319 | .replaceAll(cwdFwd, '[CWD]') |
| 320 | .replaceAll(configHomeFwd, '[CONFIG_HOME]') |
| 321 | } |
| 322 | // Normalize backslash path separators after placeholders so VCR fixture |
| 323 | // hashes match across platforms (e.g., [CWD]\foo\bar -> [CWD]/foo/bar) |
| 324 | // Handle both single backslashes and JSON-escaped double backslashes (\\) |
| 325 | s1 = s1 |
| 326 | .replace(/\[CWD\][^\s"'<>]*/g, match => |
| 327 | match.replaceAll('\\\\', '/').replaceAll('\\', '/'), |
| 328 | ) |
| 329 | .replace(/\[CONFIG_HOME\][^\s"'<>]*/g, match => |
| 330 | match.replaceAll('\\\\', '/').replaceAll('\\', '/'), |
| 331 | ) |
| 332 | if (s1.includes('Files modified by user:')) { |
| 333 | return 'Files modified by user: [FILES]' |
| 334 | } |
| 335 | return s1 |
| 336 | } |
| 337 | |
| 338 | function hydrateValue(s: unknown): unknown { |
| 339 | if (typeof s !== 'string') { |
no test coverage detected