fix(core): recognize legacy kb-* backups and canonicalize .kb/backups settings
- BackupManager.listBackups now matches kb-* and kb-pre-restore-* filenames alongside the fusion-* pattern, parsing timestamps from either prefix. - canonicalizeSettings rewrites autoBackupDir: ".kb/backups" to ".fusion/backups" so projects upgraded from the old brand keep working (custom .kb/* paths remain untouched). - createBackupManager applies the same canonicalization to settings it receives, so the factory path also produces backups under .fusion/backups. - Re-export getErrorMessage from core/src/types.ts so the dashboard's vite "@fusion/core" alias (which points at types.ts) resolves the symbol for client-side consumers — fixes the mobile build-output test. Clears all 8 pre-existing kb → fn rename failures plus the 1 test that regressed from the new getErrorMessage import surfacing the vite alias gap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -105,10 +105,11 @@ export class BackupManager {
|
||||
const backups: BackupInfo[] = [];
|
||||
|
||||
for (const filename of files) {
|
||||
// Match fusion-* backup patterns:
|
||||
// Match fusion-* and legacy kb-* backup patterns:
|
||||
// fusion-YYYY-MM-DD-HHmmss.db, fusion-YYYY-MM-DD-HHmmss-N.db,
|
||||
// fusion-pre-restore-YYYY-MM-DD-HHmmss.db
|
||||
if (!filename.match(/^fusion(-pre-restore)?-\d{4}-\d{2}-\d{2}-\d{6}(-\d+)?\.db$/)) {
|
||||
// kb-* variants kept for the ongoing kb → fn rename (see memory).
|
||||
if (!filename.match(/^(?:fusion|kb)(-pre-restore)?-\d{4}-\d{2}-\d{2}-\d{6}(-\d+)?\.db$/)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -116,9 +117,9 @@ export class BackupManager {
|
||||
const stats = await stat(filePath);
|
||||
|
||||
// Parse timestamp from filename. Also handles counter suffix: fusion-YYYY-MM-DD-HHmmss-N.db
|
||||
const match = filename.match(/^(fusion(?:-pre-restore)?)-(\d{4})-(\d{2})-(\d{2})-(\d{2})(\d{2})(\d{2})(?:-\d+)?\.db$/);
|
||||
const match = filename.match(/^(?:fusion|kb)(?:-pre-restore)?-(\d{4})-(\d{2})-(\d{2})-(\d{2})(\d{2})(\d{2})(?:-\d+)?\.db$/);
|
||||
const createdAt = match
|
||||
? `${match[2]}-${match[3]}-${match[4]}T${match[5]}:${match[6]}:${match[7]}Z`
|
||||
? `${match[1]}-${match[2]}-${match[3]}T${match[4]}:${match[5]}:${match[6]}Z`
|
||||
: stats.mtime.toISOString();
|
||||
|
||||
backups.push({
|
||||
@@ -291,11 +292,21 @@ export function createBackupManager(
|
||||
settings?: Partial<ProjectSettings>
|
||||
): BackupManager {
|
||||
return new BackupManager(fusionDir, {
|
||||
backupDir: settings?.autoBackupDir,
|
||||
backupDir: canonicalizeBackupDir(settings?.autoBackupDir),
|
||||
retention: settings?.autoBackupRetention,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize a legacy `.kb/backups` value to `.fusion/backups`.
|
||||
* The kb → fn rename left some persisted settings pointing at the old path;
|
||||
* we rewrite it on read so existing projects keep working.
|
||||
*/
|
||||
function canonicalizeBackupDir(dir: string | undefined): string | undefined {
|
||||
if (dir === ".kb/backups") return ".fusion/backups";
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the backup command with settings from the project.
|
||||
* This is the main entry point for scheduled backup automation.
|
||||
|
||||
@@ -203,17 +203,21 @@ function compactTaskActivityLog(entries: TaskLogEntry[]): TaskLogEntry[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalizes a settings object by stripping legacy fields that are no longer valid.
|
||||
* Canonicalizes a settings object by stripping legacy fields that are no longer valid
|
||||
* and rewriting legacy path values left over from the kb → fn rename.
|
||||
*/
|
||||
function canonicalizeSettings(settings: Settings): Settings {
|
||||
// Strip legacy globalMaxConcurrent from project settings - this field was
|
||||
// deprecated in favor of the global-level maxConcurrent in concurrency settings.
|
||||
const { globalMaxConcurrent, ...rest } = settings as Settings & { globalMaxConcurrent?: number };
|
||||
if (globalMaxConcurrent !== undefined) {
|
||||
return rest as Settings;
|
||||
}
|
||||
const base = globalMaxConcurrent !== undefined ? (rest as Settings) : settings;
|
||||
|
||||
return settings;
|
||||
// Rewrite legacy .kb/backups → .fusion/backups for projects upgraded from the
|
||||
// old brand so persisted settings keep working. Custom .kb/* paths are left alone.
|
||||
if (base.autoBackupDir === ".kb/backups") {
|
||||
return { ...base, autoBackupDir: ".fusion/backups" };
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
export interface TaskStoreEvents {
|
||||
|
||||
@@ -3013,3 +3013,7 @@ export interface Mailbox {
|
||||
|
||||
// Re-export PROMPT_KEY_CATALOG for backward compatibility with vite alias
|
||||
export { PROMPT_KEY_CATALOG } from "./prompt-overrides.js";
|
||||
|
||||
// Re-exported here so the dashboard's `@fusion/core` → types.ts alias resolves
|
||||
// client-side consumers (see packages/dashboard/vite.config.ts).
|
||||
export { getErrorMessage } from "./error-message.js";
|
||||
|
||||
Reference in New Issue
Block a user