mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 09:17:53 +00:00
# 🚀 Sync Gemini CLI v0.2.1 - Major Feature Update (#483)
This commit is contained in:
@@ -38,7 +38,7 @@ function renderHastNode(
|
||||
// Handle Element Nodes: Determine color and pass it down, don't wrap
|
||||
if (node.type === 'element') {
|
||||
const nodeClasses: string[] =
|
||||
(node.properties?.className as string[]) || [];
|
||||
(node.properties?.['className'] as string[]) || [];
|
||||
let elementColor: string | undefined = undefined;
|
||||
|
||||
// Find color defined specifically for this element's class
|
||||
|
||||
@@ -22,10 +22,15 @@ interface RenderInlineProps {
|
||||
}
|
||||
|
||||
const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
|
||||
// Early return for plain text without markdown or URLs
|
||||
if (!/[*_~`<[https?:]/.test(text)) {
|
||||
return <Text>{text}</Text>;
|
||||
}
|
||||
|
||||
const nodes: React.ReactNode[] = [];
|
||||
let lastIndex = 0;
|
||||
const inlineRegex =
|
||||
/(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>)/g;
|
||||
/(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|<u>.*?<\/u>|https?:\/\/\S+)/g;
|
||||
let match;
|
||||
|
||||
while ((match = inlineRegex.exec(text)) !== null) {
|
||||
@@ -126,6 +131,12 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
|
||||
)}
|
||||
</Text>
|
||||
);
|
||||
} else if (fullMatch.match(/^https?:\/\//)) {
|
||||
renderedNode = (
|
||||
<Text key={key} color={Colors.AccentBlue}>
|
||||
{fullMatch}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing inline markdown part:', fullMatch, e);
|
||||
|
||||
@@ -121,6 +121,10 @@ describe('computeSessionStats', () => {
|
||||
totalDecisions: { accept: 0, reject: 0, modify: 0 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
@@ -137,6 +141,8 @@ describe('computeSessionStats', () => {
|
||||
agreementRate: 0,
|
||||
totalPromptTokens: 0,
|
||||
totalCachedTokens: 0,
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -163,6 +169,10 @@ describe('computeSessionStats', () => {
|
||||
totalDecisions: { accept: 0, reject: 0, modify: 0 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
@@ -197,6 +207,10 @@ describe('computeSessionStats', () => {
|
||||
totalDecisions: { accept: 0, reject: 0, modify: 0 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
@@ -215,6 +229,10 @@ describe('computeSessionStats', () => {
|
||||
totalDecisions: { accept: 6, reject: 2, modify: 2 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
@@ -234,6 +252,10 @@ describe('computeSessionStats', () => {
|
||||
totalDecisions: { accept: 0, reject: 0, modify: 0 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 0,
|
||||
totalLinesRemoved: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
@@ -244,4 +266,27 @@ describe('computeSessionStats', () => {
|
||||
expect(result.successRate).toBe(0);
|
||||
expect(result.agreementRate).toBe(0);
|
||||
});
|
||||
|
||||
it('should correctly include line counts', () => {
|
||||
const metrics: SessionMetrics = {
|
||||
models: {},
|
||||
tools: {
|
||||
totalCalls: 0,
|
||||
totalSuccess: 0,
|
||||
totalFail: 0,
|
||||
totalDurationMs: 0,
|
||||
totalDecisions: { accept: 0, reject: 0, modify: 0 },
|
||||
byName: {},
|
||||
},
|
||||
files: {
|
||||
totalLinesAdded: 42,
|
||||
totalLinesRemoved: 18,
|
||||
},
|
||||
};
|
||||
|
||||
const result = computeSessionStats(metrics);
|
||||
|
||||
expect(result.totalLinesAdded).toBe(42);
|
||||
expect(result.totalLinesRemoved).toBe(18);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ export function calculateCacheHitRate(metrics: ModelMetrics): number {
|
||||
export const computeSessionStats = (
|
||||
metrics: SessionMetrics,
|
||||
): ComputedSessionStats => {
|
||||
const { models, tools } = metrics;
|
||||
const { models, tools, files } = metrics;
|
||||
const totalApiTime = Object.values(models).reduce(
|
||||
(acc, model) => acc + model.api.totalLatencyMs,
|
||||
0,
|
||||
@@ -80,5 +80,7 @@ export const computeSessionStats = (
|
||||
agreementRate,
|
||||
totalCachedTokens,
|
||||
totalPromptTokens,
|
||||
totalLinesAdded: files.totalLinesAdded,
|
||||
totalLinesRemoved: files.totalLinesRemoved,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -17,6 +17,14 @@
|
||||
*/
|
||||
export const KITTY_CTRL_C = '[99;5u';
|
||||
|
||||
/**
|
||||
* Kitty keyboard protocol keycodes
|
||||
*/
|
||||
export const KITTY_KEYCODE_ENTER = 13;
|
||||
export const KITTY_KEYCODE_NUMPAD_ENTER = 57414;
|
||||
export const KITTY_KEYCODE_TAB = 9;
|
||||
export const KITTY_KEYCODE_BACKSPACE = 127;
|
||||
|
||||
/**
|
||||
* Timing constants for terminal interactions
|
||||
*/
|
||||
|
||||
@@ -52,22 +52,24 @@ type SupportedTerminal = 'vscode' | 'cursor' | 'windsurf';
|
||||
|
||||
// Terminal detection
|
||||
async function detectTerminal(): Promise<SupportedTerminal | null> {
|
||||
const termProgram = process.env.TERM_PROGRAM;
|
||||
const termProgram = process.env['TERM_PROGRAM'];
|
||||
|
||||
// Check VS Code and its forks - check forks first to avoid false positives
|
||||
// Check for Cursor-specific indicators
|
||||
if (
|
||||
process.env.CURSOR_TRACE_ID ||
|
||||
process.env.VSCODE_GIT_ASKPASS_MAIN?.toLowerCase().includes('cursor')
|
||||
process.env['CURSOR_TRACE_ID'] ||
|
||||
process.env['VSCODE_GIT_ASKPASS_MAIN']?.toLowerCase().includes('cursor')
|
||||
) {
|
||||
return 'cursor';
|
||||
}
|
||||
// Check for Windsurf-specific indicators
|
||||
if (process.env.VSCODE_GIT_ASKPASS_MAIN?.toLowerCase().includes('windsurf')) {
|
||||
if (
|
||||
process.env['VSCODE_GIT_ASKPASS_MAIN']?.toLowerCase().includes('windsurf')
|
||||
) {
|
||||
return 'windsurf';
|
||||
}
|
||||
// Check VS Code last since forks may also set VSCODE env vars
|
||||
if (termProgram === 'vscode' || process.env.VSCODE_GIT_IPC_HANDLE) {
|
||||
if (termProgram === 'vscode' || process.env['VSCODE_GIT_IPC_HANDLE']) {
|
||||
return 'vscode';
|
||||
}
|
||||
|
||||
@@ -118,10 +120,10 @@ function getVSCodeStyleConfigDir(appName: string): string | null {
|
||||
'User',
|
||||
);
|
||||
} else if (platform === 'win32') {
|
||||
if (!process.env.APPDATA) {
|
||||
if (!process.env['APPDATA']) {
|
||||
return null;
|
||||
}
|
||||
return path.join(process.env.APPDATA, appName, 'User');
|
||||
return path.join(process.env['APPDATA'], appName, 'User');
|
||||
} else {
|
||||
return path.join(os.homedir(), '.config', appName, 'User');
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('checkForUpdates', () => {
|
||||
vi.useFakeTimers();
|
||||
vi.resetAllMocks();
|
||||
// Clear DEV environment variable before each test
|
||||
delete process.env.DEV;
|
||||
delete process.env['DEV'];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -31,7 +31,7 @@ describe('checkForUpdates', () => {
|
||||
});
|
||||
|
||||
it('should return null when running from source (DEV=true)', async () => {
|
||||
process.env.DEV = 'true';
|
||||
process.env['DEV'] = 'true';
|
||||
getPackageJson.mockResolvedValue({
|
||||
name: 'test-package',
|
||||
version: '1.0.0',
|
||||
|
||||
@@ -41,7 +41,7 @@ function getBestAvailableUpdate(
|
||||
export async function checkForUpdates(): Promise<UpdateObject | null> {
|
||||
try {
|
||||
// Skip update check when running from source (development mode)
|
||||
if (process.env.DEV === 'true') {
|
||||
if (process.env['DEV'] === 'true') {
|
||||
return null;
|
||||
}
|
||||
const packageJson = await getPackageJson();
|
||||
|
||||
Reference in New Issue
Block a user