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:
gsxdsm
2026-04-23 19:22:50 -07:00
parent 4101af8547
commit 9113f51f69
3 changed files with 29 additions and 10 deletions

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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";