feat(coding-agent): migrated settings and models to models.yml
- Settings now stored in ~/.omp/agent/config.yaml instead of agent.db - Models config now supports models.yaml (preferred) alongside models.json - Auto-migration from agent.db settings and models.json on first run - AgentStorage.saveSettings() deprecated (getSettings() kept for migration) - storage-migration.ts now only handles auth.json migration
This commit is contained in:
@@ -116,8 +116,6 @@ export class AgentStorage {
|
||||
private static instances = new Map<string, AgentStorage>();
|
||||
|
||||
private listSettingsStmt: Statement;
|
||||
private insertSettingStmt: Statement;
|
||||
private deleteSettingsStmt: Statement;
|
||||
private getCacheStmt: Statement;
|
||||
private upsertCacheStmt: Statement;
|
||||
private deleteExpiredCacheStmt: Statement;
|
||||
@@ -137,10 +135,6 @@ export class AgentStorage {
|
||||
this.hardenPermissions(dbPath);
|
||||
|
||||
this.listSettingsStmt = this.db.prepare("SELECT key, value FROM settings");
|
||||
this.insertSettingStmt = this.db.prepare(
|
||||
"INSERT INTO settings (key, value, updated_at) VALUES (?, ?, unixepoch())",
|
||||
);
|
||||
this.deleteSettingsStmt = this.db.prepare("DELETE FROM settings");
|
||||
|
||||
this.getCacheStmt = this.db.prepare("SELECT value FROM cache WHERE key = ? AND expires_at > unixepoch()");
|
||||
this.upsertCacheStmt = this.db.prepare(
|
||||
@@ -276,8 +270,11 @@ CREATE TABLE settings (
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all settings from storage.
|
||||
* Retrieves all settings from storage (legacy, for migration only).
|
||||
* Settings are now stored in config.yml. This method is only used
|
||||
* during migration from agent.db to config.yml.
|
||||
* @returns Settings object, or null if no settings are stored
|
||||
* @deprecated Use config.yml instead. This is only for migration.
|
||||
*/
|
||||
getSettings(): Settings | null {
|
||||
const rows = (this.listSettingsStmt.all() as SettingsRow[]) ?? [];
|
||||
@@ -297,26 +294,13 @@ CREATE TABLE settings (
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically replaces all settings in storage.
|
||||
* Uses delete-then-insert within a transaction for consistency.
|
||||
* @param settings - Settings object to persist
|
||||
* @deprecated Settings are now stored in config.yml, not agent.db.
|
||||
* This method is kept for backward compatibility but does nothing.
|
||||
*/
|
||||
saveSettings(settings: Settings): void {
|
||||
const entries = Object.entries(settings).filter(([, value]) => value !== undefined);
|
||||
const replace = this.db.transaction((rows: Array<[string, unknown]>) => {
|
||||
this.deleteSettingsStmt.run();
|
||||
for (const [key, value] of rows) {
|
||||
const serialized = JSON.stringify(value);
|
||||
if (serialized === undefined) continue;
|
||||
this.insertSettingStmt.run(key, serialized);
|
||||
}
|
||||
logger.warn("AgentStorage.saveSettings is deprecated - settings are now stored in config.yml", {
|
||||
keys: Object.keys(settings),
|
||||
});
|
||||
|
||||
try {
|
||||
replace(entries);
|
||||
} catch (error) {
|
||||
logger.error("AgentStorage failed to save settings", { error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/**
|
||||
* Migrates legacy JSON storage (settings.json, auth.json) to SQLite-based agent.db.
|
||||
* Settings migrate only when the DB has no settings; auth merges per-provider when missing.
|
||||
* Migrates legacy auth.json to SQLite-based agent.db.
|
||||
* Auth credentials merge per-provider when missing.
|
||||
* Original JSON files are backed up to .bak and removed after successful migration.
|
||||
*
|
||||
* NOTE: Settings migration is now handled by SettingsManager.migrateToYaml(),
|
||||
* which migrates from both settings.json and agent.db to config.yaml.
|
||||
*/
|
||||
|
||||
import { logger } from "@oh-my-pi/pi-utils";
|
||||
import { getAgentDbPath } from "$c/config";
|
||||
import type { Settings } from "$c/config/settings-manager";
|
||||
import { AgentStorage } from "./agent-storage";
|
||||
import type { AuthCredential, AuthCredentialEntry, AuthStorageData } from "./auth-storage";
|
||||
|
||||
@@ -14,7 +16,7 @@ import type { AuthCredential, AuthCredentialEntry, AuthStorageData } from "./aut
|
||||
type MigrationPaths = {
|
||||
/** Directory containing agent.db */
|
||||
agentDir: string;
|
||||
/** Path to legacy settings.json file */
|
||||
/** Path to legacy settings.json file (kept for API compatibility, no longer used) */
|
||||
settingsPath: string;
|
||||
/** Candidate paths to search for auth.json (checked in order) */
|
||||
authPaths: string[];
|
||||
@@ -22,7 +24,7 @@ type MigrationPaths = {
|
||||
|
||||
/** Result of the JSON-to-SQLite storage migration. */
|
||||
export interface StorageMigrationResult {
|
||||
/** Whether settings.json was migrated to agent.db */
|
||||
/** Whether settings.json was migrated (always false - settings migration is handled elsewhere) */
|
||||
migratedSettings: boolean;
|
||||
/** Whether auth.json was migrated to agent.db */
|
||||
migratedAuth: boolean;
|
||||
@@ -39,20 +41,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return !!value && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms legacy settings to current schema (e.g., queueMode -> steeringMode).
|
||||
* @param settings - Settings object potentially containing deprecated keys
|
||||
* @returns Settings with deprecated keys renamed to current equivalents
|
||||
*/
|
||||
function migrateLegacySettings(settings: Settings): Settings {
|
||||
const migrated = { ...settings } as Record<string, unknown>;
|
||||
if ("queueMode" in migrated && !("steeringMode" in migrated)) {
|
||||
migrated.steeringMode = migrated.queueMode;
|
||||
delete migrated.queueMode;
|
||||
}
|
||||
return migrated as Settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes credential entries to array format (legacy stored single credentials).
|
||||
* @param entry - Single credential or array of credentials
|
||||
@@ -99,32 +87,6 @@ async function backupJson(path: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates settings.json to SQLite storage if DB is empty.
|
||||
* @param storage - AgentStorage instance to migrate into
|
||||
* @param settingsPath - Path to legacy settings.json
|
||||
* @param warnings - Array to collect non-fatal warnings
|
||||
* @returns True if migration was performed
|
||||
*/
|
||||
async function migrateSettings(storage: AgentStorage, settingsPath: string, warnings: string[]): Promise<boolean> {
|
||||
const settingsFile = Bun.file(settingsPath);
|
||||
const settingsExists = await settingsFile.exists();
|
||||
const hasDbSettings = storage.getSettings() !== null;
|
||||
|
||||
if (!settingsExists) return false;
|
||||
if (hasDbSettings) {
|
||||
warnings.push(`settings.json exists but agent.db is authoritative: ${settingsPath}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const settingsJson = await readJsonFile<Settings>(settingsPath);
|
||||
if (!settingsJson) return false;
|
||||
|
||||
storage.saveSettings(migrateLegacySettings(settingsJson));
|
||||
await backupJson(settingsPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first valid auth.json from candidate paths (checked in priority order).
|
||||
* @param authPaths - Candidate paths to search (e.g., project-local before global)
|
||||
@@ -191,8 +153,8 @@ async function migrateAuth(storage: AgentStorage, authPaths: string[], warnings:
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates legacy JSON files (settings.json, auth.json) to SQLite-based agent.db.
|
||||
* Settings migrate only when the DB has no settings; auth merges per-provider when missing.
|
||||
* Migrates legacy auth.json to SQLite-based agent.db.
|
||||
* Settings migration is handled separately by SettingsManager.migrateToYaml().
|
||||
* @param paths - Configuration specifying locations of legacy files and target DB
|
||||
* @returns Result indicating what was migrated and any warnings encountered
|
||||
*/
|
||||
@@ -200,10 +162,7 @@ export async function migrateJsonStorage(paths: MigrationPaths): Promise<Storage
|
||||
const storage = AgentStorage.open(getAgentDbPath(paths.agentDir));
|
||||
const warnings: string[] = [];
|
||||
|
||||
const [migratedSettings, migratedAuth] = await Promise.all([
|
||||
migrateSettings(storage, paths.settingsPath, warnings),
|
||||
migrateAuth(storage, paths.authPaths, warnings),
|
||||
]);
|
||||
const migratedAuth = await migrateAuth(storage, paths.authPaths, warnings);
|
||||
|
||||
if (warnings.length > 0) {
|
||||
for (const warning of warnings) {
|
||||
@@ -211,5 +170,5 @@ export async function migrateJsonStorage(paths: MigrationPaths): Promise<Storage
|
||||
}
|
||||
}
|
||||
|
||||
return { migratedSettings, migratedAuth, warnings };
|
||||
return { migratedSettings: false, migratedAuth, warnings };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user