autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
169 lines (168 loc) • 7.41 kB
JavaScript
/**
* UiStartupTasks — asd ui 启动后异步后台刷新任务
*
* 在 Dashboard 启动后异步执行,不阻塞 UI:
* 1. syncAll: .md → DB 全量同步 + sourceRefs 对账
* 2. staging promote: 到期 staging → active 晋升
* 3. vector reconcile: 向量对账(best-effort)
* 4. refreshIndex: BM25 增量刷新
* 5. proposalCheck: 到期 Proposal 检查 + 自动执行/拒绝
* 6. metabolismCycle: 知识新陈代谢(矛盾/冗余/衰退扫描 → 新 Proposal)
* 7. timeoutCheck: 中间态超时兜底(evolving/decaying 超时自动恢复)
*/
import Logger from '../../infrastructure/logging/Logger.js';
const logger = Logger.getInstance();
/**
* 异步执行所有启动后台任务。
* 每个阶段独立 try/catch,一个失败不影响后续。
*/
export async function runUiStartupTasks(ctx) {
const start = Date.now();
const report = { durationMs: 0, errors: [] };
logger.info('[UiStartupTasks] Starting background refresh...');
// ── Stage 1: syncAll (.md → DB + sourceRefs reconcile) ──
try {
const { KnowledgeSyncService } = await import('../../cli/KnowledgeSyncService.js');
const { SourceRefReconciler } = await import('../../service/knowledge/SourceRefReconciler.js');
const sourceRefReconciler = ctx.container.singletons.sourceRefReconciler;
const syncService = new KnowledgeSyncService(ctx.projectRoot, {
sourceRefReconciler: sourceRefReconciler || undefined,
});
const db = ctx.container.get('database');
const syncReport = await syncService.syncAll(db, { skipViolations: true });
report.syncAll = {
synced: syncReport.synced,
created: syncReport.created,
updated: syncReport.updated,
};
if (syncReport.reconcileReport) {
report.reconcile = {
inserted: syncReport.reconcileReport.inserted,
active: syncReport.reconcileReport.active,
stale: syncReport.reconcileReport.stale,
};
}
logger.info('[UiStartupTasks] Stage 1 complete: syncAll', report.syncAll);
}
catch (err) {
const msg = `syncAll failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 2: Staging auto-promotion (Bug 2 fix) ──
try {
if (ctx.container.services.stagingManager) {
const sm = ctx.container.get('stagingManager');
const result = await sm.checkAndPromote();
report.staging = { promoted: result.promoted.length };
if (result.promoted.length > 0) {
logger.info(`[UiStartupTasks] Stage 2: auto-promoted ${result.promoted.length} staging entries`);
}
}
}
catch (err) {
const msg = `staging promote failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 3: Vector reconcile (best-effort) ──
try {
if (ctx.container.services.vectorService) {
const vectorService = ctx.container.get('vectorService');
if (vectorService.syncCoordinator &&
typeof vectorService.syncCoordinator.reconcile === 'function') {
const result = await vectorService.syncCoordinator.reconcile();
report.vectorReconcile = {
orphans: result.orphansRemoved,
missing: result.missingQueued,
};
logger.info('[UiStartupTasks] Stage 3: vector reconcile complete', report.vectorReconcile);
}
}
}
catch (err) {
const msg = `vector reconcile failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 4: BM25 index refresh ──
try {
if (ctx.container.services.searchEngine) {
const searchEngine = ctx.container.get('searchEngine');
searchEngine.refreshIndex({ force: true });
report.indexRefresh = true;
logger.info('[UiStartupTasks] Stage 4: BM25 index refreshed');
}
}
catch (err) {
const msg = `index refresh failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 5: ProposalExecutor — 到期 Proposal 检查 + 自动执行 ──
try {
if (ctx.container.services.proposalExecutor) {
const executor = ctx.container.get('proposalExecutor');
const result = await executor.checkAndExecute();
report.proposalCheck = {
executed: result.executed.length,
rejected: result.rejected.length,
expired: result.expired.length,
};
const total = result.executed.length + result.rejected.length + result.expired.length;
if (total > 0) {
logger.info(`[UiStartupTasks] Stage 5: proposal check — executed=${result.executed.length}, rejected=${result.rejected.length}, expired=${result.expired.length}`);
}
}
}
catch (err) {
const msg = `proposal check failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 6: KnowledgeMetabolism — 知识新陈代谢扫描 ──
try {
if (ctx.container.services.knowledgeMetabolism) {
const metabolism = ctx.container.get('knowledgeMetabolism');
const result = await metabolism.runFullCycle();
report.metabolismCycle = {
proposalCount: result.summary.proposalCount,
contradictions: result.summary.contradictionCount,
redundancies: result.summary.redundancyCount,
decaying: result.summary.decayingCount,
};
if (result.summary.proposalCount > 0) {
logger.info(`[UiStartupTasks] Stage 6: metabolism cycle — ${result.summary.proposalCount} proposals generated`);
}
}
}
catch (err) {
const msg = `metabolism cycle failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
// ── Stage 7: Supervisor — 中间态超时兜底 ──
try {
if (ctx.container.services.lifecycleSupervisor) {
const supervisor = ctx.container.get('lifecycleSupervisor');
const result = await supervisor.checkTimeouts();
report.timeoutCheck = {
timedOut: result.timedOut.length,
checked: result.checked,
};
if (result.timedOut.length > 0) {
logger.info(`[UiStartupTasks] Stage 7: timeout check — ${result.timedOut.length} recipes timed out (checked: ${result.checked})`);
}
}
}
catch (err) {
const msg = `timeout check failed: ${err.message}`;
report.errors.push(msg);
logger.warn(`[UiStartupTasks] ${msg}`);
}
report.durationMs = Date.now() - start;
logger.info(`[UiStartupTasks] All tasks completed in ${report.durationMs}ms`, {
errors: report.errors.length,
});
return report;
}