fix(agent): recognize node-launched Qwen Code on Windows (#33461)

Detect Qwen Code on Windows: exact node entrypoint identities for the npm (@qwen-code/qwen-code cli-entry/cli) and standalone (qwen-code/lib) layouts, and comparablePath now collapses . / .. segments so shim paths like .bin\..\ match.

Fixes #17326
Supersedes #17382

Co-authored-by: Baojiang Lee <101562714+libaojiang@users.noreply.github.com>
This commit is contained in:
Neil
2026-10-25 02:28:15 -07:00
committed by GitHub
co-authored by Baojiang Lee
parent fca374c7d5
commit 49bde1c3d8
3 changed files with 46 additions and 1 deletions
+15 -1
View File
@@ -124,9 +124,23 @@ export function findInterpreterEntrypointToken(
}
export function comparablePath(token: string): string {
return token
const path = token
.trim()
.replace(/^["']|["']$/g, '')
.replace(/\\/g, '/')
.toLowerCase()
// Why: npm's local `.bin` shims and Qwen's standalone launcher run `<dir>/../<script>` paths.
const prefix = /^\/*/.exec(path)?.[0] ?? ''
const segments: string[] = []
for (const segment of path.slice(prefix.length).split('/')) {
if (segment === '' || segment === '.') {
continue
}
if (segment === '..' && segments.length > 0 && segments.at(-1) !== '..') {
segments.pop()
continue
}
segments.push(segment)
}
return prefix + segments.join('/')
}
@@ -41,5 +41,13 @@ export const EXACT_NODE_ENTRYPOINT_IDENTITIES: readonly {
pattern: /(?:^|\/)node_modules\/@deepseek-ai\/dsh\/lib\/bin\.js$/,
agent: 'dsh',
processName: 'dsh'
},
// Why: Qwen's npm bin is a generic `cli-entry` script that re-runs `cli` in a child node on
// Windows; the standalone installer ships the same pair under `qwen-code/lib/`.
{
pattern:
/(?:^|\/)(?:node_modules\/@qwen-code\/qwen-code\/(?:cli-entry|cli|scripts\/cli-entry|dist\/cli)|qwen-code\/lib\/cli(?:-entry)?)\.js$/,
agent: 'qwen-code',
processName: 'qwen'
}
]
@@ -426,6 +426,29 @@ describe('agent process recognition', () => {
expect(recognizeAgentProcessFromCommandLine(command)).toBeNull()
})
// Command lines captured from a live Windows Qwen Code 0.26.1 session (#17326).
it.each([
String.raw`"node" "C:\Users\dev\AppData\Local\Temp\q\node_modules\.bin\\..\@qwen-code\qwen-code\cli-entry.js"`,
String.raw`"node" "C:\Users\dev\AppData\Roaming\npm\\node_modules\@qwen-code\qwen-code\cli-entry.js"`,
String.raw`"C:\Program Files\nodejs\node.exe" --expose-gc C:\Users\dev\AppData\Roaming\npm\node_modules\@qwen-code\qwen-code\cli.js`,
String.raw`"C:\Users\dev\AppData\Local\qwen-code\qwen-code\node\node.exe" "C:\Users\dev\AppData\Local\qwen-code\qwen-code\bin\..\lib\cli-entry.js"`,
String.raw`C:\Users\dev\AppData\Local\qwen-code\qwen-code\node\node.exe --expose-gc C:\Users\dev\AppData\Local\qwen-code\qwen-code\lib\cli.js`,
'node /usr/local/lib/node_modules/@qwen-code/qwen-code/cli.js'
])('recognizes a node-launched Qwen Code entrypoint: %s', (command) => {
expect(recognizeAgentProcessFromCommandLine(command)).toEqual({
agent: 'qwen-code',
processName: 'qwen'
})
})
it.each([
'node /tmp/node_modules/@qwen-code/qwen-code/fzfWorker.js',
'node /tmp/node_modules/@other/qwen-code/cli.js',
'node /tmp/not-qwen-code/lib/cli.js'
])('does not recognize a Qwen Code entrypoint lookalike: %s', (command) => {
expect(recognizeAgentProcessFromCommandLine(command)).toBeNull()
})
it('recognizes Prime Agent by its binary and npm entrypoint', () => {
expect(recognizeAgentProcess('prime-agent')).toEqual({
agent: 'prime-agent',