pi-one-ui 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -341,10 +341,7 @@ export type PolishedTuiColors = {
341
341
  workingLineHigh?: ColorSpec;
342
342
  };
343
343
 
344
- /**
345
- * Canonical configuration plus a temporary flat compatibility projection used
346
- * by production consumers while they migrate to `components`.
347
- */
344
+ /** Canonical configuration plus a derived flat runtime view for existing callers. */
348
345
  export type PolishedTuiConfig = ZentuiConfig & {
349
346
  footerFormat: string;
350
347
  responsiveFooter: boolean;
@@ -626,9 +623,7 @@ function parseEditorStyle(value: unknown): EditorStyle {
626
623
  ) {
627
624
  return value;
628
625
  }
629
- if (value === "polished") return "opencode";
630
- if (value === "polished-copy-friendly") return "opencode-copy-friendly";
631
- return defaultConfig.editorStyle;
626
+ return defaultComponents.editor.style;
632
627
  }
633
628
 
634
629
  function parseEditorBorderColorMode(value: unknown): EditorBorderColorMode {
@@ -759,9 +754,9 @@ function normalizeColors(
759
754
  record: Record<string, unknown>,
760
755
  ): Partial<PolishedTuiConfig["colors"]> {
761
756
  return definedColors({
762
- cwd: colorValue(record, "cwd") ?? colorValue(record, "cwdText"),
757
+ cwd: colorValue(record, "cwd"),
763
758
  sessionName: colorValue(record, "sessionName"),
764
- gitBranch: colorValue(record, "gitBranch") ?? colorValue(record, "git"),
759
+ gitBranch: colorValue(record, "gitBranch"),
765
760
  gitStatus: colorValue(record, "gitStatus"),
766
761
  contextNormal: colorValue(record, "contextNormal"),
767
762
  contextWarning: colorValue(record, "contextWarning"),
@@ -962,25 +957,25 @@ function validFooterSegmentEntries(
962
957
  ) as Partial<FooterSegmentsConfig>;
963
958
  }
964
959
 
965
- /**
966
- * Applies one compatibility mutation through the shared config writer.
967
- */
960
+ /** Applies one canonical mutation through the shared config writer. */
968
961
  function mutateConfig(
969
962
  path: string,
970
963
  mutate: (record: ConfigRecord) => void,
971
964
  ): PolishedTuiConfig {
965
+ const update = (record: ConfigRecord): void => {
966
+ record.version = 1;
967
+ mutate(record);
968
+ };
972
969
  const record =
973
970
  path === configPath
974
- ? configStore.update(mutate)
975
- : mutateConfigFile(path, mutate, "Zentui");
971
+ ? configStore.update(update)
972
+ : mutateConfigFile(path, update);
976
973
  return mergeConfig(record);
977
974
  }
978
975
 
979
976
  export function ensureConfigExists(_path = configPath): void {
980
- // Intentionally left as a no-op. Zentui config is user-owned and
981
- // compatibility-sensitive: runtime defaults come from `mergeConfig({})`, and
982
- // the extension should not persist opinionated defaults unless the user
983
- // explicitly changes a setting.
977
+ // Intentionally left as a no-op. Runtime defaults come from `mergeConfig({})`;
978
+ // persist the canonical file only after the user changes a setting.
984
979
  }
985
980
 
986
981
  function hasOwn(record: ConfigRecord, key: string): boolean {
@@ -991,17 +986,6 @@ function recordValue(value: unknown): ConfigRecord {
991
986
  return isRecord(value) ? value : {};
992
987
  }
993
988
 
994
- function resolvedValue(
995
- canonical: ConfigRecord,
996
- canonicalKey: string,
997
- legacy?: ConfigRecord,
998
- legacyKey = canonicalKey,
999
- ): unknown {
1000
- if (hasOwn(canonical, canonicalKey)) return canonical[canonicalKey];
1001
- if (legacy && hasOwn(legacy, legacyKey)) return legacy[legacyKey];
1002
- return undefined;
1003
- }
1004
-
1005
989
  function parseBoolean(value: unknown, fallback: boolean): boolean {
1006
990
  return typeof value === "boolean" ? value : fallback;
1007
991
  }
@@ -1014,10 +998,19 @@ function parseSelectorBorderStyle(value: unknown): SelectorBorderStyle {
1014
998
  return value === "zentui" ? value : "zentui";
1015
999
  }
1016
1000
 
1017
- function parseFooterStyle(value: unknown): FooterStyle | undefined {
1001
+ function parseFooterStyle(value: unknown): FooterStyle {
1018
1002
  return value === "native" || value === "starship" || value === "hidden"
1019
1003
  ? value
1020
- : undefined;
1004
+ : defaultComponents.footer.style;
1005
+ }
1006
+
1007
+ function parseUserMessageStyle(value: unknown): UserMessageStyle {
1008
+ return value === "framed" ||
1009
+ value === "framed-copy-friendly" ||
1010
+ value === "compact" ||
1011
+ value === "labeled"
1012
+ ? value
1013
+ : defaultComponents.userMessages.style;
1021
1014
  }
1022
1015
 
1023
1016
  function parseNonEmptyString(value: unknown, fallback: string): string {
@@ -1025,216 +1018,54 @@ function parseNonEmptyString(value: unknown, fallback: string): string {
1025
1018
  }
1026
1019
 
1027
1020
  function resolveContextThresholds(
1028
- canonical: unknown,
1029
- legacy: unknown,
1021
+ value: unknown,
1030
1022
  defaults: ContextThresholds,
1031
1023
  ): ContextThresholds {
1032
- const canonicalRecord = recordValue(canonical);
1033
- const legacyRecord = recordValue(legacy);
1034
- return parseContextThresholds(
1035
- {
1036
- warning: resolvedValue(canonicalRecord, "warning", legacyRecord),
1037
- error: resolvedValue(canonicalRecord, "error", legacyRecord),
1038
- },
1039
- defaults,
1040
- );
1024
+ return parseContextThresholds(value, defaults);
1041
1025
  }
1042
1026
 
1043
- function resolvePathDisplay(
1044
- canonical: unknown,
1045
- legacy: unknown,
1046
- ): PathDisplayConfig {
1047
- const canonicalRecord = recordValue(canonical);
1048
- const legacyRecord = recordValue(legacy);
1049
- return parsePathDisplay({
1050
- mode: resolvedValue(canonicalRecord, "mode", legacyRecord),
1051
- depth: resolvedValue(canonicalRecord, "depth", legacyRecord),
1052
- });
1027
+ function resolvePathDisplay(value: unknown): PathDisplayConfig {
1028
+ return parsePathDisplay(value);
1053
1029
  }
1054
1030
 
1055
- function resolveGitBranch(
1056
- canonical: unknown,
1057
- legacy: unknown,
1058
- ): GitBranchConfig {
1059
- const canonicalRecord = recordValue(canonical);
1060
- const legacyRecord = recordValue(legacy);
1061
- return parseGitBranchConfig({
1062
- maxLength: resolvedValue(canonicalRecord, "maxLength", legacyRecord),
1063
- });
1031
+ function resolveGitBranch(value: unknown): GitBranchConfig {
1032
+ return parseGitBranchConfig(value);
1064
1033
  }
1065
1034
 
1066
- function resolveGitCommit(
1067
- canonical: unknown,
1068
- legacy: unknown,
1069
- ): GitCommitConfig {
1070
- const canonicalRecord = recordValue(canonical);
1071
- const legacyRecord = recordValue(legacy);
1072
- return normalizeGitCommitConfig({
1073
- hashLength: resolvedValue(canonicalRecord, "hashLength", legacyRecord),
1074
- onlyDetached: resolvedValue(canonicalRecord, "onlyDetached", legacyRecord),
1075
- showTag: resolvedValue(canonicalRecord, "showTag", legacyRecord),
1076
- });
1035
+ function resolveGitCommit(value: unknown): GitCommitConfig {
1036
+ return normalizeGitCommitConfig(recordValue(value));
1077
1037
  }
1078
1038
 
1079
- function resolveGitMetrics(
1080
- canonical: unknown,
1081
- legacy: unknown,
1082
- ): GitMetricsConfig {
1083
- const canonicalRecord = recordValue(canonical);
1084
- const legacyRecord = recordValue(legacy);
1085
- return normalizeGitMetricsConfig({
1086
- onlyNonzero: resolvedValue(canonicalRecord, "onlyNonzero", legacyRecord),
1087
- ignoreSubmodules: resolvedValue(
1088
- canonicalRecord,
1089
- "ignoreSubmodules",
1090
- legacyRecord,
1091
- ),
1092
- });
1039
+ function resolveGitMetrics(value: unknown): GitMetricsConfig {
1040
+ return normalizeGitMetricsConfig(recordValue(value));
1093
1041
  }
1094
1042
 
1095
- function resolveExtensionStatuses(
1096
- canonical: unknown,
1097
- legacy: unknown,
1098
- ): ExtensionStatusesConfig {
1099
- const canonicalRecord = recordValue(canonical);
1100
- const legacyRecord = recordValue(legacy);
1101
- return normalizeExtensionStatuses({
1102
- defaultPlacement: resolvedValue(
1103
- canonicalRecord,
1104
- "defaultPlacement",
1105
- legacyRecord,
1106
- ),
1107
- placements: resolvedValue(canonicalRecord, "placements", legacyRecord),
1108
- colorModes: resolvedValue(canonicalRecord, "colorModes", legacyRecord),
1109
- });
1043
+ function resolveExtensionStatuses(value: unknown): ExtensionStatusesConfig {
1044
+ return normalizeExtensionStatuses(recordValue(value));
1110
1045
  }
1111
1046
 
1112
1047
  const FOOTER_SEGMENT_KEYS = Object.keys(defaultFooterSegments) as Array<
1113
1048
  keyof FooterSegmentsConfig
1114
1049
  >;
1115
1050
 
1116
- function resolveFooterSegments(
1117
- canonical: unknown,
1118
- legacy: unknown,
1119
- ): FooterSegmentsConfig {
1120
- const canonicalRecord = recordValue(canonical);
1121
- const legacyRecord = recordValue(legacy);
1051
+ function resolveFooterSegments(value: unknown): FooterSegmentsConfig {
1052
+ const record = recordValue(value);
1122
1053
  return Object.fromEntries(
1123
1054
  FOOTER_SEGMENT_KEYS.map((key) => [
1124
1055
  key,
1125
- parseBoolean(
1126
- resolvedValue(canonicalRecord, key, legacyRecord),
1127
- defaultFooterSegments[key],
1128
- ),
1056
+ parseBoolean(record[key], defaultFooterSegments[key]),
1129
1057
  ]),
1130
1058
  ) as FooterSegmentsConfig;
1131
1059
  }
1132
1060
 
1133
- function legacyCopyFriendly(record: ConfigRecord): boolean {
1134
- return record.copyFriendly === true;
1135
- }
1136
-
1137
- function resolveEditorStyle(
1138
- editor: ConfigRecord,
1139
- polished: ConfigRecord,
1140
- features: ConfigRecord,
1141
- ): EditorStyle {
1142
- const rawStyle = editor.style;
1143
- if (
1144
- rawStyle === "opencode" ||
1145
- rawStyle === "opencode-copy-friendly" ||
1146
- rawStyle === "accent-rail" ||
1147
- rawStyle === "minimalist"
1148
- ) {
1149
- return rawStyle;
1150
- }
1151
- if (rawStyle === "polished-copy-friendly") return "opencode-copy-friendly";
1152
- if (rawStyle === "polished") {
1153
- return hasOwn(polished, "copyFriendly") && legacyCopyFriendly(polished)
1154
- ? "opencode-copy-friendly"
1155
- : "opencode";
1156
- }
1157
- if (hasOwn(polished, "copyFriendly")) {
1158
- return legacyCopyFriendly(polished) ? "opencode-copy-friendly" : "opencode";
1159
- }
1160
- return legacyCopyFriendly(features) ? "opencode-copy-friendly" : "opencode";
1161
- }
1162
-
1163
- function resolveFooterStyle(
1164
- footer: ConfigRecord,
1165
- features: ConfigRecord,
1166
- ): FooterStyle {
1167
- const explicit = parseFooterStyle(footer.style);
1168
- if (explicit) return explicit;
1169
- if (typeof footer.enabled === "boolean")
1170
- return footer.enabled ? "starship" : "native";
1171
- if (typeof features.statusLine === "boolean") {
1172
- return features.statusLine ? "starship" : "native";
1173
- }
1174
- return defaultComponents.footer.style;
1175
- }
1176
-
1177
- function resolveUserMessagesSelection(
1178
- userMessages: ConfigRecord,
1179
- framed: ConfigRecord,
1180
- features: ConfigRecord,
1181
- ): Pick<UserMessagesComponentConfig, "enabled" | "style"> {
1182
- const normalEnabled = parseBoolean(
1183
- resolvedValue(userMessages, "enabled", features, "editor"),
1184
- defaultComponents.userMessages.enabled,
1185
- );
1186
- const rawStyle = userMessages.style;
1187
- if (
1188
- rawStyle === "compact" ||
1189
- rawStyle === "labeled" ||
1190
- rawStyle === "framed-copy-friendly"
1191
- ) {
1192
- return { style: rawStyle, enabled: normalEnabled };
1193
- }
1194
- if (rawStyle === "framed" || hasOwn(framed, "copyFriendly")) {
1195
- return {
1196
- style: legacyCopyFriendly(framed) ? "framed-copy-friendly" : "framed",
1197
- enabled: normalEnabled,
1198
- };
1199
- }
1200
- return {
1201
- style: legacyCopyFriendly(features) ? "framed-copy-friendly" : "framed",
1202
- enabled: normalEnabled,
1203
- };
1204
- }
1205
-
1206
1061
  function resolveWorkingLineMessages(
1207
1062
  messages: ConfigRecord,
1208
1063
  ): WorkingLineMessagesConfig {
1209
- const preset = () => [...PI_WORKING_LINE_MESSAGES];
1210
- const hasCanonicalCustom = hasOwn(messages, "custom");
1211
- const custom = hasCanonicalCustom
1212
- ? parseBoolean(messages.custom, true)
1213
- : messages.mode !== "native";
1214
- if (hasCanonicalCustom) {
1215
- return {
1216
- custom,
1217
- values: hasOwn(messages, "values")
1218
- ? normalizeWorkingLineMessages(messages.values)
1219
- : preset(),
1220
- };
1221
- }
1222
- const legacyValues = normalizeWorkingLineMessages(messages.values);
1223
- if (messages.mode === "append") {
1224
- return {
1225
- custom,
1226
- values: normalizeWorkingLineMessages([...preset(), ...legacyValues]),
1227
- };
1228
- }
1229
- if (messages.mode === "replace" || messages.mode === "native") {
1230
- return {
1231
- custom,
1232
- values: legacyValues.length > 0 ? legacyValues : preset(),
1233
- };
1234
- }
1235
1064
  return {
1236
- custom,
1237
- values: hasOwn(messages, "values") ? legacyValues : preset(),
1065
+ custom: parseBoolean(messages.custom, true),
1066
+ values: hasOwn(messages, "values")
1067
+ ? normalizeWorkingLineMessages(messages.values)
1068
+ : [...PI_WORKING_LINE_MESSAGES],
1238
1069
  };
1239
1070
  }
1240
1071
 
@@ -1243,18 +1074,12 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1243
1074
  const editor = recordValue(components.editor);
1244
1075
  const editorStyles = recordValue(editor.styles);
1245
1076
  const opencode = recordValue(editorStyles.opencode);
1246
- const polished = recordValue(editorStyles.polished);
1247
1077
  const opencodeCopyFriendly = recordValue(
1248
1078
  editorStyles["opencode-copy-friendly"],
1249
1079
  );
1250
- const polishedCopyFriendly = recordValue(
1251
- editorStyles["polished-copy-friendly"],
1252
- );
1253
1080
  const accentRail = recordValue(editorStyles["accent-rail"]);
1254
1081
  const minimalist = recordValue(editorStyles.minimalist);
1255
1082
  const userMessages = recordValue(components.userMessages);
1256
- const userMessageStyles = recordValue(userMessages.styles);
1257
- const framed = recordValue(userMessageStyles.framed);
1258
1083
  const workingLine = recordValue(components.workingLine);
1259
1084
  const workingLineMessages = recordValue(workingLine.messages);
1260
1085
  const workingLineSegments = recordValue(workingLine.segments);
@@ -1262,82 +1087,35 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1262
1087
  const footer = recordValue(components.footer);
1263
1088
  const footerStyles = recordValue(footer.styles);
1264
1089
  const starship = recordValue(footerStyles.starship);
1265
- const features = recordValue(config.features);
1266
- const colorSources = recordValue(config.colorSources);
1267
-
1268
- const minimalistThresholds = resolveContextThresholds(
1269
- minimalist.contextThresholds,
1270
- config.contextThresholds,
1271
- defaultMinimalistStyle.contextThresholds,
1272
- );
1273
- const footerThresholds = resolveContextThresholds(
1274
- starship.contextThresholds,
1275
- config.contextThresholds,
1276
- defaultStarshipStyle.contextThresholds,
1277
- );
1278
- const compactFormat = resolvedValue(
1279
- starship,
1280
- "compactFormat",
1281
- config,
1282
- "compactFooterFormat",
1283
- );
1284
- const metadataFormat = hasOwn(opencode, "metadataFormat")
1285
- ? opencode.metadataFormat
1286
- : resolvedValue(polished, "metadataFormat", config, "editorMetadataFormat");
1287
- const lowRailMetadataFormat = hasOwn(opencodeCopyFriendly, "metadataFormat")
1288
- ? opencodeCopyFriendly.metadataFormat
1289
- : hasOwn(polishedCopyFriendly, "metadataFormat")
1290
- ? polishedCopyFriendly.metadataFormat
1291
- : metadataFormat;
1292
- const userMessagesSelection = resolveUserMessagesSelection(
1293
- userMessages,
1294
- framed,
1295
- features,
1296
- );
1297
1090
 
1298
1091
  return {
1299
1092
  editor: {
1300
- enabled: parseBoolean(
1301
- resolvedValue(editor, "enabled", features, "editor"),
1302
- defaultComponents.editor.enabled,
1303
- ),
1304
- style: resolveEditorStyle(editor, polished, features),
1093
+ enabled: parseBoolean(editor.enabled, defaultComponents.editor.enabled),
1094
+ style: parseEditorStyle(editor.style),
1305
1095
  colorSource: parseColorSource(
1306
- resolvedValue(editor, "colorSource", colorSources, "editor"),
1096
+ editor.colorSource,
1307
1097
  defaultComponents.editor.colorSource,
1308
1098
  ),
1309
- borderColorMode: parseEditorBorderColorMode(
1310
- resolvedValue(
1311
- editor,
1312
- "borderColorMode",
1313
- config,
1314
- "editorBorderColorMode",
1315
- ),
1316
- ),
1099
+ borderColorMode: parseEditorBorderColorMode(editor.borderColorMode),
1317
1100
  modelLabel: parseEditorModelLabel(
1318
- resolvedValue(editor, "modelLabel", config, "editorModelLabel"),
1101
+ editor.modelLabel,
1319
1102
  defaultComponents.editor.modelLabel,
1320
1103
  ),
1321
1104
  viewportIndicators: parseBoolean(
1322
- resolvedValue(
1323
- editor,
1324
- "viewportIndicators",
1325
- features,
1326
- "viewportIndicators",
1327
- ),
1105
+ editor.viewportIndicators,
1328
1106
  defaultComponents.editor.viewportIndicators,
1329
1107
  ),
1330
1108
  styles: {
1331
1109
  opencode: {
1332
1110
  metadataFormat: parseNonEmptyString(
1333
- metadataFormat,
1111
+ opencode.metadataFormat,
1334
1112
  DEFAULT_EDITOR_METADATA_FORMAT,
1335
1113
  ),
1336
1114
  completionMenu: parseCompletionMenuStyle(opencode.completionMenu),
1337
1115
  },
1338
1116
  "opencode-copy-friendly": {
1339
1117
  metadataFormat: parseNonEmptyString(
1340
- lowRailMetadataFormat,
1118
+ opencodeCopyFriendly.metadataFormat,
1341
1119
  DEFAULT_EDITOR_METADATA_FORMAT,
1342
1120
  ),
1343
1121
  completionMenu: parseCompletionMenuStyle(
@@ -1390,20 +1168,21 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1390
1168
  minimalist.showGit,
1391
1169
  defaultMinimalistStyle.showGit,
1392
1170
  ),
1393
- contextThresholds: minimalistThresholds,
1171
+ contextThresholds: resolveContextThresholds(
1172
+ minimalist.contextThresholds,
1173
+ defaultMinimalistStyle.contextThresholds,
1174
+ ),
1394
1175
  },
1395
1176
  },
1396
1177
  },
1397
1178
  userMessages: {
1398
- enabled: userMessagesSelection.enabled,
1399
- style: userMessagesSelection.style,
1179
+ enabled: parseBoolean(
1180
+ userMessages.enabled,
1181
+ defaultComponents.userMessages.enabled,
1182
+ ),
1183
+ style: parseUserMessageStyle(userMessages.style),
1400
1184
  colorSource: parseColorSource(
1401
- resolvedValue(
1402
- userMessages,
1403
- "colorSource",
1404
- colorSources,
1405
- "userMessages",
1406
- ),
1185
+ userMessages.colorSource,
1407
1186
  defaultComponents.userMessages.colorSource,
1408
1187
  ),
1409
1188
  styles: {
@@ -1431,19 +1210,9 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1431
1210
  ? workingLine.spinner
1432
1211
  : defaultComponents.workingLine.spinner,
1433
1212
  spinnerIntervalMs: isValidWorkingLineIntervalMs(
1434
- resolvedValue(
1435
- workingLine,
1436
- "spinnerIntervalMs",
1437
- workingLine,
1438
- "intervalMs",
1439
- ),
1213
+ workingLine.spinnerIntervalMs,
1440
1214
  )
1441
- ? (resolvedValue(
1442
- workingLine,
1443
- "spinnerIntervalMs",
1444
- workingLine,
1445
- "intervalMs",
1446
- ) as number)
1215
+ ? workingLine.spinnerIntervalMs
1447
1216
  : defaultComponents.workingLine.spinnerIntervalMs,
1448
1217
  animateSpinnerColor: parseBoolean(
1449
1218
  workingLine.animateSpinnerColor,
@@ -1484,74 +1253,53 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1484
1253
  },
1485
1254
  selectorBorders: {
1486
1255
  enabled: parseBoolean(
1487
- resolvedValue(selectorBorders, "enabled", features, "editor"),
1256
+ selectorBorders.enabled,
1488
1257
  defaultComponents.selectorBorders.enabled,
1489
1258
  ),
1490
- style: parseSelectorBorderStyle(resolvedValue(selectorBorders, "style")),
1259
+ style: parseSelectorBorderStyle(selectorBorders.style),
1491
1260
  colorSource: parseColorSource(
1492
- resolvedValue(selectorBorders, "colorSource", colorSources, "editor"),
1261
+ selectorBorders.colorSource,
1493
1262
  defaultComponents.selectorBorders.colorSource,
1494
1263
  ),
1495
1264
  },
1496
1265
  footer: {
1497
- style: resolveFooterStyle(footer, features),
1266
+ style: parseFooterStyle(footer.style),
1498
1267
  colorSource: parseColorSource(
1499
- resolvedValue(footer, "colorSource", colorSources, "starship"),
1268
+ footer.colorSource,
1500
1269
  defaultComponents.footer.colorSource,
1501
1270
  ),
1502
1271
  modelLabel: parseEditorModelLabel(
1503
- resolvedValue(footer, "modelLabel", config, "editorModelLabel"),
1272
+ footer.modelLabel,
1504
1273
  defaultComponents.footer.modelLabel,
1505
1274
  ),
1506
1275
  styles: {
1507
1276
  starship: {
1508
1277
  format:
1509
- typeof resolvedValue(starship, "format", config, "footerFormat") ===
1510
- "string"
1511
- ? (resolvedValue(
1512
- starship,
1513
- "format",
1514
- config,
1515
- "footerFormat",
1516
- ) as string)
1278
+ typeof starship.format === "string"
1279
+ ? starship.format
1517
1280
  : defaultStarshipStyle.format,
1518
1281
  responsive: parseBoolean(
1519
- resolvedValue(starship, "responsive", config, "responsiveFooter"),
1282
+ starship.responsive,
1520
1283
  defaultStarshipStyle.responsive,
1521
1284
  ),
1522
1285
  compactFormat: parseNonEmptyString(
1523
- compactFormat,
1286
+ starship.compactFormat,
1524
1287
  defaultStarshipStyle.compactFormat,
1525
1288
  ),
1526
- compactMaxLines: parseCompactFooterMaxLines(
1527
- resolvedValue(
1528
- starship,
1529
- "compactMaxLines",
1530
- config,
1531
- "compactFooterMaxLines",
1532
- ),
1533
- ),
1534
- separator: parseSeparatorStyle(
1535
- resolvedValue(starship, "separator", config, "separator"),
1289
+ compactMaxLines: parseCompactFooterMaxLines(starship.compactMaxLines),
1290
+ separator: parseSeparatorStyle(starship.separator),
1291
+ contextStyle: parseContextStyle(starship.contextStyle),
1292
+ contextThresholds: resolveContextThresholds(
1293
+ starship.contextThresholds,
1294
+ defaultStarshipStyle.contextThresholds,
1536
1295
  ),
1537
- contextStyle: parseContextStyle(
1538
- resolvedValue(starship, "contextStyle", config, "contextStyle"),
1539
- ),
1540
- contextThresholds: footerThresholds,
1541
- pathDisplay: resolvePathDisplay(
1542
- starship.pathDisplay,
1543
- config.pathDisplay,
1544
- ),
1545
- segments: resolveFooterSegments(
1546
- starship.segments,
1547
- config.footerSegments,
1548
- ),
1549
- gitBranch: resolveGitBranch(starship.gitBranch, config.gitBranch),
1550
- gitCommit: resolveGitCommit(starship.gitCommit, config.gitCommit),
1551
- gitMetrics: resolveGitMetrics(starship.gitMetrics, config.gitMetrics),
1296
+ pathDisplay: resolvePathDisplay(starship.pathDisplay),
1297
+ segments: resolveFooterSegments(starship.segments),
1298
+ gitBranch: resolveGitBranch(starship.gitBranch),
1299
+ gitCommit: resolveGitCommit(starship.gitCommit),
1300
+ gitMetrics: resolveGitMetrics(starship.gitMetrics),
1552
1301
  extensionStatuses: resolveExtensionStatuses(
1553
1302
  starship.extensionStatuses,
1554
- config.extensionStatuses,
1555
1303
  ),
1556
1304
  },
1557
1305
  },
@@ -1559,7 +1307,7 @@ function resolveComponents(config: ConfigRecord): ComponentsConfig {
1559
1307
  };
1560
1308
  }
1561
1309
 
1562
- function compatibilityView(config: ZentuiConfig): PolishedTuiConfig {
1310
+ function derivedRuntimeView(config: ZentuiConfig): PolishedTuiConfig {
1563
1311
  const starship = config.components.footer.styles.starship;
1564
1312
  const minimalist = config.components.editor.styles.minimalist;
1565
1313
  return {
@@ -1610,8 +1358,6 @@ const knownComponentStyleIds: Record<
1610
1358
  "opencode-copy-friendly",
1611
1359
  "accent-rail",
1612
1360
  "minimalist",
1613
- "polished",
1614
- "polished-copy-friendly",
1615
1361
  ]),
1616
1362
  userMessages: new Set([
1617
1363
  "framed",
@@ -1660,13 +1406,10 @@ export function mergeConfig(parsed: unknown): PolishedTuiConfig {
1660
1406
  colors: {
1661
1407
  ...defaultConfig.colors,
1662
1408
  ...colors,
1663
- ...(colors.editorGitBranch === undefined && colors.gitBranch !== undefined
1664
- ? { editorGitBranch: colors.gitBranch }
1665
- : {}),
1666
1409
  },
1667
1410
  components: resolveComponents(config),
1668
1411
  };
1669
- const view = compatibilityView(canonical);
1412
+ const view = derivedRuntimeView(canonical);
1670
1413
  const unsupported = new Set<ComponentStyleOwner>();
1671
1414
  for (const owner of [
1672
1415
  "editor",
@@ -1765,7 +1508,6 @@ function restoreUnknownSelectedStyleIds(
1765
1508
  function saveComponentsMutation(
1766
1509
  update: (components: ComponentsConfig) => void,
1767
1510
  path: string,
1768
- cleanupRaw?: (record: ConfigRecord) => void,
1769
1511
  replacedStyle?: ComponentStyleOwner,
1770
1512
  ): PolishedTuiConfig {
1771
1513
  return mutateConfig(path, (record) => {
@@ -1775,39 +1517,9 @@ function saveComponentsMutation(
1775
1517
  const normalized = resolveComponents({ components });
1776
1518
  record.components = overlayKnown(record.components, normalized);
1777
1519
  restoreUnknownSelectedStyleIds(record, preservedStyles, replacedStyle);
1778
- cleanupRaw?.(record);
1779
1520
  });
1780
1521
  }
1781
1522
 
1782
- function deleteLegacyEditorCopyFriendly(record: ConfigRecord): void {
1783
- const components = record.components;
1784
- if (!isRecord(components)) return;
1785
- const editor = components.editor;
1786
- if (!isRecord(editor)) return;
1787
- const styles = editor.styles;
1788
- if (!isRecord(styles)) return;
1789
- const polished = styles.polished;
1790
- if (isRecord(polished)) delete polished.copyFriendly;
1791
- }
1792
-
1793
- function deleteLegacyFooterEnabled(record: ConfigRecord): void {
1794
- const components = record.components;
1795
- if (!isRecord(components)) return;
1796
- const footer = components.footer;
1797
- if (isRecord(footer)) delete footer.enabled;
1798
- }
1799
-
1800
- function deleteLegacyMessageCopyFriendly(record: ConfigRecord): void {
1801
- const components = record.components;
1802
- if (!isRecord(components)) return;
1803
- const userMessages = components.userMessages;
1804
- if (!isRecord(userMessages)) return;
1805
- const styles = userMessages.styles;
1806
- if (!isRecord(styles)) return;
1807
- const framed = styles.framed;
1808
- if (isRecord(framed)) delete framed.copyFriendly;
1809
- }
1810
-
1811
1523
  function applyEditorComponentPatch(
1812
1524
  component: EditorComponentConfig,
1813
1525
  patch: Partial<
@@ -1851,7 +1563,6 @@ export function saveEditorComponentPatch(
1851
1563
  return saveComponentsMutation(
1852
1564
  (components) => applyEditorComponentPatch(components.editor, patch),
1853
1565
  path,
1854
- patch.style !== undefined ? deleteLegacyEditorCopyFriendly : undefined,
1855
1566
  patch.style !== undefined ? "editor" : undefined,
1856
1567
  );
1857
1568
  }
@@ -1941,7 +1652,6 @@ export function saveUserMessagesComponentPatch(
1941
1652
  component.colorSource = patch.colorSource;
1942
1653
  },
1943
1654
  path,
1944
- patch.style !== undefined ? deleteLegacyMessageCopyFriendly : undefined,
1945
1655
  patch.style !== undefined ? "userMessages" : undefined,
1946
1656
  );
1947
1657
  }
@@ -1950,49 +1660,38 @@ export function saveWorkingLineComponentPatch(
1950
1660
  patch: WorkingLineComponentPatch,
1951
1661
  path = configPath,
1952
1662
  ): PolishedTuiConfig {
1953
- return saveComponentsMutation(
1954
- (components) => {
1955
- const component = components.workingLine;
1956
- if (patch.enabled !== undefined) component.enabled = patch.enabled;
1957
- if (patch.turnSummary !== undefined)
1958
- component.turnSummary = patch.turnSummary;
1959
- if (patch.spinner !== undefined) component.spinner = patch.spinner;
1960
- if (patch.spinnerIntervalMs !== undefined)
1961
- component.spinnerIntervalMs = patch.spinnerIntervalMs;
1962
- if (patch.animateSpinnerColor !== undefined)
1963
- component.animateSpinnerColor = patch.animateSpinnerColor;
1964
- if (patch.textIntervalMs !== undefined)
1965
- component.textIntervalMs = patch.textIntervalMs;
1966
- if (patch.textAnimation !== undefined)
1967
- component.textAnimation = patch.textAnimation;
1968
- if (patch.colorSource !== undefined)
1969
- component.colorSource = patch.colorSource;
1970
- if (patch.messages?.custom !== undefined)
1971
- component.messages.custom = patch.messages.custom;
1972
- if (patch.messages?.values !== undefined) {
1973
- component.messages.values = normalizeWorkingLineMessages([
1974
- ...patch.messages.values,
1975
- ]);
1976
- }
1977
- if (patch.segments?.tool !== undefined)
1978
- component.segments.tool = patch.segments.tool;
1979
- if (patch.segments?.elapsed !== undefined)
1980
- component.segments.elapsed = patch.segments.elapsed;
1981
- if (patch.segments?.thought !== undefined)
1982
- component.segments.thought = patch.segments.thought;
1983
- if (patch.segments?.tokens !== undefined)
1984
- component.segments.tokens = patch.segments.tokens;
1985
- },
1986
- path,
1987
- (record) => {
1988
- const workingLine = recordValue(
1989
- recordValue(record.components).workingLine,
1990
- );
1991
- delete workingLine.intervalMs;
1992
- const messages = recordValue(workingLine.messages);
1993
- delete messages.mode;
1994
- },
1995
- );
1663
+ return saveComponentsMutation((components) => {
1664
+ const component = components.workingLine;
1665
+ if (patch.enabled !== undefined) component.enabled = patch.enabled;
1666
+ if (patch.turnSummary !== undefined)
1667
+ component.turnSummary = patch.turnSummary;
1668
+ if (patch.spinner !== undefined) component.spinner = patch.spinner;
1669
+ if (patch.spinnerIntervalMs !== undefined)
1670
+ component.spinnerIntervalMs = patch.spinnerIntervalMs;
1671
+ if (patch.animateSpinnerColor !== undefined)
1672
+ component.animateSpinnerColor = patch.animateSpinnerColor;
1673
+ if (patch.textIntervalMs !== undefined)
1674
+ component.textIntervalMs = patch.textIntervalMs;
1675
+ if (patch.textAnimation !== undefined)
1676
+ component.textAnimation = patch.textAnimation;
1677
+ if (patch.colorSource !== undefined)
1678
+ component.colorSource = patch.colorSource;
1679
+ if (patch.messages?.custom !== undefined)
1680
+ component.messages.custom = patch.messages.custom;
1681
+ if (patch.messages?.values !== undefined) {
1682
+ component.messages.values = normalizeWorkingLineMessages([
1683
+ ...patch.messages.values,
1684
+ ]);
1685
+ }
1686
+ if (patch.segments?.tool !== undefined)
1687
+ component.segments.tool = patch.segments.tool;
1688
+ if (patch.segments?.elapsed !== undefined)
1689
+ component.segments.elapsed = patch.segments.elapsed;
1690
+ if (patch.segments?.thought !== undefined)
1691
+ component.segments.thought = patch.segments.thought;
1692
+ if (patch.segments?.tokens !== undefined)
1693
+ component.segments.tokens = patch.segments.tokens;
1694
+ }, path);
1996
1695
  }
1997
1696
 
1998
1697
  export function saveSelectorBordersComponentPatch(
@@ -2008,7 +1707,6 @@ export function saveSelectorBordersComponentPatch(
2008
1707
  component.colorSource = patch.colorSource;
2009
1708
  },
2010
1709
  path,
2011
- undefined,
2012
1710
  patch.style !== undefined ? "selectorBorders" : undefined,
2013
1711
  );
2014
1712
  }
@@ -2029,7 +1727,6 @@ export function saveFooterComponentPatch(
2029
1727
  component.modelLabel = patch.modelLabel;
2030
1728
  },
2031
1729
  path,
2032
- patch.style !== undefined ? deleteLegacyFooterEnabled : undefined,
2033
1730
  patch.style !== undefined ? "footer" : undefined,
2034
1731
  );
2035
1732
  }
@@ -2128,7 +1825,6 @@ export function saveUiFeaturesPatch(
2128
1825
  }
2129
1826
  },
2130
1827
  path,
2131
- valid.statusLine !== undefined ? deleteLegacyFooterEnabled : undefined,
2132
1828
  valid.statusLine !== undefined ? "footer" : undefined,
2133
1829
  );
2134
1830
  }