ci: auto build & obfuscate [2026-04-06 00:50:28] (Jenkins #7)

This commit is contained in:
Jenkins CI
2026-04-06 00:50:28 +08:00
parent ed3f52a568
commit 49c1fa6f60
142 changed files with 38769 additions and 29661 deletions

View File

@@ -0,0 +1,18 @@
import { Module, ModuleBuilder } from './Module.js';
const builder = new ModuleBuilder()
.name('AdditionalFeatures')
.view('assets/amily-additional-features/Amily2-AdditionalFeatures.html');
export default class AdditionalFeaturesModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_additional_features_panel';
this.el.style.display = 'none';
}
}
}

View File

@@ -0,0 +1,28 @@
import { Module, ModuleBuilder } from './Module.js';
import { bindApiConfigPanel } from '../../ui/api-config-bindings.js';
import { syncAllSlots } from '../../ui/profile-sync.js';
const builder = new ModuleBuilder()
.name('ApiConfig')
.view('assets/api-config-panel.html')
.strict(true)
.required(['mount']);
export default class ApiConfigModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_api_config_panel';
this.el.style.display = 'none';
}
bindApiConfigPanel($(this.el));
syncAllSlots();
}
expose() {
return { syncAllSlots };
}
}

22
SL/module/CWBModule.js Normal file
View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { initializeCharacterWorldBook } from '../../CharacterWorldBook/cwb_index.js';
const builder = new ModuleBuilder()
.name('CharacterWorldBook')
.view('CharacterWorldBook/cwb_settings.html')
.strict(true)
.required(['mount']);
export default class CWBModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_character_world_book_panel';
this.el.style.display = 'none';
}
await initializeCharacterWorldBook($(this.el));
}
}

View File

@@ -0,0 +1,24 @@
import { Module, ModuleBuilder } from './Module.js';
const builder = new ModuleBuilder()
.name('Glossary')
.view('assets/amily-glossary-system/amily2-glossary.html')
.strict(true)
.required(['mount']);
export default class GlossaryModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_glossary_panel';
this.el.style.display = 'none';
}
// bindGlossaryEvents 由 index.js 中 waitForGlossaryPanelAndBindEvents 轮询调用
// 模块化后面板已就绪,可直接绑定
const { bindGlossaryEvents } = await import('../../glossary/GT_bindings.js');
bindGlossaryEvents();
}
}

View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { bindHanlinyuanEvents } from '../../ui/hanlinyuan-bindings.js';
const builder = new ModuleBuilder()
.name('Hanlinyuan')
.view('assets/amily-hanlinyuan-system/hanlinyuan.html')
.strict(true)
.required(['mount']);
export default class HanlinyuanModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_hanlinyuan_panel';
this.el.style.display = 'none';
}
bindHanlinyuanEvents();
}
}

View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { bindHistoriographyEvents } from '../../ui/historiography-bindings.js';
const builder = new ModuleBuilder()
.name('Historiography')
.view('assets/Amily2-TextOptimization.html')
.strict(true)
.required(['mount']);
export default class HistoriographyModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_text_optimization_panel';
this.el.style.display = 'none';
}
bindHistoriographyEvents();
}
}

144
SL/module/ModuleRegistry.js Normal file
View File

@@ -0,0 +1,144 @@
/**
* ModuleRegistry — 模块注册中心
*
* 职责:
* 1. 收集所有 Module 子类的注册信息name → factory
* 2. 统一执行 init → mount 生命周期
* 3. 向 Amily2Bus 暴露各模块的 expose() 结果,供跨模块调用
* 4. 提供 dispose 方法用于整体卸载
*
* 用法:
* import { registry } from 'SL/module/ModuleRegistry.js';
* registry.register('Hanlinyuan', () => new HanlinyuanModule());
* await registry.mountAll(ctx); // ctx = { baseUrl, root, ... }
* registry.query('Hanlinyuan'); // 获取该模块 expose() 的公开 API
*/
const _modules = new Map(); // name → Module instance (mounted)
const _factories = new Map(); // name → () => Module
/**
* 注册一个模块工厂。
* @param {string} name 唯一模块名
* @param {Function} factory 无参函数,返回 Module 实例
*/
export function register(name, factory) {
if (_factories.has(name)) {
console.warn(`[ModuleRegistry] 模块 "${name}" 已注册,将覆盖。`);
}
_factories.set(name, factory);
}
/**
* 初始化并挂载所有已注册模块。
* @param {Object} ctx 传给 module.init(ctx) 的上下文
* ctx.baseUrl — 插件根 URL用于 view 路径解析)
* ctx.root — 挂载目标 DOM 元素
*/
export async function mountAll(ctx = {}) {
for (const [name, factory] of _factories) {
if (_modules.has(name)) {
console.warn(`[ModuleRegistry] 模块 "${name}" 已挂载,跳过。`);
continue;
}
try {
const mod = factory();
await mod.init(ctx);
await mod.mount();
_modules.set(name, mod);
// 向 Bus 暴露模块公开 API
_exposeToBus(name, mod);
console.log(`[ModuleRegistry] ✔ ${name}`);
} catch (e) {
console.error(`[ModuleRegistry] ✘ ${name} 挂载失败:`, e);
}
}
}
/**
* 按名称挂载单个模块(延迟挂载场景)。
*/
export async function mountOne(name, ctx = {}) {
const factory = _factories.get(name);
if (!factory) {
console.warn(`[ModuleRegistry] 模块 "${name}" 未注册。`);
return null;
}
if (_modules.has(name)) return _modules.get(name);
const mod = factory();
await mod.init(ctx);
await mod.mount();
_modules.set(name, mod);
_exposeToBus(name, mod);
return mod;
}
/**
* 查询已挂载模块的公开 API。
*/
export function query(name) {
const mod = _modules.get(name);
return mod ? mod.expose() : null;
}
/**
* 获取已挂载的模块实例(内部使用)。
*/
export function getInstance(name) {
return _modules.get(name) || null;
}
/**
* 卸载所有模块。
*/
export function disposeAll() {
for (const [name, mod] of _modules) {
try {
mod.dispose();
} catch (e) {
console.error(`[ModuleRegistry] ${name} dispose 失败:`, e);
}
}
_modules.clear();
}
/**
* 已注册的模块名列表。
*/
export function names() {
return [..._factories.keys()];
}
// ── 内部 ──────────────────────────────────────────────
function _exposeToBus(name, mod) {
try {
const bus = window.Amily2Bus;
if (!bus) return;
const exposed = mod.expose();
if (exposed && Object.keys(exposed).length > 0) {
const _ctx = bus.register(`Module:${name}`);
if (_ctx) {
_ctx.expose(exposed);
_ctx.log(`Module:${name}`, 'info', `模块 ${name} 已注册到 Bus。`);
}
}
} catch (e) {
// Bus 未就绪或注册冲突,静默忽略
}
}
export const registry = {
register,
mountAll,
mountOne,
query,
getInstance,
disposeAll,
names,
};
export default registry;

