mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
Windows terminals emit control sequences (cursor movement, screen clearing) that leaked into session.tmp files and were injected verbatim into Claude's context on the next session start. Add a comprehensive stripAnsi() to utils.js that handles CSI, OSC, charset selection, and bare ESC sequences. Apply it in session-end.js (when extracting user messages from the transcript) and in session-start.js (safety net before injecting session content).
This commit is contained in:
@@ -2424,6 +2424,65 @@ function runTests() {
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
// ─── stripAnsi ───
|
||||
console.log('\nstripAnsi:');
|
||||
|
||||
if (test('strips SGR color codes (\\x1b[...m)', () => {
|
||||
assert.strictEqual(utils.stripAnsi('\x1b[31mRed text\x1b[0m'), 'Red text');
|
||||
assert.strictEqual(utils.stripAnsi('\x1b[1;36mBold cyan\x1b[0m'), 'Bold cyan');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips cursor movement sequences (\\x1b[H, \\x1b[2J, \\x1b[3J)', () => {
|
||||
// These are the exact sequences reported in issue #642
|
||||
assert.strictEqual(utils.stripAnsi('\x1b[H\x1b[2J\x1b[3JHello'), 'Hello');
|
||||
assert.strictEqual(utils.stripAnsi('before\x1b[Hafter'), 'beforeafter');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips cursor position sequences (\\x1b[row;colH)', () => {
|
||||
assert.strictEqual(utils.stripAnsi('\x1b[5;10Hplaced'), 'placed');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips erase line sequences (\\x1b[K, \\x1b[2K)', () => {
|
||||
assert.strictEqual(utils.stripAnsi('line\x1b[Kend'), 'lineend');
|
||||
assert.strictEqual(utils.stripAnsi('line\x1b[2Kend'), 'lineend');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips OSC sequences (window title, hyperlinks)', () => {
|
||||
// OSC terminated by BEL (\x07)
|
||||
assert.strictEqual(utils.stripAnsi('\x1b]0;My Title\x07content'), 'content');
|
||||
// OSC terminated by ST (\x1b\\)
|
||||
assert.strictEqual(utils.stripAnsi('\x1b]8;;https://example.com\x1b\\link\x1b]8;;\x1b\\'), 'link');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips charset selection (\\x1b(B)', () => {
|
||||
assert.strictEqual(utils.stripAnsi('\x1b(Bnormal'), 'normal');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('strips bare ESC + letter (\\x1bM reverse index)', () => {
|
||||
assert.strictEqual(utils.stripAnsi('line\x1bMup'), 'lineup');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('handles mixed ANSI sequences in one string', () => {
|
||||
const input = '\x1b[H\x1b[2J\x1b[1;36mSession\x1b[0m summary\x1b[K';
|
||||
assert.strictEqual(utils.stripAnsi(input), 'Session summary');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('returns empty string for non-string input', () => {
|
||||
assert.strictEqual(utils.stripAnsi(null), '');
|
||||
assert.strictEqual(utils.stripAnsi(undefined), '');
|
||||
assert.strictEqual(utils.stripAnsi(42), '');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('preserves string with no ANSI codes', () => {
|
||||
assert.strictEqual(utils.stripAnsi('plain text'), 'plain text');
|
||||
assert.strictEqual(utils.stripAnsi(''), '');
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('handles CSI with question mark parameter (DEC private modes)', () => {
|
||||
// e.g. \x1b[?25h (show cursor), \x1b[?25l (hide cursor)
|
||||
assert.strictEqual(utils.stripAnsi('\x1b[?25hvisible\x1b[?25l'), 'visible');
|
||||
})) passed++; else failed++;
|
||||
|
||||
// Summary
|
||||
console.log('\n=== Test Results ===');
|
||||
console.log(`Passed: ${passed}`);
|
||||
|
||||
Reference in New Issue
Block a user