qwen-code/packages/vscode-ide-companion/package.json
易良 e49867a762
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
feat(vscode): replace OAuth with Coding Plan / API Key provider setup (#3398)
* refactor(core): move codingPlan constants from cli to core package

Extract Coding Plan region configs, model templates, and utility
functions into packages/core/src/constants/ so both CLI and VSCode
extension can import from a shared source of truth.

* refactor(cli): import codingPlan constants from core instead of local path

Update all CLI files to import CodingPlanRegion, CODING_PLAN_ENV_KEY,
and related utilities from @qwen-code/qwen-code-core, replacing the
local ../../constants/codingPlan.js imports.

* feat(vscode-ide-companion): replace login flow with provider setup via VSCode Settings

Replace the OAuth-based login command with a settings-driven provider
configuration flow. Users now configure Coding Plan or API Key providers
through VSCode Settings (qwen-code.*), which auto-syncs to
~/.qwen/settings.json.

- Rename login command to auth, opening VSCode Settings panel
- Add /auth2 interactive flow (QuickPick + InputBox)
- Add ProviderSetupForm onboarding component with inline config
- Add bidirectional sync between VSCode settings and ~/.qwen/settings.json
- Add settingsWriter service for direct settings.json read/write
- Add VSCode configuration schema (provider, apiKey, region, model, etc.)
- Update all login/session messages to use auth terminology

* refactor(vscode-ide-companion): rename auth2→auth, remove dead code, fix sync guard

- Rename auth2 to auth for all message types, handlers, and slash command
- Remove unused InfoBanner.tsx (128 lines, no references)
- Remove dead openProviderSettings handler (no callers)
- Remove redundant qwen-code.baseUrl VSCode setting (already in modelProviders)
- Replace unreliable setTimeout(500) sync guard with await Promise.all + finally
- Clean up old authHandler/setAuthHandler in favor of authInteractiveHandler

* refactor(vscode-ide-companion): remove dead VSCode Settings plumbing, simplify sync

- Remove qwen-code.modelProviders and qwen-code.model from package.json
  (model switching handled by chat UI's /model command, not VSCode Settings)
- Remove connectWithSettings message handler and plumbing
  (no webview component sends this message type)
- Remove handleConnectWithSettings method from WebViewProvider
- Simplify syncVSCodeSettingsToQwenConfig: only sync provider/apiKey/region
- Simplify syncQwenConfigToVSCodeSettings: only populate provider/apiKey/region
- Simplify QwenSettingsForVSCode interface: remove modelProviders and model
- Improve Onboarding UI: logo above card, better hierarchy, arrow icon on button

* fix(vscode-ide-companion): add missing vscode.workspace mock in test

Add onDidChangeConfiguration and getConfiguration to the vscode.workspace
mock in WebViewProvider.test.ts to fix CI test failures.

* fix(vscode-ide-companion): clean up stale coding plan state, add auth cancel handling, add tests

- Clear CODING_PLAN_ENV_KEY and codingPlan metadata when switching to api-key mode
- Add authCancelled notification when QuickPick/InputBox is dismissed
- ProviderSetupForm resets button state on authCancelled
- syncVSCodeSettingsToQwenConfig returns false for api-key mode (no-op)
- Fix Onboarding vertical centering (flex-1 min-h-0)
- Import from @qwen-code/qwen-code-core top-level instead of deep paths
- Add tests: settingsWriter, ProviderSetupForm cancel, AuthMessageHandler cancel, WebViewProvider sync
- Fix redundant ternary in pick() helper

* fix(vscode-ide-companion): force center Onboarding against parent override

Parent container uses [&>*]:items-start and [&>*]:text-left which overrides
Tailwind classes. Use inline style for alignItems/justifyContent/textAlign
to ensure Onboarding is always centered both horizontally and vertically.

* fix(vscode-ide-companion): bundle onboarding logo

* test(vscode-ide-companion): add png loader to bundle test

* fix(vscode-ide-companion/webview): avoid redundant auth sync reconnects

* fix(vscode-ide-companion/webview): fix auth sync typecheck

* docs(vscode-ide-companion): clarify auth restoration flow

* fix(webui): use bracket access for permission drawer plan content

* fix(vscode-ide-companion): guard authSuccess emission on actual auth state

After reconnecting in handleAuthInteractive, doInitializeAgentConnection
may return without throwing even when credentials are rejected (it sends
authState:false internally and returns early). Previously we unconditionally
emitted authSuccess, which contradicted the failed auth state and could
briefly show a success toast before re-opening the auth flow.

Now we check this.authState after reconnection: only emit authSuccess when
authentication actually succeeded, otherwise emit authError with a clear
credentials message.

Addresses review feedback from PR #3398.

* fix(vscode): address auth setup review feedback

* fix(vscode-ide-companion): guard concurrent auth flows, merge model providers

- Add authFlowActive mutex and autoAuthTimer to WebViewProvider so
  startInteractiveAuth() cancels the deferred auto-auth timeout,
  preventing two overlapping QuickPick flows from a single command.
- Change writeModelProvidersConfig() to merge new entries with existing
  non-target models (different envKey) instead of replacing the entire
  array, preserving unrelated providers like Coding Plan.

* fix(vscode-ide-companion): handle apiKey clearing as de-auth signal, fix auto-auth race, clean imports

- Add clearPersistedAuth() to settingsWriter.ts: removes selectedType,
  API keys, and coding plan metadata from ~/.qwen/settings.json
- Config change handler now detects empty apiKey with active agent and
  triggers de-auth: clear credentials, disconnect, update authState
- Auto-auth timer callback now properly sets authFlowActive mutex to
  prevent concurrent auth flows with startInteractiveAuth()
- Add test covering the de-auth path (clearPersistedAuth + disconnect)
- Fix import formatting in 7 CLI files (spacing, trailing commas)
- Remove duplicate comment in attemptAuthStateRestoration()

* fix(vscode-ide-companion): scope de-auth to apiKey changes only

The previous de-auth logic triggered on any auth-related setting change
where syncVSCodeSettingsToQwenConfig() returned false. For api-key
providers this is the normal path (interactive auth owns config), so
changing codingPlanRegion or provider would incorrectly wipe OPENAI_API_KEY.

Now the de-auth branch only fires when e.affectsConfiguration('qwen-code.apiKey')
is true AND the value is empty, preventing false-positive credential clearing.

Add regression test: non-apiKey setting changes on an api-key provider
must not trigger clearPersistedAuth or disconnect.

* fix(vscode-ide-companion): add disconnect to mock type to fix CI typecheck

The hoisted mockQwenAgentManagerInstances type was missing the
disconnect property, causing TS2339 in the de-auth test assertions.
2026-04-21 22:20:58 +08:00

270 lines
7.4 KiB
JSON

{
"name": "qwen-code-vscode-ide-companion",
"displayName": "Qwen Code Companion",
"description": "Enable Qwen Code with direct access to your VS Code workspace.",
"version": "0.14.5",
"publisher": "qwenlm",
"icon": "assets/icon.png",
"repository": {
"type": "git",
"url": "https://github.com/QwenLM/qwen-code.git",
"directory": "packages/vscode-ide-companion"
},
"engines": {
"vscode": "^1.85.0"
},
"license": "LICENSE",
"preview": true,
"categories": [
"AI"
],
"keywords": [
"qwen-code",
"qwen code",
"qwen",
"qwen code",
"cli",
"ide integration",
"ide companion"
],
"activationEvents": [
"onStartupFinished",
"onView:qwen-code.chatView.sidebar",
"onView:qwen-code.chatView.secondary",
"onCommand:qwen-code.openChat",
"onCommand:qwen-code.focusChat",
"onCommand:qwen-code.newConversation",
"onCommand:qwen-code.showLogs"
],
"contributes": {
"jsonValidation": [
{
"fileMatch": "**/.qwen/settings.json",
"url": "./schemas/settings.schema.json"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "qwen-code-sidebar",
"title": "Qwen Code",
"icon": "assets/sidebar-icon.svg",
"when": "!qwen-code:supportsSecondarySidebar"
}
],
"secondarySidebar": [
{
"id": "qwen-code-secondary",
"title": "Qwen Code",
"icon": "assets/sidebar-icon.svg",
"when": "qwen-code:supportsSecondarySidebar"
}
]
},
"views": {
"qwen-code-sidebar": [
{
"type": "webview",
"id": "qwen-code.chatView.sidebar",
"name": "Qwen Code",
"icon": "assets/sidebar-icon.svg",
"when": "!qwen-code:supportsSecondarySidebar"
}
],
"qwen-code-secondary": [
{
"type": "webview",
"id": "qwen-code.chatView.secondary",
"name": "Qwen Code",
"icon": "assets/sidebar-icon.svg",
"when": "qwen-code:supportsSecondarySidebar"
}
]
},
"languages": [
{
"id": "qwen-diff-editable"
}
],
"commands": [
{
"command": "qwen.diff.accept",
"title": "Qwen Code: Accept Current Diff",
"icon": "$(check)"
},
{
"command": "qwen.diff.cancel",
"title": "Qwen Code: Close Diff Editor",
"icon": "$(close)"
},
{
"command": "qwen-code.runQwenCode",
"title": "Qwen Code: Run"
},
{
"command": "qwen-code.showNotices",
"title": "Qwen Code: View Third-Party Notices"
},
{
"command": "qwen-code.openChat",
"title": "Qwen Code: Open",
"icon": "./assets/icon.png"
},
{
"command": "qwen-code.auth",
"title": "Qwen Code: Auth"
},
{
"command": "qwen-code.focusChat",
"title": "Qwen Code: Focus Chat View"
},
{
"command": "qwen-code.newConversation",
"title": "Qwen Code: New Conversation"
},
{
"command": "qwen-code.showLogs",
"title": "Qwen Code: Show Logs"
}
],
"menus": {
"commandPalette": [
{
"command": "qwen.diff.accept",
"when": "qwen.diff.isVisible"
},
{
"command": "qwen.diff.cancel",
"when": "qwen.diff.isVisible"
},
{
"command": "qwen-code.auth"
}
],
"editor/title": [
{
"command": "qwen.diff.accept",
"when": "qwen.diff.isVisible",
"group": "navigation"
},
{
"command": "qwen.diff.cancel",
"when": "qwen.diff.isVisible",
"group": "navigation"
},
{
"command": "qwen-code.openChat",
"group": "navigation"
}
]
},
"configuration": {
"title": "Qwen Code",
"properties": {
"qwen-code.provider": {
"order": 0,
"type": "string",
"enum": [
"coding-plan",
"api-key"
],
"enumDescriptions": [
"Alibaba Cloud Coding Plan — configurable from VS Code Settings",
"Configured via Qwen Code: Auth or the onboarding button"
],
"default": "coding-plan",
"markdownDescription": "**Coding Plan**: enter API Key + Region here to sync `~/.qwen/settings.json`.\n\n**API Key**: use **Qwen Code: Auth** or the onboarding button to configure ModelStudio or custom OpenAI-compatible providers."
},
"qwen-code.apiKey": {
"order": 1,
"type": "string",
"default": "",
"markdownDescription": "API key used for **Coding Plan** settings sync. For **API Key** providers, configure the full provider details through **Qwen Code: Auth**."
},
"qwen-code.codingPlanRegion": {
"order": 2,
"type": "string",
"enum": [
"china",
"global"
],
"enumDescriptions": [
"China — 阿里云百炼 (aliyun.com)",
"Global — Alibaba Cloud (alibabacloud.com)"
],
"default": "china",
"markdownDescription": "Region for Coding Plan. _(Only used when Provider is `coding-plan`)_"
}
}
},
"keybindings": [
{
"command": "qwen.diff.accept",
"key": "ctrl+s",
"when": "qwen.diff.isVisible"
},
{
"command": "qwen.diff.accept",
"key": "cmd+s",
"when": "qwen.diff.isVisible"
},
{
"command": "qwen-code.focusChat",
"key": "ctrl+shift+l",
"mac": "cmd+shift+l"
}
]
},
"main": "./dist/extension.cjs",
"type": "module",
"scripts": {
"prepackage": "node ./scripts/prepackage.js",
"build": "npm run build:dev",
"build:dev": "npm run check-types && npm run lint && node esbuild.js",
"build:prod": "node esbuild.js --production",
"generate:notices": "node ./scripts/generate-notices.js",
"prepare": "npm run generate:notices",
"check-types": "tsc --noEmit",
"lint": "eslint src",
"watch": "npm-run-all2 -p watch:*",
"watch:esbuild": "node esbuild.js --watch",
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
"package": "vsce package --no-dependencies",
"test": "vitest run",
"test:ci": "vitest run --coverage",
"validate:notices": "node ./scripts/validate-notices.js"
},
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/markdown-it": "^14.1.2",
"@types/node": "20.x",
"@types/react": "^19.2.10",
"@types/react-dom": "^19.2.3",
"@types/semver": "^7.7.1",
"@types/vscode": "^1.85.0",
"@typescript-eslint/eslint-plugin": "^8.31.1",
"@typescript-eslint/parser": "^8.31.1",
"autoprefixer": "^10.4.22",
"esbuild": "^0.25.3",
"eslint": "^9.25.1",
"eslint-plugin-react-hooks": "^5.2.0",
"npm-run-all2": "^8.0.2",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18",
"typescript": "^5.8.3",
"vitest": "^3.2.4"
},
"dependencies": {
"@agentclientprotocol/sdk": "^0.14.1",
"@qwen-code/webui": "*",
"@modelcontextprotocol/sdk": "^1.25.1",
"cors": "^2.8.5",
"express": "^5.1.0",
"markdown-it": "^14.1.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"semver": "^7.7.2",
"zod": "^3.25.76"
}
}