mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-17 03:57:18 +00:00
fix(cli): resolve chunk-relative sibling paths under esbuild splitting
With `splitting: true`, esbuild hoists modules with shared dependencies into `dist/chunks/`. Three modules derived runtime paths from `import.meta.url` assuming they were co-located with `cli.js`; once hoisted, `path.dirname(fileURLToPath(import.meta.url))` resolved to `dist/chunks/` and sibling-asset lookups silently missed: - `skill-manager.ts`: bundledSkillsDir → `dist/chunks/bundled` (actual `dist/bundled/`). The `existsSync` guard swallowed the miss, dropping all four bundled skills (`/review`, `/qc-helper`, `/batch`, `/loop`) with no user-visible signal. - `ripgrepUtils.ts`: `getBuiltinRipgrep()` → `dist/chunks/vendor/...`. Falls back to system rg if installed, otherwise null on minimal hosts — degrading grep to the slow internal scanner. - `i18n/index.ts`: `getBuiltinLocalesDir()` → `dist/chunks/locales`. User-visible behavior survives via the static glob import in `tryImportBundledTranslations`, but the loose-on-disk override path is dead. Each module now strips a trailing `chunks` segment when present, so the lookup resolves under `dist/`. In source / transpiled modes the basename is never `chunks`, so the fallback is a no-op. Also: - Add `chunks` to `DIST_REQUIRED_PATHS` in `create-standalone-package.js` so a regressed bundle that produces only `cli.js` fails the pre-packaging check instead of shipping a broken archive. - Expand `esbuild-shims.js` header so future contributors understand that `__qwen_filename` / `__qwen_dirname` always resolve to the shim's chunk file (dist/chunks/) and that sibling-asset lookups must strip the `chunks` segment. Reported by claude-opus-4-7 via Qwen Code /qreview on #4070. Generated with AI Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
c201ba2fcb
commit
d581da04dd
5 changed files with 49 additions and 8 deletions
|
|
@ -44,7 +44,16 @@ type TranslationLoadResult =
|
|||
// Path helpers
|
||||
const getBuiltinLocalesDir = (): string => {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
return path.join(path.dirname(__filename), 'locales');
|
||||
// When bundled with esbuild code-splitting, this module is hoisted into a
|
||||
// shared chunk under `dist/chunks/`. The locales directory is still copied
|
||||
// to `dist/locales/` (a sibling of cli.js), so strip the trailing `chunks`
|
||||
// segment so the lookup resolves under `dist/`. In source / transpiled
|
||||
// modes the basename is never `chunks`, so this is a no-op.
|
||||
let moduleDir = path.dirname(__filename);
|
||||
if (path.basename(moduleDir) === 'chunks') {
|
||||
moduleDir = path.dirname(moduleDir);
|
||||
}
|
||||
return path.join(moduleDir, 'locales');
|
||||
};
|
||||
|
||||
const getUserLocalesDir = (): string =>
|
||||
|
|
|
|||
|
|
@ -86,10 +86,17 @@ export class SkillManager {
|
|||
private activationRegistry: SkillActivationRegistry | null = null;
|
||||
|
||||
constructor(private readonly config: Config) {
|
||||
this.bundledSkillsDir = path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'bundled',
|
||||
);
|
||||
// When bundled with esbuild code-splitting, this module is hoisted into
|
||||
// a shared chunk under `dist/chunks/`. The bundled skills directory is
|
||||
// still copied to `dist/bundled/` by `copy_bundle_assets.js`, so strip
|
||||
// the trailing `chunks` segment so the sibling lookup resolves under
|
||||
// `dist/` rather than `dist/chunks/`. In source / transpiled modes the
|
||||
// basename is never `chunks`, so this is a no-op.
|
||||
let moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
if (path.basename(moduleDir) === 'chunks') {
|
||||
moduleDir = path.dirname(moduleDir);
|
||||
}
|
||||
this.bundledSkillsDir = path.join(moduleDir, 'bundled');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -57,9 +57,18 @@ function wslTimeout(): number {
|
|||
: RIPGREP_RUN_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
// Get the directory of the current module
|
||||
// Get the directory of the current module. When bundled with esbuild
|
||||
// code-splitting, this file is hoisted into `dist/chunks/`, but the vendored
|
||||
// ripgrep binary is still copied to `dist/vendor/` (a sibling of cli.js).
|
||||
// Strip the trailing `chunks` segment so the lookup below resolves under
|
||||
// `dist/`. In source / transpiled modes the basename is never `chunks`, so
|
||||
// the fallback is a no-op.
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const __dirnameRaw = path.dirname(__filename);
|
||||
const __dirname =
|
||||
path.basename(__dirnameRaw) === 'chunks'
|
||||
? path.dirname(__dirnameRaw)
|
||||
: __dirnameRaw;
|
||||
|
||||
type Platform = 'darwin' | 'linux' | 'win32';
|
||||
type Architecture = 'x64' | 'arm64';
|
||||
|
|
|
|||
|
|
@ -36,7 +36,12 @@ const TARGETS = new Map([
|
|||
['win-x64', { outputExtension: 'zip', nodeExecutable: ['node.exe'] }],
|
||||
]);
|
||||
|
||||
const DIST_REQUIRED_PATHS = ['cli.js', 'vendor', 'bundled/qc-helper/docs'];
|
||||
const DIST_REQUIRED_PATHS = [
|
||||
'cli.js',
|
||||
'chunks',
|
||||
'vendor',
|
||||
'bundled/qc-helper/docs',
|
||||
];
|
||||
const DIST_ALLOWED_ENTRIES = new Set([
|
||||
'cli.js',
|
||||
'chunks',
|
||||
|
|
|
|||
|
|
@ -27,5 +27,16 @@ if (typeof globalThis.require === 'undefined') {
|
|||
}
|
||||
|
||||
export const require = _require;
|
||||
// IMPORTANT: __qwen_filename / __qwen_dirname always resolve to this shim's
|
||||
// chunk file — i.e. dist/chunks/ in a built bundle, NOT the directory of any
|
||||
// source file that uses bare __dirname / __filename. esbuild's `define`
|
||||
// rewrites all free references in source code to these symbols, so to get a
|
||||
// per-file path you MUST declare a local shadow at the top of your module:
|
||||
// const __filename = fileURLToPath(import.meta.url);
|
||||
// const __dirname = path.dirname(__filename);
|
||||
// Even with a local shadow, under code-splitting the path can still point to
|
||||
// dist/chunks/ rather than the source dir — sibling-asset lookups (vendor/,
|
||||
// bundled/, locales/) must strip a trailing `chunks` segment. See
|
||||
// skill-manager.ts / ripgrepUtils.ts / i18n/index.ts for the pattern.
|
||||
export const __qwen_filename = fileURLToPath(import.meta.url);
|
||||
export const __qwen_dirname = dirname(__qwen_filename);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue