Files
wehub-resource-sync 7088f49b01
Build dist / build (push) Has been cancelled
CI / test (18.x) (push) Has been cancelled
CI / test (20.x) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:33 +08:00

183 lines
6.9 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { renderIdentityLine } from '../dist/render/lines/identity.js';
function stripAnsi(str) {
return str
.replace(/\x1b\[[0-9;]*m/g, '')
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '');
}
function baseContext() {
return {
stdin: {
model: { display_name: 'Opus' },
context_window: {
context_window_size: 200000,
current_usage: {
input_tokens: 10000,
cache_creation_input_tokens: 0,
cache_read_input_tokens: 0,
},
},
},
transcript: { tools: [], skills: [], mcpServers: [], agents: [], todos: [], sessionTokens: undefined },
claudeMdCount: 0,
rulesCount: 0,
mcpCount: 0,
hooksCount: 0,
sessionDuration: '',
gitStatus: null,
usageData: null,
memoryUsage: null,
config: {
lineLayout: 'compact',
showSeparators: false,
pathLevels: 1,
elementOrder: ['project', 'context', 'usage'],
gitStatus: { enabled: true, showDirty: true, showAheadBehind: false, showFileStats: false, branchOverflow: 'truncate', pushWarningThreshold: 0, pushCriticalThreshold: 0 },
display: { showModel: true, showProject: true, showContextBar: true, contextValue: 'percent', showConfigCounts: true, showCost: false, showDuration: true, showSpeed: false, showTokenBreakdown: true, showUsage: true, usageValue: 'percent', usageBarEnabled: false, showResetLabel: true, showTools: true, showSkills: false, showMcp: false, showAgents: true, showTodos: true, showSessionTokens: false, showSessionName: false, showClaudeCodeVersion: false, showMemoryUsage: false, showPromptCache: false, promptCacheTtlSeconds: 300, showOutputStyle: false, mergeGroups: [['context', 'usage']], autocompactBuffer: 'enabled', usageThreshold: 0, sevenDayThreshold: 80, environmentThreshold: 0, customLine: '' },
colors: {
context: 'green',
usage: 'brightBlue',
warning: 'yellow',
usageWarning: 'brightMagenta',
critical: 'red',
model: 'cyan',
project: 'yellow',
git: 'magenta',
gitBranch: 'cyan',
label: 'dim',
custom: 208,
},
},
};
}
test('renderIdentityLine shows percent by default', () => {
const ctx = baseContext();
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('Context'));
assert.ok(line.includes('5%'));
});
test('renderIdentityLine shows context in tokens mode', () => {
const ctx = baseContext();
ctx.config.display.contextValue = 'tokens';
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('10k/200k'));
});
test('renderIdentityLine shows context in both mode', () => {
const ctx = baseContext();
ctx.config.display.contextValue = 'both';
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('5%'));
assert.ok(line.includes('10k/200k'));
});
test('renderIdentityLine shows context in remaining mode', () => {
const ctx = baseContext();
ctx.config.display.contextValue = 'remaining';
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('95%'));
});
test('renderIdentityLine shows tokens mode with no context_window_size', () => {
const ctx = baseContext();
ctx.config.display.contextValue = 'tokens';
ctx.stdin.context_window.context_window_size = 0;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('10k'));
assert.ok(!line.includes('/'));
});
test('renderIdentityLine shows both mode with no context_window_size', () => {
const ctx = baseContext();
ctx.config.display.contextValue = 'both';
ctx.stdin.context_window.context_window_size = 0;
const line = stripAnsi(renderIdentityLine(ctx));
// Without a window size, both mode just shows percent
assert.match(line, /\d+%/);
});
test('renderIdentityLine hides context bar when showContextBar is false', () => {
const ctx = baseContext();
ctx.config.display.showContextBar = false;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('Context'));
// Should not have a bar (█ characters)
assert.ok(!line.includes('█'));
});
test('renderIdentityLine shows token breakdown when percent >= critical threshold', () => {
const ctx = baseContext();
ctx.stdin.context_window.current_usage.input_tokens = 180000;
ctx.stdin.context_window.current_usage.cache_creation_input_tokens = 5000;
ctx.stdin.context_window.current_usage.cache_read_input_tokens = 2000;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('in:'));
assert.ok(line.includes('cache:'));
});
test('renderIdentityLine hides token breakdown when showTokenBreakdown is false', () => {
const ctx = baseContext();
ctx.stdin.context_window.current_usage.input_tokens = 180000;
ctx.config.display.showTokenBreakdown = false;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(!line.includes('in:'));
});
test('renderIdentityLine respects custom contextCriticalThreshold', () => {
const ctx = baseContext();
// 10k/200k = 5%, set threshold to 5 to trigger breakdown
ctx.config.display.contextCriticalThreshold = 5;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('in:'));
});
test('renderIdentityLine uses autoCompactWindow for token display', () => {
const ctx = baseContext();
ctx.config.display.autoCompactWindow = 100000;
ctx.config.display.contextValue = 'tokens';
const line = stripAnsi(renderIdentityLine(ctx));
// Should show tokens relative to autoCompactWindow (100k) not full window (200k)
assert.ok(line.includes('10k/100k'));
});
test('renderIdentityLine supports alignLabels parameter', () => {
const ctx = baseContext();
const lineNoAlign = stripAnsi(renderIdentityLine(ctx, false));
const lineAlign = stripAnsi(renderIdentityLine(ctx, true));
// Both should contain Context label
assert.ok(lineNoAlign.includes('Context'));
assert.ok(lineAlign.includes('Context'));
});
test('renderIdentityLine disables autocompact buffer when set to disabled', () => {
const ctx = baseContext();
ctx.config.display.autocompactBuffer = 'disabled';
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('Context'));
// Should show raw percent
assert.ok(line.includes('5%'));
});
test('renderIdentityLine formats million-scale tokens correctly', () => {
const ctx = baseContext();
ctx.stdin.context_window.context_window_size = 1000000;
ctx.stdin.context_window.current_usage.input_tokens = 900000;
ctx.config.display.contextCriticalThreshold = 85;
ctx.config.display.contextValue = 'tokens';
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('900k/1.0M'));
});
test('renderIdentityLine does not show breakdown when no usage data', () => {
const ctx = baseContext();
ctx.stdin.context_window.current_usage = null;
ctx.stdin.context_window.context_window_size = 200000;
const line = stripAnsi(renderIdentityLine(ctx));
assert.ok(line.includes('Context'));
});