



















@@ -16,6 +16,27 @@ export { copyStaticExtensionAssets, listStaticExtensionAssetOutputs };
16161717const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
1818const ROOT_RUNTIME_ALIAS_PATTERN = /^(?<base>.+\.(?:runtime|contract))-[A-Za-z0-9_-]+\.js$/u;
19+const ROOT_STABLE_RUNTIME_ALIAS_PATTERN = /^.+\.(?:runtime|contract)\.js$/u;
20+const ROOT_RUNTIME_IMPORT_SPECIFIER_PATTERN =
21+/(["'])\.\/([^"']+\.(?:runtime|contract)-[A-Za-z0-9_-]+\.js)\1/gu;
22+const LEGACY_ROOT_RUNTIME_COMPAT_ALIASES = [
23+// v2026.4.29 dispatch lazy chunks. Package updates used to replace the
24+// dist tree before the live gateway had restarted, so an already-loaded old
25+// dispatch chunk could still resolve these names after the swap.
26+["abort.runtime-DX6vo4yJ.js", "abort.runtime.js"],
27+["get-reply-from-config.runtime-uABrvCZ-.js", "get-reply-from-config.runtime.js"],
28+["reply-media-paths.runtime-C5UnVaLF.js", "reply-media-paths.runtime.js"],
29+["route-reply.runtime-D4PGzijU.js", "route-reply.runtime.js"],
30+["runtime-plugins.runtime-fLHuT7Vs.js", "runtime-plugins.runtime.js"],
31+["tts.runtime-66taD50M.js", "tts.runtime.js"],
32+// v2026.5.2-beta.1 dispatch lazy chunks.
33+["abort.runtime-CKviLU0L.js", "abort.runtime.js"],
34+["get-reply-from-config.runtime-BzFAggVK.js", "get-reply-from-config.runtime.js"],
35+["reply-media-paths.runtime-ZpULeITb.js", "reply-media-paths.runtime.js"],
36+["route-reply.runtime-uzaOjbd1.js", "route-reply.runtime.js"],
37+["runtime-plugins.runtime-CNAfmQRG.js", "runtime-plugins.runtime.js"],
38+["tts.runtime-D-THXDsp.js", "tts.runtime.js"],
39+];
1940const LEGACY_CLI_EXIT_COMPAT_CHUNKS = [
2041{
2142dest: "dist/memory-state-CcqRgDZU.js",
@@ -38,16 +59,106 @@ export function writeStableRootRuntimeAliases(params = {}) {
3859return;
3960}
406141-for (const entry of entries) {
62+const candidatesByAlias = new Map();
63+for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
4264if (!entry.isFile()) {
4365continue;
4466}
4567const match = entry.name.match(ROOT_RUNTIME_ALIAS_PATTERN);
4668if (!match?.groups?.base) {
4769continue;
4870}
49-const aliasPath = path.join(distDir, `${match.groups.base}.js`);
50-writeTextFileIfChanged(aliasPath, `export * from "./${entry.name}";\n`);
71+const aliasFileName = `${match.groups.base}.js`;
72+const candidates = candidatesByAlias.get(aliasFileName) ?? [];
73+candidates.push(entry.name);
74+candidatesByAlias.set(aliasFileName, candidates);
75+}
76+77+for (const [aliasFileName, candidates] of candidatesByAlias) {
78+const aliasPath = path.join(distDir, aliasFileName);
79+if (candidates.length !== 1) {
80+fsImpl.rmSync?.(aliasPath, { force: true });
81+continue;
82+}
83+writeTextFileIfChanged(aliasPath, `export * from "./${candidates[0]}";\n`);
84+}
85+}
86+87+export function rewriteRootRuntimeImportsToStableAliases(params = {}) {
88+const rootDir = params.rootDir ?? ROOT;
89+const distDir = path.join(rootDir, "dist");
90+const fsImpl = params.fs ?? fs;
91+let entries = [];
92+try {
93+entries = fsImpl.readdirSync(distDir, { withFileTypes: true });
94+} catch {
95+return;
96+}
97+98+const candidatesByAlias = new Map();
99+for (const entry of entries.toSorted((left, right) => left.name.localeCompare(right.name))) {
100+if (!entry.isFile()) {
101+continue;
102+}
103+const match = entry.name.match(ROOT_RUNTIME_ALIAS_PATTERN);
104+if (match?.groups?.base) {
105+const aliasFileName = `${match.groups.base}.js`;
106+const candidates = candidatesByAlias.get(aliasFileName) ?? [];
107+candidates.push(entry.name);
108+candidatesByAlias.set(aliasFileName, candidates);
109+}
110+}
111+const runtimeAliasFiles = new Map();
112+for (const [aliasFileName, candidates] of candidatesByAlias) {
113+if (candidates.length !== 1) {
114+continue;
115+}
116+runtimeAliasFiles.set(candidates[0], aliasFileName);
117+}
118+if (runtimeAliasFiles.size === 0) {
119+return;
120+}
121+122+for (const entry of entries) {
123+if (!entry.isFile() || !entry.name.endsWith(".js")) {
124+continue;
125+}
126+if (ROOT_STABLE_RUNTIME_ALIAS_PATTERN.test(entry.name)) {
127+continue;
128+}
129+const filePath = path.join(distDir, entry.name);
130+let source;
131+try {
132+source = fsImpl.readFileSync(filePath, "utf8");
133+} catch {
134+continue;
135+}
136+const rewritten = source.replace(
137+ROOT_RUNTIME_IMPORT_SPECIFIER_PATTERN,
138+(specifier, quote, fileName) => {
139+const aliasFileName = runtimeAliasFiles.get(fileName);
140+return aliasFileName ? `${quote}./${aliasFileName}${quote}` : specifier;
141+},
142+);
143+if (rewritten !== source) {
144+writeTextFileIfChanged(filePath, rewritten);
145+}
146+}
147+}
148+149+export function writeLegacyRootRuntimeCompatAliases(params = {}) {
150+const rootDir = params.rootDir ?? ROOT;
151+const distDir = path.join(rootDir, "dist");
152+const fsImpl = params.fs ?? fs;
153+for (const [legacyFileName, aliasFileName] of LEGACY_ROOT_RUNTIME_COMPAT_ALIASES) {
154+const legacyPath = path.join(distDir, legacyFileName);
155+if (fsImpl.existsSync(legacyPath)) {
156+continue;
157+}
158+if (!fsImpl.existsSync(path.join(distDir, aliasFileName))) {
159+continue;
160+}
161+writeTextFileIfChanged(legacyPath, `export * from "./${aliasFileName}";\n`);
51162}
52163}
53164@@ -76,7 +187,9 @@ export function runRuntimePostBuild(params = {}) {
76187runPhase("bundled plugin metadata", () => copyBundledPluginMetadata(params));
77188runPhase("official channel catalog", () => writeOfficialChannelCatalog(params));
78189runPhase("bundled plugin runtime overlay", () => stageBundledPluginRuntime(params));
190+runPhase("stable root runtime imports", () => rewriteRootRuntimeImportsToStableAliases(params));
79191runPhase("stable root runtime aliases", () => writeStableRootRuntimeAliases(params));
192+runPhase("legacy root runtime compat aliases", () => writeLegacyRootRuntimeCompatAliases(params));
80193runPhase("legacy CLI exit compat chunks", () => writeLegacyCliExitCompatChunks(params));
81194runPhase("static extension assets", () =>
82195copyStaticExtensionAssets({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。