fix(prefs): break parse/serialize cycle for empty arrays and objects

The preferences parser treated [] and {} as strings instead of empty
array/object. On next serialize, yamlSafeString quoted them as "[]"
and "{}", permanently corrupting the preferences file. This caused
the wizard to show empty fields (models, auto_supervisor, etc.).

Fix: parseScalar now recognizes [] and {} (quoted or unquoted) as
empty array/object. Serializer omits empty values entirely instead
of writing key: [] or key: {}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
deseltrus 2026-03-15 07:19:09 +01:00
parent 5377cfad50
commit be2492b48d
2 changed files with 8 additions and 6 deletions

View file

@ -448,8 +448,7 @@ function serializePreferencesToFrontmatter(prefs: Record<string, unknown>): stri
if (Array.isArray(value)) {
if (value.length === 0) {
lines.push(`${prefix}${key}: []`);
return;
return; // Omit empty arrays — avoids parse/serialize cycle bug with "[]" strings
}
lines.push(`${prefix}${key}:`);
for (const item of value) {
@ -480,8 +479,7 @@ function serializePreferencesToFrontmatter(prefs: Record<string, unknown>): stri
if (typeof value === "object") {
const entries = Object.entries(value as Record<string, unknown>);
if (entries.length === 0) {
lines.push(`${prefix}${key}: {}`);
return;
return; // Omit empty objects — avoids parse/serialize cycle bug with "{}" strings
}
lines.push(`${prefix}${key}:`);
for (const [k, v] of entries) {

View file

@ -482,16 +482,20 @@ function parseFrontmatterBlock(frontmatter: string): GSDPreferences {
return root as GSDPreferences;
}
function parseScalar(value: string): string | number | boolean {
function parseScalar(value: string): unknown {
if (value === "true") return true;
if (value === "false") return false;
// Recognize empty array/object literals (with or without surrounding quotes)
const unquoted = value.replace(/^['\"]|['\"]$/g, "");
if (unquoted === "[]") return [];
if (unquoted === "{}") return {};
if (/^-?\d+$/.test(value)) {
const n = Number(value);
// Keep large integers (e.g. Discord channel IDs) as strings to avoid precision loss
if (Number.isSafeInteger(n)) return n;
return value;
}
return value.replace(/^['\"]|['\"]$/g, "");
return unquoted;
}
/**