View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { initializePlotOptimizationBindings } from '../../ui/plot-opt-bindings.js';
const builder = new ModuleBuilder()
.name('PlotOptimization')
.view('assets/Amily2-optimization.html')
.strict(true)
.required(['mount']);
export default class PlotOptModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_plot_optimization_panel';
this.el.style.display = 'none';
}
initializePlotOptimizationBindings();
}
}

View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { initializeRendererBindings } from '../../core/tavern-helper/renderer-bindings.js';
const builder = new ModuleBuilder()
.name('Renderer')
.view('core/tavern-helper/renderer.html')
.strict(true)
.required(['mount']);
export default class RendererModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_renderer_panel';
this.el.style.display = 'none';
}
initializeRendererBindings();
}
}

View File

@@ -0,0 +1,22 @@
import { Module, ModuleBuilder } from './Module.js';
import { bindSuperMemoryEvents } from '../../core/super-memory/bindings.js';
const builder = new ModuleBuilder()
.name('SuperMemory')
.view('core/super-memory/index.html')
.strict(true)
.required(['mount']);
export default class SuperMemoryModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_super_memory_panel';
this.el.style.display = 'none';
}
bindSuperMemoryEvents();
}
}

View File

@@ -0,0 +1,29 @@
import { Module, ModuleBuilder } from './Module.js';
import { extensionName } from '../../utils/settings.js';
const builder = new ModuleBuilder()
.name('WorldEditor')
.view('WorldEditor.html');
export default class WorldEditorModule extends Module {
constructor() {
super(builder);
}
async mount() {
if (this.el) {
this.el.id = 'amily2_world_editor_panel';
this.el.style.display = 'none';
}
// WorldEditor.js 必须作为 <script type="module"> 加载
const scriptId = 'world-editor-script';
if (!document.getElementById(scriptId)) {
const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`;
const script = document.createElement('script');
script.id = scriptId;
script.type = 'module';
script.src = `${extensionFolderPath}/WorldEditor/WorldEditor.js?v=${Date.now()}`;
document.head.appendChild(script);
}
}
}

36
SL/module/register-all.js Normal file
View File

@@ -0,0 +1,36 @@
/**
* register-all.js — 集中注册所有 UI 模块
*
* 调用 registerAllModules() 后,所有模块工厂被注册到 ModuleRegistry。
* 随后由 drawer.js 在面板容器就绪后调用 registry.mountAll(ctx) 完成挂载。
*
* 注册顺序即挂载顺序 —— DOM 中面板的排列取决于此。
*/
import registry from './ModuleRegistry.js';
import AdditionalFeaturesModule from './AdditionalFeaturesModule.js';
import HistoriographyModule from './HistoriographyModule.js';
import HanlinyuanModule from './HanlinyuanModule.js';
import TableModule from './TableModule.js';
import PlotOptModule from './PlotOptModule.js';
import CWBModule from './CWBModule.js';
import WorldEditorModule from './WorldEditorModule.js';
import GlossaryModule from './GlossaryModule.js';
import RendererModule from './RendererModule.js';
import SuperMemoryModule from './SuperMemoryModule.js';
import ApiConfigModule from './ApiConfigModule.js';
export function registerAllModules() {
registry.register('AdditionalFeatures', () => new AdditionalFeaturesModule());
registry.register('Historiography', () => new HistoriographyModule());
registry.register('Hanlinyuan', () => new HanlinyuanModule());
registry.register('Table', () => new TableModule());
registry.register('PlotOptimization', () => new PlotOptModule());
registry.register('CharacterWorldBook', () => new CWBModule());
registry.register('WorldEditor', () => new WorldEditorModule());
registry.register('Glossary', () => new GlossaryModule());
registry.register('Renderer', () => new RendererModule());
registry.register('SuperMemory', () => new SuperMemoryModule());
registry.register('ApiConfig', () => new ApiConfigModule());
}