mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-01-22 16:56:19 +00:00
Compare commits
3 Commits
feat/multi
...
v0.8.0-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbbc4c6342 | ||
|
|
21b26a400a | ||
|
|
1562780393 |
12
package-lock.json
generated
12
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
@@ -17304,7 +17304,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"dependencies": {
|
||||
"@google/genai": "1.30.0",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
@@ -17941,7 +17941,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@qwen-code/qwen-code-core",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.36.1",
|
||||
@@ -21400,7 +21400,7 @@
|
||||
},
|
||||
"packages/test-utils": {
|
||||
"name": "@qwen-code/qwen-code-test-utils",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
@@ -21412,7 +21412,7 @@
|
||||
},
|
||||
"packages/vscode-ide-companion": {
|
||||
"name": "qwen-code-vscode-ide-companion",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"license": "LICENSE",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.25.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
@@ -13,7 +13,7 @@
|
||||
"url": "git+https://github.com/QwenLM/qwen-code.git"
|
||||
},
|
||||
"config": {
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.8.0"
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.8.0-preview.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env node scripts/start.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"description": "Qwen Code",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -33,7 +33,7 @@
|
||||
"dist"
|
||||
],
|
||||
"config": {
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.8.0"
|
||||
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.8.0-preview.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/genai": "1.30.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code-core",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"description": "Qwen Code Core",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -92,11 +92,15 @@ const findCodeBlocks = (
|
||||
|
||||
describe('memoryImportProcessor', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks(); // Use resetAllMocks to clear mock implementations
|
||||
// Mock console methods
|
||||
console.warn = vi.fn();
|
||||
console.error = vi.fn();
|
||||
console.debug = vi.fn();
|
||||
// Default mock for lstat (used by findProjectRoot)
|
||||
mockedFs.lstat.mockRejectedValue(
|
||||
Object.assign(new Error('ENOENT'), { code: 'ENOENT' }),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -204,20 +208,43 @@ describe('memoryImportProcessor', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle file not found errors', async () => {
|
||||
it('should silently preserve content when file not found (ENOENT)', async () => {
|
||||
const content = 'Content @./nonexistent.md more content';
|
||||
const basePath = testPath('test', 'path');
|
||||
|
||||
mockedFs.access.mockRejectedValue(new Error('File not found'));
|
||||
// Mock ENOENT error (file not found)
|
||||
mockedFs.access.mockRejectedValue(
|
||||
Object.assign(new Error('ENOENT: no such file or directory'), {
|
||||
code: 'ENOENT',
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await processImports(content, basePath, true);
|
||||
|
||||
// Content should be preserved as-is when file doesn't exist
|
||||
expect(result.content).toBe(content);
|
||||
// No error should be logged for ENOENT
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should log error for non-ENOENT file access errors', async () => {
|
||||
const content = 'Content @./permission-denied.md more content';
|
||||
const basePath = testPath('test', 'path');
|
||||
|
||||
// Mock a permission denied error (not ENOENT)
|
||||
mockedFs.access.mockRejectedValue(
|
||||
Object.assign(new Error('Permission denied'), { code: 'EACCES' }),
|
||||
);
|
||||
|
||||
const result = await processImports(content, basePath, true);
|
||||
|
||||
// Should show error comment for non-ENOENT errors
|
||||
expect(result.content).toContain(
|
||||
'<!-- Import failed: ./nonexistent.md - File not found -->',
|
||||
'<!-- Import failed: ./permission-denied.md - Permission denied -->',
|
||||
);
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'[ERROR] [ImportProcessor]',
|
||||
'Failed to import ./nonexistent.md: File not found',
|
||||
'Failed to import ./permission-denied.md: Permission denied',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -448,6 +475,50 @@ describe('memoryImportProcessor', () => {
|
||||
expect(result.importTree.imports).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should still import valid paths while ignoring non-existent paths', async () => {
|
||||
const content = '使用 @./valid.md 文件和 @中文路径 注解';
|
||||
const basePath = testPath('test', 'path');
|
||||
const importedContent = 'Valid imported content';
|
||||
|
||||
// Mock: valid.md exists, 中文路径 doesn't exist
|
||||
mockedFs.access
|
||||
.mockResolvedValueOnce(undefined) // ./valid.md exists
|
||||
.mockRejectedValueOnce(
|
||||
Object.assign(new Error('ENOENT'), { code: 'ENOENT' }),
|
||||
); // 中文路径 doesn't exist
|
||||
mockedFs.readFile.mockResolvedValue(importedContent);
|
||||
|
||||
const result = await processImports(content, basePath, true);
|
||||
|
||||
// Should import valid.md
|
||||
expect(result.content).toContain(importedContent);
|
||||
expect(result.content).toContain('<!-- Imported from: ./valid.md -->');
|
||||
// The non-existent path should remain as-is
|
||||
expect(result.content).toContain('@中文路径');
|
||||
});
|
||||
|
||||
it('should import Chinese file names if they exist', async () => {
|
||||
const content = '导入 @./中文文档.md 文件';
|
||||
const projectRoot = testPath('test', 'project');
|
||||
const basePath = testPath(projectRoot, 'src');
|
||||
const importedContent = '这是中文文档的内容';
|
||||
|
||||
mockedFs.access.mockResolvedValue(undefined);
|
||||
mockedFs.readFile.mockResolvedValue(importedContent);
|
||||
|
||||
const result = await processImports(
|
||||
content,
|
||||
basePath,
|
||||
true,
|
||||
undefined,
|
||||
projectRoot,
|
||||
);
|
||||
|
||||
// Should successfully import the Chinese-named file
|
||||
expect(result.content).toContain(importedContent);
|
||||
expect(result.content).toContain('<!-- Imported from: ./中文文档.md -->');
|
||||
});
|
||||
|
||||
it('should allow imports from parent and subdirectories within project root', async () => {
|
||||
const content =
|
||||
'Parent import: @../parent.md Subdir import: @./components/sub.md';
|
||||
|
||||
@@ -150,6 +150,18 @@ function isLetter(char: string): boolean {
|
||||
); // a-z
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an error is a "file not found" error (ENOENT)
|
||||
*/
|
||||
function isFileNotFoundError(err: unknown): boolean {
|
||||
return (
|
||||
typeof err === 'object' &&
|
||||
err !== null &&
|
||||
'code' in err &&
|
||||
(err as { code: unknown }).code === 'ENOENT'
|
||||
);
|
||||
}
|
||||
|
||||
function findCodeRegions(content: string): Array<[number, number]> {
|
||||
const regions: Array<[number, number]> = [];
|
||||
const tokens = marked.lexer(content);
|
||||
@@ -292,7 +304,9 @@ export async function processImports(
|
||||
depth + 1,
|
||||
);
|
||||
} catch (error) {
|
||||
if (debugMode) {
|
||||
// If file doesn't exist, silently skip this import (it's not a real import)
|
||||
// Only log warnings for other types of errors
|
||||
if (!isFileNotFoundError(error) && debugMode) {
|
||||
logger.warn(
|
||||
`Failed to import ${fullPath}: ${hasMessage(error) ? error.message : 'Unknown error'}`,
|
||||
);
|
||||
@@ -371,6 +385,12 @@ export async function processImports(
|
||||
result += `<!-- Imported from: ${importPath} -->\n${imported.content}\n<!-- End of import from: ${importPath} -->`;
|
||||
imports.push(imported.importTree);
|
||||
} catch (err: unknown) {
|
||||
// If file doesn't exist, preserve the original @path text (it's not a real import)
|
||||
if (isFileNotFoundError(err)) {
|
||||
result += `@${importPath}`;
|
||||
continue;
|
||||
}
|
||||
// For other errors, log and add error comment
|
||||
let message = 'Unknown error';
|
||||
if (hasMessage(err)) {
|
||||
message = err.message;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qwen-code/qwen-code-test-utils",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"private": true,
|
||||
"main": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "qwen-code-vscode-ide-companion",
|
||||
"displayName": "Qwen Code Companion",
|
||||
"description": "Enable Qwen Code with direct access to your VS Code workspace.",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.0-preview.0",
|
||||
"publisher": "qwenlm",
|
||||
"icon": "assets/icon.png",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user