Compare commits

..

6 Commits

Author SHA1 Message Date
github-actions[bot]
c13149a3b5 chore(release): v0.0.2 2025-08-01 10:29:04 +00:00
奕桁
2786f10e8c update dev version 2025-08-01 18:28:16 +08:00
奕桁
964d211270 update dev version 2025-08-01 18:05:05 +08:00
Yiheng Xu
a09a9f2261 fix release.yml 2025-08-01 17:51:42 +08:00
奕桁
09c2a1871b release v0.0.1 2025-08-01 17:26:59 +08:00
Yiheng Xu
999f3af098 fix release workflow (#172) 2025-08-01 17:13:07 +08:00
26 changed files with 154 additions and 123 deletions

View File

@@ -44,7 +44,7 @@ jobs:
- name: Run E2E tests
env:
QWEN_CODE_API_KEY: ${{ secrets.OPENAI_API_KEY }}
QWEN_CODE_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
QWEN_CODE_MODEL: ${{ secrets.OPENAI_MODEL }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }}
run: npm run test:integration:${{ matrix.sandbox }} -- --verbose --keep-output

View File

@@ -37,7 +37,7 @@ jobs:
environment:
name: production-release
url: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ steps.version.outputs.RELEASE_TAG }}
if: github.repository == 'google-gemini/gemini-cli'
if: github.repository == 'QwenLM/qwen-code'
permissions:
contents: write
packages: write
@@ -95,7 +95,9 @@ jobs:
npm run test:integration:sandbox:none
npm run test:integration:sandbox:docker
env:
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
OPENAI_MODEL: ${{ secrets.OPENAI_MODEL }}
- name: Configure Git User
run: |
@@ -133,22 +135,22 @@ jobs:
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '20'
registry-url: 'https://wombat-dressing-room.appspot.com'
scope: '@google'
registry-url: 'https://registry.npmjs.org'
scope: '@qwen-code'
- name: Publish @google/gemini-cli-core
run: npm publish --workspace=@google/gemini-cli-core --tag=${{ steps.version.outputs.NPM_TAG }} ${{ steps.vars.outputs.is_dry_run == 'true' && '--dry-run' || '' }}
- name: Publish @qwen-code/qwen-code-core
run: npm publish --workspace=@qwen-code/qwen-code-core --access public --tag=${{ steps.version.outputs.NPM_TAG }} ${{ steps.vars.outputs.is_dry_run == 'true' && '--dry-run' || '' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.WOMBAT_TOKEN_CORE }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install latest core package
if: steps.vars.outputs.is_dry_run == 'false'
run: npm install @google/gemini-cli-core@${{ steps.version.outputs.RELEASE_VERSION }} --workspace=@google/gemini-cli --save-exact
run: npm install @qwen-code/qwen-code-core@${{ steps.version.outputs.RELEASE_VERSION }} --workspace=@qwen-code/qwen-code --save-exact
- name: Publish @google/gemini-cli
run: npm publish --workspace=@google/gemini-cli --tag=${{ steps.version.outputs.NPM_TAG }} ${{ steps.vars.outputs.is_dry_run == 'true' && '--dry-run' || '' }}
- name: Publish @qwen-code/qwen-code
run: npm publish --workspace=@qwen-code/qwen-code --access public --tag=${{ steps.version.outputs.NPM_TAG }} ${{ steps.vars.outputs.is_dry_run == 'true' && '--dry-run' || '' }}
env:
NODE_AUTH_TOKEN: ${{ secrets.WOMBAT_TOKEN_CLI }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create GitHub Release and Tag
if: ${{ steps.vars.outputs.is_dry_run == 'false' }}

View File

@@ -97,17 +97,17 @@ Qwen Code supports multiple API providers. You can configure your API key throug
1. **Environment Variables**
```bash
export QWEN_CODE_API_KEY="your_api_key_here"
export QWEN_CODE_BASE_URL="your_api_endpoint"
export QWEN_CODE_MODEL="your_model_choice"
export OPENAI_API_KEY="your_api_key_here"
export OPENAI_BASE_URL="your_api_endpoint"
export OPENAI_MODEL="your_model_choice"
```
2. **Project `.env` File**
Create a `.env` file in your project root:
```env
QWEN_CODE_API_KEY=your_api_key_here
QWEN_CODE_BASE_URL=your_api_endpoint
QWEN_CODE_MODEL=your_model_choice
OPENAI_API_KEY=your_api_key_here
OPENAI_BASE_URL=your_api_endpoint
OPENAI_MODEL=your_model_choice
```
#### API Provider Options
@@ -123,9 +123,9 @@ Qwen Code supports multiple API providers. You can configure your API key throug
**Option 1: Alibaba Cloud Bailian** ([Apply for API Key](https://bailian.console.aliyun.com/))
```bash
export QWEN_CODE_API_KEY="your_api_key_here"
export QWEN_CODE_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
export QWEN_CODE_MODEL="qwen3-coder-plus"
export OPENAI_API_KEY="your_api_key_here"
export OPENAI_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1"
export OPENAI_MODEL="qwen3-coder-plus"
```
**Option 2: ModelScope (Free Tier)** ([Apply for API Key](https://modelscope.cn/docs/model-service/API-Inference/intro))
@@ -134,9 +134,9 @@ export QWEN_CODE_MODEL="qwen3-coder-plus"
- ⚠️ Connect your Aliyun account to avoid authentication errors
```bash
export QWEN_CODE_API_KEY="your_api_key_here"
export QWEN_CODE_BASE_URL="https://api-inference.modelscope.cn/v1"
export QWEN_CODE_MODEL="Qwen/Qwen3-Coder-480B-A35B-Instruct"
export OPENAI_API_KEY="your_api_key_here"
export OPENAI_BASE_URL="https://api-inference.modelscope.cn/v1"
export OPENAI_MODEL="Qwen/Qwen3-Coder-480B-A35B-Instruct"
```
</details>
@@ -147,17 +147,17 @@ export QWEN_CODE_MODEL="Qwen/Qwen3-Coder-480B-A35B-Instruct"
**Option 1: Alibaba Cloud ModelStudio** ([Apply for API Key](https://modelstudio.console.alibabacloud.com/))
```bash
export QWEN_CODE_API_KEY="your_api_key_here"
export QWEN_CODE_BASE_URL="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
export QWEN_CODE_MODEL="qwen3-coder-plus"
export OPENAI_API_KEY="your_api_key_here"
export OPENAI_BASE_URL="https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
export OPENAI_MODEL="qwen3-coder-plus"
```
**Option 2: OpenRouter (Free Tier Available)** ([Apply for API Key](https://openrouter.ai/))
```bash
export QWEN_CODE_API_KEY="your_api_key_here"
export QWEN_CODE_BASE_URL="https://openrouter.ai/api/v1"
export QWEN_CODE_MODEL="qwen/qwen3-coder:free"
export OPENAI_API_KEY="your_api_key_here"
export OPENAI_BASE_URL="https://openrouter.ai/api/v1"
export OPENAI_MODEL="qwen/qwen3-coder:free"
```
</details>

View File

@@ -219,8 +219,8 @@ In addition to a project settings file, a project's `.gemini` directory can cont
- **Description:** Configures custom system prompt templates for specific model names and base URLs. This allows you to use different system prompts for different AI models or API endpoints.
- **Default:** `undefined` (uses default system prompt)
- **Properties:**
- **`baseUrls`** (array of strings, optional): Array of base URLs to exactly match against `QWEN_CODE_BASE_URL` environment variable. If not specified, matches any base URL.
- **`modelNames`** (array of strings, optional): Array of model names to exactly match against `QWEN_CODE_MODEL` environment variable. If not specified, matches any model.
- **`baseUrls`** (array of strings, optional): Array of base URLs to exactly match against `OPENAI_BASE_URL` environment variable. If not specified, matches any base URL.
- **`modelNames`** (array of strings, optional): Array of model names to exactly match against `OPENAI_MODEL` environment variable. If not specified, matches any model.
- **`template`** (string): The system prompt template to use when both baseUrl and modelNames match. Supports placeholders:
- `{RUNTIME_VARS_IS_GIT_REPO}`: Replaced with `true` or `false` based on whether the current directory is a git repository
- `{RUNTIME_VARS_SANDBOX}`: Replaced with the sandbox type (e.g., `"sandbox-exec"`, `"docker"`, or empty string)

View File

@@ -40,9 +40,9 @@ qwen-code --openai-api-key "your-api-key-here" --model "gpt-4-turbo"
Set the following environment variables in your shell or `.env` file:
```bash
export QWEN_CODE_API_KEY="your-api-key-here"
export QWEN_CODE_BASE_URL="https://api.openai.com/v1" # Optional, defaults to this value
export QWEN_CODE_MODEL="gpt-4o" # Optional, defaults to gpt-4o
export OPENAI_API_KEY="your-api-key-here"
export OPENAI_BASE_URL="https://api.openai.com/v1" # Optional, defaults to this value
export OPENAI_MODEL="gpt-4o" # Optional, defaults to gpt-4o
```
## Supported Models
@@ -58,7 +58,7 @@ The CLI supports all OpenAI models that are available through the OpenAI API, in
## Custom Endpoints
You can use custom endpoints by setting the `QWEN_CODE_BASE_URL` environment variable or using the `--openai-base-url` command line argument. This is useful for:
You can use custom endpoints by setting the `OPENAI_BASE_URL` environment variable or using the `--openai-base-url` command line argument. This is useful for:
- Using Azure OpenAI
- Using other OpenAI-compatible APIs

13
package-lock.json generated
View File

@@ -1,18 +1,15 @@
{
"name": "@qwen-code/qwen-code",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qwen-code/qwen-code",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"workspaces": [
"packages/*"
],
"dependencies": {
"@qwen-code/qwen-code": "^0.0.1-alpha.8"
},
"bin": {
"qwen": "bundle/gemini.js"
},
@@ -11945,7 +11942,7 @@
},
"packages/cli": {
"name": "@qwen-code/qwen-code",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"dependencies": {
"@qwen-code/qwen-code-core": "file:../core",
"@types/update-notifier": "^6.0.8",
@@ -12123,7 +12120,7 @@
},
"packages/core": {
"name": "@qwen-code/qwen-code-core",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"dependencies": {
"@google/genai": "1.8.0",
"@modelcontextprotocol/sdk": "^1.11.0",
@@ -12197,7 +12194,7 @@
},
"packages/vscode-ide-companion": {
"name": "@qwen-code/qwen-code-vscode-ide-companion",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
"cors": "^2.8.5",

View File

@@ -1,6 +1,6 @@
{
"name": "@qwen-code/qwen-code",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"engines": {
"node": ">=20"
},
@@ -10,10 +10,10 @@
],
"repository": {
"type": "git",
"url": "git+http://gitlab.alibaba-inc.com/Qwen-Coder/qwen-code.git"
"url": "git+https://github.com/QwenLM/qwen-code.git"
},
"config": {
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.1-alpha.12"
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.2"
},
"scripts": {
"start": "node scripts/start.js",
@@ -81,8 +81,5 @@
"typescript-eslint": "^8.30.1",
"vitest": "^3.2.4",
"yargs": "^18.0.0"
},
"dependencies": {
"@qwen-code/qwen-code": "^0.0.1-alpha.8"
}
}

View File

@@ -1,10 +1,10 @@
{
"name": "@qwen-code/qwen-code",
"version": "0.0.1-alpha.12",
"description": "Gemini CLI",
"version": "0.0.2",
"description": "Qwen Code",
"repository": {
"type": "git",
"url": "git+http://gitlab.alibaba-inc.com/Qwen-Coder/qwen-code.git"
"url": "git+https://github.com/QwenLM/qwen-code.git"
},
"type": "module",
"main": "dist/index.js",
@@ -25,7 +25,7 @@
"dist"
],
"config": {
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.1-alpha.12"
"sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.2"
},
"dependencies": {
"@qwen-code/qwen-code-core": "file:../core",

View File

@@ -39,8 +39,8 @@ export const validateAuthMethod = (authMethod: string): string | null => {
}
if (authMethod === AuthType.USE_OPENAI) {
if (!process.env.QWEN_CODE_API_KEY) {
return 'QWEN_CODE_API_KEY environment variable not found. You can enter it interactively or add it to your .env file.';
if (!process.env.OPENAI_API_KEY) {
return 'OPENAI_API_KEY environment variable not found. You can enter it interactively or add it to your .env file.';
}
return null;
}
@@ -49,13 +49,13 @@ export const validateAuthMethod = (authMethod: string): string | null => {
};
export const setOpenAIApiKey = (apiKey: string): void => {
process.env.QWEN_CODE_API_KEY = apiKey;
process.env.OPENAI_API_KEY = apiKey;
};
export const setOpenAIBaseUrl = (baseUrl: string): void => {
process.env.QWEN_CODE_BASE_URL = baseUrl;
process.env.OPENAI_BASE_URL = baseUrl;
};
export const setOpenAIModel = (model: string): void => {
process.env.QWEN_CODE_MODEL = model;
process.env.OPENAI_MODEL = model;
};

View File

@@ -264,12 +264,12 @@ export async function loadCliConfig(
// Handle OpenAI API key from command line
if (argv.openaiApiKey) {
process.env.QWEN_CODE_API_KEY = argv.openaiApiKey;
process.env.OPENAI_API_KEY = argv.openaiApiKey;
}
// Handle OpenAI base URL from command line
if (argv.openaiBaseUrl) {
process.env.QWEN_CODE_BASE_URL = argv.openaiBaseUrl;
process.env.OPENAI_BASE_URL = argv.openaiBaseUrl;
}
// Set the context filename in the server's memoryTool module BEFORE loading memory

View File

@@ -1173,7 +1173,7 @@ describe('useGeminiStream', () => {
mockAuthType,
undefined,
'gemini-2.5-pro',
'qwen3-coder-flash',
'gemini-2.5-flash',
);
});
});

View File

@@ -39,7 +39,7 @@ describe('parseAndFormatApiError', () => {
);
expect(result).toContain('[API Error: Rate limit exceeded');
expect(result).toContain(
'Possible quota limitations in place or slow response times detected. Switching to the qwen3-coder-flash model',
'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
);
});
@@ -55,7 +55,7 @@ describe('parseAndFormatApiError', () => {
);
expect(result).toContain('[API Error: Rate limit exceeded');
expect(result).toContain(
'Possible quota limitations in place or slow response times detected. Switching to the qwen3-coder-flash model',
'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
);
});
@@ -169,7 +169,7 @@ describe('parseAndFormatApiError', () => {
);
expect(result).toContain('[API Error: Rate limit exceeded');
expect(result).toContain(
'Possible quota limitations in place or slow response times detected. Switching to the qwen3-coder-flash model',
'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
);
expect(result).not.toContain(
'You have reached your daily gemini-2.5-pro quota limit',

View File

@@ -517,15 +517,15 @@ export async function start_sandbox(
args.push('--env', `GOOGLE_API_KEY=${process.env.GOOGLE_API_KEY}`);
}
// copy QWEN_CODE_API_KEY and related env vars for Qwen
if (process.env.QWEN_CODE_API_KEY) {
args.push('--env', `QWEN_CODE_API_KEY=${process.env.QWEN_CODE_API_KEY}`);
// copy OPENAI_API_KEY and related env vars for Qwen
if (process.env.OPENAI_API_KEY) {
args.push('--env', `OPENAI_API_KEY=${process.env.OPENAI_API_KEY}`);
}
if (process.env.QWEN_CODE_BASE_URL) {
args.push('--env', `QWEN_CODE_BASE_URL=${process.env.QWEN_CODE_BASE_URL}`);
if (process.env.OPENAI_BASE_URL) {
args.push('--env', `OPENAI_BASE_URL=${process.env.OPENAI_BASE_URL}`);
}
if (process.env.QWEN_CODE_MODEL) {
args.push('--env', `QWEN_CODE_MODEL=${process.env.QWEN_CODE_MODEL}`);
if (process.env.OPENAI_MODEL) {
args.push('--env', `OPENAI_MODEL=${process.env.OPENAI_MODEL}`);
}
// copy GOOGLE_GENAI_USE_VERTEXAI

View File

@@ -1,12 +1,12 @@
{
"name": "@google/gemini-cli-core",
"version": "0.0.1-alpha.12",
"version": "0.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@google/gemini-cli-core",
"version": "0.0.1-alpha.12",
"version": "0.0.3",
"dependencies": {
"@google/genai": "^1.4.0",
"@modelcontextprotocol/sdk": "^1.11.0",

View File

@@ -1,10 +1,10 @@
{
"name": "@qwen-code/qwen-code-core",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"description": "Qwen Code Core",
"repository": {
"type": "git",
"url": "git+http://gitlab.alibaba-inc.com/Qwen-Coder/qwen-code.git"
"url": "git+https://github.com/QwenLM/qwen-code.git"
},
"type": "module",
"main": "dist/index.js",

View File

@@ -5,5 +5,5 @@
*/
export const DEFAULT_GEMINI_MODEL = 'qwen3-coder-plus';
export const DEFAULT_GEMINI_FLASH_MODEL = 'qwen3-coder-flash';
export const DEFAULT_GEMINI_FLASH_MODEL = 'gemini-2.5-flash';
export const DEFAULT_GEMINI_EMBEDDING_MODEL = 'gemini-embedding-001';

View File

@@ -34,7 +34,7 @@ describe('OpenAIContentGenerator Timeout Handling', () => {
vi.clearAllMocks();
// Mock environment variables
vi.stubEnv('QWEN_CODE_BASE_URL', '');
vi.stubEnv('OPENAI_BASE_URL', '');
// Mock config
mockConfig = {

View File

@@ -75,7 +75,7 @@ export async function createContentGeneratorConfig(
const googleApiKey = process.env.GOOGLE_API_KEY || undefined;
const googleCloudProject = process.env.GOOGLE_CLOUD_PROJECT || undefined;
const googleCloudLocation = process.env.GOOGLE_CLOUD_LOCATION || undefined;
const openaiApiKey = process.env.QWEN_CODE_API_KEY;
const openaiApiKey = process.env.OPENAI_API_KEY;
// Use runtime model from config if available, otherwise fallback to parameter or default
const effectiveModel = model || DEFAULT_GEMINI_MODEL;
@@ -117,7 +117,7 @@ export async function createContentGeneratorConfig(
if (authType === AuthType.USE_OPENAI && openaiApiKey) {
contentGeneratorConfig.apiKey = openaiApiKey;
contentGeneratorConfig.model =
process.env.QWEN_CODE_MODEL || DEFAULT_GEMINI_MODEL;
process.env.OPENAI_MODEL || DEFAULT_GEMINI_MODEL;
return contentGeneratorConfig;
}

View File

@@ -97,7 +97,7 @@ export class OpenAIContentGenerator implements ContentGenerator {
constructor(apiKey: string, model: string, config: Config) {
this.model = model;
this.config = config;
const baseURL = process.env.QWEN_CODE_BASE_URL || '';
const baseURL = process.env.OPENAI_BASE_URL || '';
// Configure timeout settings - using progressive timeouts
const timeoutConfig = {

View File

@@ -130,8 +130,8 @@ describe('URL matching with trailing slash compatibility', () => {
// Test case 1: No trailing slash in config, actual URL has trailing slash
process.env = {
...originalEnv,
QWEN_CODE_BASE_URL: 'https://api.example.com/',
QWEN_CODE_MODEL: 'gpt-4',
OPENAI_BASE_URL: 'https://api.example.com/',
OPENAI_MODEL: 'gpt-4',
};
const result1 = getCoreSystemPrompt(undefined, config);
@@ -140,8 +140,8 @@ describe('URL matching with trailing slash compatibility', () => {
// Test case 2: Config has trailing slash, actual URL has no trailing slash
process.env = {
...originalEnv,
QWEN_CODE_BASE_URL: 'https://api.openai.com',
QWEN_CODE_MODEL: 'gpt-3.5-turbo',
OPENAI_BASE_URL: 'https://api.openai.com',
OPENAI_MODEL: 'gpt-3.5-turbo',
};
const result2 = getCoreSystemPrompt(undefined, config);
@@ -150,8 +150,8 @@ describe('URL matching with trailing slash compatibility', () => {
// Test case 3: No trailing slash in config, actual URL has no trailing slash
process.env = {
...originalEnv,
QWEN_CODE_BASE_URL: 'https://api.example.com',
QWEN_CODE_MODEL: 'gpt-4',
OPENAI_BASE_URL: 'https://api.example.com',
OPENAI_MODEL: 'gpt-4',
};
const result3 = getCoreSystemPrompt(undefined, config);
@@ -160,8 +160,8 @@ describe('URL matching with trailing slash compatibility', () => {
// Test case 4: Config has trailing slash, actual URL has trailing slash
process.env = {
...originalEnv,
QWEN_CODE_BASE_URL: 'https://api.openai.com/',
QWEN_CODE_MODEL: 'gpt-3.5-turbo',
OPENAI_BASE_URL: 'https://api.openai.com/',
OPENAI_MODEL: 'gpt-3.5-turbo',
};
const result4 = getCoreSystemPrompt(undefined, config);
@@ -187,8 +187,8 @@ describe('URL matching with trailing slash compatibility', () => {
// Test case: URLs do not match
process.env = {
...originalEnv,
QWEN_CODE_BASE_URL: 'https://api.different.com',
QWEN_CODE_MODEL: 'gpt-4',
OPENAI_BASE_URL: 'https://api.different.com',
OPENAI_MODEL: 'gpt-4',
};
const result = getCoreSystemPrompt(undefined, config);

View File

@@ -65,8 +65,8 @@ export function getCoreSystemPrompt(
// Check for system prompt mappings from global config
if (config?.systemPromptMappings) {
const currentModel = process.env.QWEN_CODE_MODEL || DEFAULT_GEMINI_MODEL;
const currentBaseUrl = process.env.QWEN_CODE_BASE_URL || '';
const currentModel = process.env.OPENAI_MODEL || DEFAULT_GEMINI_MODEL;
const currentBaseUrl = process.env.OPENAI_BASE_URL || '';
const matchedMapping = config.systemPromptMappings.find((mapping) => {
const { baseUrls, modelNames } = mapping;

View File

@@ -1,12 +1,12 @@
{
"name": "qwen-code-vscode",
"version": "0.0.1-alpha.12",
"version": "0.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "qwen-code-vscode",
"version": "0.0.1-alpha.12",
"version": "0.0.3",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
"cors": "^2.8.5",

View File

@@ -2,7 +2,7 @@
"name": "@qwen-code/qwen-code-vscode-ide-companion",
"displayName": "Qwen Code VSCode IDE Companion",
"description": "",
"version": "0.0.1-alpha.12",
"version": "0.0.2",
"engines": {
"vscode": "^1.101.0"
},

View File

@@ -14,20 +14,44 @@ function getPackageVersion() {
return packageJson.version;
}
function getShortSha() {
return execSync('git rev-parse --short HEAD').toString().trim();
function incrementPatchVersion(version) {
const parts = version.split('.');
const major = parseInt(parts[0]);
const minor = parseInt(parts[1]);
const patch = parseInt(parts[2].split('-')[0]); // Handle pre-release versions
return `${major}.${minor}.${patch + 1}`;
}
function getLatestNightlyCount() {
try {
// Try to get the latest nightly tag from git to determine the counter
const currentVersion = getPackageVersion();
const nextVersion = incrementPatchVersion(currentVersion);
const tags = execSync(`git tag -l "v${nextVersion}-nightly.*"`)
.toString()
.trim();
if (!tags) return 0;
const nightlyTags = tags.split('\n').filter(Boolean);
const counts = nightlyTags.map((tag) => {
const match = tag.match(/nightly\.(\d+)$/);
return match ? parseInt(match[1]) : 0;
});
return Math.max(...counts, -1) + 1;
} catch (_error) {
// If we can't get tags, start from 0
return 0;
}
}
export function getNightlyTagName() {
const version = getPackageVersion();
const now = new Date();
const year = now.getUTCFullYear().toString().slice(-2);
const month = (now.getUTCMonth() + 1).toString().padStart(2, '0');
const day = now.getUTCDate().toString().padStart(2, '0');
const date = `${year}${month}${day}`;
const nextVersion = incrementPatchVersion(version);
const nightlyCount = getLatestNightlyCount();
const sha = getShortSha();
return `v${version}-nightly.${date}.${sha}`;
return `v${nextVersion}-nightly.${nightlyCount}`;
}
export function getReleaseVersion() {
@@ -72,7 +96,13 @@ export function getReleaseVersion() {
const releaseVersion = releaseTag.substring(1);
let npmTag = 'latest';
if (releaseVersion.includes('-')) {
npmTag = releaseVersion.split('-')[1].split('.')[0];
const prereleasePart = releaseVersion.split('-')[1];
npmTag = prereleasePart.split('.')[0];
// Ensure nightly releases use 'nightly' tag, not 'latest'
if (npmTag === 'nightly') {
npmTag = 'nightly';
}
}
return { releaseTag, releaseVersion, npmTag };

View File

@@ -41,15 +41,14 @@ describe('getReleaseVersion', () => {
it('should calculate nightly version when IS_NIGHTLY is true', () => {
process.env.IS_NIGHTLY = 'true';
const knownDate = new Date('2025-07-20T10:00:00.000Z');
vi.setSystemTime(knownDate);
vi.mocked(fs.default.readFileSync).mockReturnValue(
JSON.stringify({ version: '0.1.0' }),
);
vi.mocked(execSync).mockReturnValue('abcdef');
// Mock git tag command to return empty (no existing nightly tags)
vi.mocked(execSync).mockReturnValue('');
const { releaseTag, releaseVersion, npmTag } = getReleaseVersion();
expect(releaseTag).toBe('v0.1.0-nightly.250720.abcdef');
expect(releaseVersion).toBe('0.1.0-nightly.250720.abcdef');
expect(releaseTag).toBe('v0.1.1-nightly.0');
expect(releaseVersion).toBe('0.1.1-nightly.0');
expect(npmTag).toBe('nightly');
});
@@ -99,8 +98,8 @@ describe('getReleaseVersion', () => {
describe('get-release-version script', () => {
it('should print version JSON to stdout when executed directly', () => {
const expectedJson = {
releaseTag: 'v0.1.0-nightly.20250705',
releaseVersion: '0.1.0-nightly.20250705',
releaseTag: 'v0.1.1-nightly.0',
releaseVersion: '0.1.1-nightly.0',
npmTag: 'nightly',
};
execSync.mockReturnValue(JSON.stringify(expectedJson));

View File

@@ -23,18 +23,24 @@ function writeJson(filePath, data) {
writeFileSync(filePath, JSON.stringify(data, null, 2) + '\n');
}
// 1. Get the version type from the command line arguments.
const versionType = process.argv[2];
if (!versionType) {
console.error('Error: No version type specified.');
console.error('Usage: npm run version <patch|minor|major|prerelease>');
// 1. Get the version from the command line arguments.
const versionArg = process.argv[2];
if (!versionArg) {
console.error('Error: No version specified.');
console.error(
'Usage: npm run version <version> (e.g., 1.2.3 or patch|minor|major|prerelease)',
);
process.exit(1);
}
// 2. Bump the version in the root and all workspace package.json files.
run(`npm version ${versionType} --no-git-tag-version --allow-same-version`);
// 2. Determine if we have a specific version or a version type
const isSpecificVersion = /^\d+\.\d+\.\d+/.test(versionArg);
const npmVersionArg = isSpecificVersion ? versionArg : versionArg;
// 3. Bump the version in the root and all workspace package.json files.
run(`npm version ${npmVersionArg} --no-git-tag-version --allow-same-version`);
run(
`npm version ${versionType} --workspaces --no-git-tag-version --allow-same-version`,
`npm version ${npmVersionArg} --workspaces --no-git-tag-version --allow-same-version`,
);
// 3. Get the new version number from the root package.json