qwen-code/packages/cli/assets/export-html/build.mjs
mingholy.lmh a364c8212e fix(export): fix TodoWrite tool call display in HTML export
- Restore plan update handling in collect.ts, formatting todo data as markdown checklist
- Skip todo_write tool_result processing in normalize.ts to avoid duplicates
- Add getMessageTimestamp() and getMessageUuid() methods to maintain message order
- Fix version parsing to support @latest tags
- Fix Windows spawn EINVAL error (CVE-2024-27980)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-05 16:48:27 +08:00

105 lines
3.2 KiB
JavaScript

import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { build } from 'esbuild';
import { buildConfig } from './esbuild.config.mjs';
import prettier from 'prettier';
const assetsDir = dirname(fileURLToPath(import.meta.url));
const srcDir = join(assetsDir, 'src');
const assetsDistDir = join(assetsDir, 'dist');
const packageDistDir = join(
assetsDir,
'..',
'..',
'dist',
'assets',
'export-html',
);
const templateModulePath = join(
assetsDir,
'..',
'..',
'src',
'ui',
'utils',
'export',
'formatters',
'htmlTemplate.ts',
);
const packageJsonPath = join(assetsDir, 'package.json');
await mkdir(assetsDistDir, { recursive: true });
await mkdir(packageDistDir, { recursive: true });
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
const dependencyVersions = packageJson?.dependencies ?? {};
const getDependencyVersion = (name) => {
const version = dependencyVersions[name];
if (!version) {
throw new Error(`Missing ${name} dependency version in package.json.`);
}
// Handle various version formats:
// - "^0.1.0" -> "0.1.0"
// - "~1.2.3" -> "1.2.3"
// - "latest" -> "latest"
// - "^0.1.0@latest" -> "0.1.0" (remove npm tag suffix)
const versionWithoutPrefix = version.replace(/^[^0-9a-zA-Z]+/, '');
// Remove npm tag suffix (e.g., "0.1.0@latest" -> "0.1.0")
return versionWithoutPrefix.replace(/@.+$/, '');
};
const webuiVersion = getDependencyVersion('@qwen-code/webui');
const reactUmdVersion = '18.2.0';
const reactDomUmdVersion = '18.2.0';
const buildResult = await build(buildConfig);
const jsBundle = buildResult.outputFiles.find((file) =>
file.path.endsWith('.js'),
);
const cssBundle = buildResult.outputFiles.find((file) =>
file.path.endsWith('.css'),
);
if (!jsBundle) {
throw new Error('Failed to generate inline script bundle.');
}
const css = cssBundle
? cssBundle.text
: await readFile(join(srcDir, 'styles.css'), 'utf8');
const htmlTemplate = await readFile(join(srcDir, 'index.html'), 'utf8');
const faviconSvg = await readFile(join(srcDir, 'favicon.svg'), 'utf8');
const faviconData = encodeURIComponent(faviconSvg.trim());
const htmlOutput = htmlTemplate
.replace('__INLINE_CSS__', css.trim())
.replace('__INLINE_SCRIPT__', jsBundle.text.trim())
.replaceAll('__REACT_UMD_VERSION__', reactUmdVersion)
.replaceAll('__REACT_DOM_UMD_VERSION__', reactDomUmdVersion)
.replaceAll('__WEBUI_VERSION__', webuiVersion)
.replace('__FAVICON_SVG__', faviconSvg.trim())
.replace('__FAVICON_DATA__', faviconData);
const templateModule = `/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*
* This HTML template is code-generated; do not edit manually.
*/
export const HTML_TEMPLATE = ${JSON.stringify(htmlOutput)};
`;
const formattedTemplateModule = await prettier.format(templateModule, {
parser: 'typescript',
singleQuote: true,
semi: true,
trailingComma: 'all',
printWidth: 80,
tabWidth: 2,
});
await writeFile(join(assetsDistDir, 'index.html'), htmlOutput);
await writeFile(join(packageDistDir, 'index.html'), htmlOutput);
await writeFile(templateModulePath, formattedTemplateModule);