@narumitw/pi-statusline 0.50.0 → 0.50.2

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.
package/README.md CHANGED
@@ -88,17 +88,15 @@ The `tools` segment takes no space while idle.
88
88
 
89
89
  | Command | Purpose |
90
90
  | --- | --- |
91
- | `/statusline` | Open Appearance, Information, Advanced, Status, and Help |
92
- | `/statusline settings` | Open the JSON editor in TUI mode |
93
- | `/statusline status` | Show the effective settings and diagnostics |
94
- | `/statusline help` | Show command and schema guidance |
95
-
96
- The direct `settings`, `status`, and `help` routes remain for compatibility.
97
- The main menu is TUI-only; Escape returns from Advanced or closes the menu.
98
- RPC receives notifications instead of TUI-only controls.
91
+ | `/statusline` | Customize footer appearance, information density, and layout. |
92
+ | `/statusline settings` | Edit the settings JSON. |
93
+ | `/statusline status` | Show effective settings and diagnostics. |
94
+ | `/statusline help` | Show command and schema guidance. |
95
+
96
+ The menu and editor require TUI; RPC receives notifications instead, including the manual settings path for `settings`.
97
+ Status and help support TUI and RPC; print and JSON modes produce no command output.
99
98
  Unknown subcommands and trailing arguments are rejected.
100
- The standard palette picker owns navigation and cleanup; pi-statusline owns footer previews, settings, and rollback.
101
- The width-aware layout editor and JSON editor remain specialized UI.
99
+ Palette previews save on Enter and revert on Escape, but layout changes save immediately and are not undone by closing the editor; see the [configuration guide](./docs/configuration.md).
102
100
 
103
101
  ## 📐 Runtime behavior
104
102
 
@@ -136,7 +134,7 @@ If the last remaining segment is itself wider than the row, that row renders emp
136
134
  - `context` renders one-decimal current usage and the model window, such as `2.4%/272k`.
137
135
  After compaction it can temporarily render `?/272k` until the next valid assistant response.
138
136
  - `tokens`, `cache`, and `cost` total every usage-bearing session entry, matching Pi's native footer.
139
- This includes assistant messages, nested-LLM tool results, compactions, and branch summaries, including abandoned branches retained in the session.
137
+ This includes assistant messages, nested-LLM tool results, compactions, branch summaries, and persisted cache-warming usage, including abandoned branches retained in the session.
140
138
  - Cache tokens are `R<read>`, `W<write>`, and `CH<rate>`.
141
139
  `R` and `W` are cumulative; `CH` uses only the latest assistant prompt: `cacheRead / (input + cacheRead + cacheWrite) * 100`.
142
140
  - Subscription-backed OAuth models and `kimi-coding` append `(sub)` to cost.
@@ -145,188 +143,28 @@ If the last remaining segment is itself wider than the row, that row renders emp
145
143
 
146
144
  ## ⚙️ Settings
147
145
 
148
- The extension uses one user-level file:
149
-
150
- ```text
151
- <getAgentDir()>/pi-statusline.json
152
- ```
153
-
154
- There are no project or environment overrides.
155
- When the file is absent, pi-statusline uses built-in defaults without creating the file or its parent directory.
156
- The first successful settings save creates a complete editable document atomically.
157
- Malformed or unreadable settings are never overwritten.
158
- Settings reload on startup, `/reload`, and session replacement.
159
-
160
- A valid legacy `pi-statusline-settings.json` remains readable with a warning and is never modified automatically; rename it to `pi-statusline.json`.
161
- If both files exist, `pi-statusline.json` wins.
162
-
163
- ### Settings reference
146
+ Use `/statusline` for appearance and information presets, or **Advanced → Edit settings JSON** (`/statusline settings`) for a custom document.
147
+ The only settings file is `<getAgentDir()>/pi-statusline.json`; there are no project or environment overrides.
164
148
 
165
- | Field | Accepted values | Purpose |
166
- | --- | --- | --- |
167
- | `palettePreset` | `tokyo-night`, `ocean`, `sunset`, `forest`, `candy`, `neon`, `mono`, `custom` | Select the active color preset |
168
- | `palette` | Per-segment `fg`/`bg` `#RRGGBB` colors | Define colors used by `custom` |
169
- | `density` | `compact`, `cozy` | Control horizontal padding |
170
- | `separator` | `none`, `dot`, `bar`, `powerline`, `round` | Separate adjacent segments in one color block |
171
- | `segments` | Ordered unique segment names and `line_break` | Control visibility, order, and rows |
172
- | `segmentText` | Per-segment `prefix` and `suffix`; model truncation fields | Format Pi-owned dynamic values |
173
- | `extensionStatusIcons` | Raw status key or `namespace:*` to icon string | Customize extension status icons |
174
-
175
- All fields are optional in an existing document.
176
- Missing fields use defaults.
177
- Menu saves warn about and preserve unknown fields.
178
- Invalid recognized values block saving and leave the file and live footer unchanged.
179
-
180
- A compact customization example:
149
+ A minimal customization selects a palette and a few segments:
181
150
 
182
151
  ```json
183
152
  {
184
153
  "palettePreset": "ocean",
185
- "density": "compact",
186
- "separator": "dot",
187
- "segments": ["model", "thinking", "cwd", "branch", "context", "cache", "cost"],
188
- "segmentText": {
189
- "model": {
190
- "truncationLength": 40,
191
- "truncationSymbol": "…",
192
- "truncationDirection": "middle"
193
- },
194
- "context": { "prefix": "ctx ", "suffix": "" }
195
- },
196
- "extensionStatusIcons": {
197
- "goal": "◎",
198
- "foo:*": "🧪"
199
- }
200
- }
201
- ```
202
-
203
- Use **Advanced → Edit settings JSON** or `/statusline settings` to edit, validate, atomically save, and apply the file.
204
-
205
- ## 🎨 Appearance
206
-
207
- Named palettes provide contrast-checked color ramps.
208
- Appearance previews update while the picker moves, but save only when Enter is pressed; Escape restores the saved palette.
209
-
210
- When `palettePreset` is `custom`, `palette` maps segment names to foreground/background colors:
211
-
212
- ```json
213
- {
214
- "palettePreset": "custom",
215
- "palette": {
216
- "model": { "fg": "#090c0c", "bg": "#a3aed2" },
217
- "context": { "fg": "#c0caf5", "bg": "#1d2230" }
218
- }
219
- }
220
- ```
221
-
222
- - Selecting `custom` without a palette copies the active named preset as a starting point.
223
- - A manually authored `"palettePreset": "custom"` without `palette` uses Tokyo Night colors.
224
- - Named presets ignore but preserve an existing custom palette.
225
- - A `palette` object without `palettePreset` selects `custom`.
226
- - Legacy string palettes such as `"palette": "ocean"` remain accepted.
227
- - Missing custom colors remain unstyled instead of inheriting Tokyo Night.
228
- - Adjacent segments with identical colors share one block; transitions use ``.
229
- - Hex palette colors render as ANSI-256 when Pi's effective terminal capabilities disable true color.
230
-
231
- `segmentText` values must be single-line text without terminal control characters.
232
- Use `line_break` for another row rather than inserting a newline into a prefix or suffix.
233
-
234
- ### Model truncation
235
-
236
- Long model IDs are truncated out of the box so the balanced footer can retain useful model context:
237
-
238
- ```json
239
- {
240
- "segmentText": {
241
- "model": {
242
- "truncationLength": 36,
243
- "truncationSymbol": "…",
244
- "truncationDirection": "start"
245
- }
246
- }
154
+ "segments": ["model", "cwd", "branch", "context"]
247
155
  }
248
156
  ```
249
157
 
250
- `truncationLength` counts model grapheme clusters retained before the symbol.
251
- The built-in value is `36`; set it to `0` to display the complete ID.
252
- The direction names the removed portion:
253
-
254
- - `start` retains the suffix and is the default, which is useful for long llama.cpp paths and model variants.
255
- - `middle` retains both ends.
256
- - `end` retains the prefix.
257
-
258
- Truncation runs after the built-in Claude/GPT shortening rules but before the configured model prefix and suffix.
259
- It changes display only—the provider model ID is untouched.
260
- Terminal control sequences in model IDs are removed at render time, and unsafe configured symbols are rejected.
261
- An empty `truncationSymbol` truncates without a marker.
262
- pi-statusline treats model IDs as opaque strings and does not parse paths, repositories, GGUF suffixes, or quantization names.
263
- At very narrow widths, the existing responsive priorities may still omit the model rather than overflow the terminal.
158
+ A missing file uses the balanced built-in footer without creating the file or its parent directory.
159
+ The first successful save creates an editable document atomically.
160
+ Menu saves preserve unknown fields; invalid recognized values block saving and keep the live footer unchanged.
161
+ Malformed or unreadable files are never overwritten.
162
+ Manual edits load at startup, `/reload`, or session replacement.
264
163
 
265
- ## 🧩 Advanced layout
266
-
267
- Open **Advanced → Custom layout** when the curated levels are not enough.
268
-
269
- | Key | Action |
270
- | --- | --- |
271
- | Up/Down | Navigate |
272
- | Page Up/Page Down | Move by one viewport |
273
- | Enter/Space | Show or hide the selected segment |
274
- | `M` | Enter or leave Move mode |
275
- | Up/Down in Move mode | Reorder the selected visible segment |
276
- | `Alt+Up` / `Alt+Down` | Reorder without entering Move mode |
277
- | `B` | Add or remove a line break after the selected segment |
278
- | Configured Back key (Escape by default) | Leave Move mode first, then close the screen |
279
- | Ctrl+C | Close the screen immediately, including from Move mode |
280
-
281
- The layout displays the effective Back key and keeps Ctrl+C available when Back is remapped.
282
- Every successful change saves and applies immediately.
283
- Closing the screen does not roll it back.
284
-
285
- Available data segments:
286
-
287
- ```text
288
- brand provider model thinking cwd branch tools context tokens cache cost time turn
289
- ```
290
-
291
- Data segments must be unique.
292
- `line_break` may repeat when data segments separate occurrences, but consecutive breaks are invalid.
293
- It has no `segmentText` entry.
294
- The menu cleans up leading, trailing, and newly consecutive breaks after visibility changes.
295
- Manually authored leading/trailing breaks represent empty rows.
296
-
297
- ```json
298
- {
299
- "segments": ["model", "line_break", "cwd", "branch", "context"]
300
- }
301
- ```
302
-
303
- An empty `segments` array hides the main powerline while extension statuses can still render.
304
-
305
- ## 🔌 Extension statuses and icons
306
-
307
- Other extension statuses appear below the main powerline, wrap to terminal width, and are limited to five items.
308
- Icons use this order:
309
-
310
- 1. Exact configured raw key, such as `goal` or `foo:server`.
311
- 2. Longest configured colon wildcard, such as `foo:*` or `foo:server:*`.
312
- 3. Unambiguous installed-package alias, such as `@vendor/pi-foo`, `pi-foo`, or `foo`.
313
- 4. Leading emoji supplied by the status text.
314
- 5. Built-in icon.
315
- 6. Generic `🔌` fallback.
316
-
317
- Set an icon to `""` to hide only the icon.
318
- Wildcards match colon namespaces, not slash-delimited keys.
319
- Configure slash keys exactly.
320
- Compatibility fallbacks retain `codex-usage`, `pisync`, and `unknown-error-retry`; an explicit canonical key wins.
321
-
322
- For interoperable extensions, prefer one aggregated key or a stable coexistence slot:
323
-
324
- ```text
325
- <extension-id>
326
- <extension-id>:<stable-slot>
327
- ```
164
+ Appearance previews save only on Enter, while Escape restores the saved palette.
165
+ Custom-layout changes save immediately, so closing that screen does not undo them.
328
166
 
329
- Put transient activity in the value, and clear the exact key that was set.
167
+ Read the [configuration reference](./docs/configuration.md) for all settings, palettes, model truncation, multiline layouts, effective layout controls, extension-status icon precedence, and legacy-file handling.
330
168
 
331
169
  ## 🚧 Limitations
332
170
 
@@ -345,34 +183,16 @@ Put transient activity in the value, and clear the exact key that was set.
345
183
 
346
184
  ```text
347
185
  packages/pi-statusline/
348
- ├── dist/ # generated split TypeScript runtime loaded by Jiti
349
- ├── scripts/
350
- │ └── build-runtime.mjs # deterministic runtime bundler and eager-boundary validator
351
- ├── src/
352
- │ ├── index.ts # thin entrypoint forwarding to the source runtime
353
- │ ├── statusline.ts # authoritative lifecycle implementation
354
- │ ├── command-contract.ts
355
- │ ├── render.ts
356
- │ ├── directory.ts
357
- │ ├── usage.ts
358
- │ ├── powerline.ts
359
- │ ├── information-profiles.ts
360
- │ ├── commands.ts
361
- │ ├── settings.ts
362
- │ ├── extension-status.ts
363
- │ ├── git-status.ts
364
- │ ├── ansi.ts
365
- │ ├── types.ts
366
- │ └── presets/
367
- ├── test/
368
- ├── README.md
369
- ├── LICENSE
370
- ├── tsconfig.json
371
- └── package.json
186
+ ├── src/ # Authoritative implementation and helpers
187
+ │ ├── index.ts # Thin Pi entrypoint
188
+ │ └── statusline.ts # Responsive footer lifecycle
189
+ ├── dist/ # Generated Jiti runtime
190
+ ├── scripts/build-runtime.mjs # Runtime builder
191
+ ├── docs/ # Published reference documentation
192
+ └── test/ # Behavior and lifecycle coverage
372
193
  ```
373
194
 
374
- `src/` is the authoritative implementation, and `src/index.ts` remains its thin source forwarder.
375
- The package build emits the sole declared Pi entrypoint at `dist/index.ts` without forwarding back into `src`.
195
+ The generated runtime is built from `src/index.ts` and does not import back into `src`.
376
196
 
377
197
  ## 🔎 Keywords
378
198
 
@@ -30,15 +30,7 @@ var SEGMENT_NAMES = [
30
30
  "turn"
31
31
  ];
32
32
  var LINE_BREAK_SEGMENT_NAME = "line_break";
33
- var PALETTE_NAMES = [
34
- "tokyo-night",
35
- "ocean",
36
- "sunset",
37
- "forest",
38
- "candy",
39
- "neon",
40
- "mono"
41
- ];
33
+ var PALETTE_NAMES = ["tokyo-night", "ocean", "sunset", "forest", "candy", "neon", "mono"];
42
34
  var PALETTE_PRESET_NAMES = [...PALETTE_NAMES, "custom"];
43
35
  var DENSITIES = ["compact", "cozy"];
44
36
  var SEPARATOR_NAMES = ["none", "dot", "bar", "powerline", "round"];
@@ -77,13 +69,7 @@ function relativeLuminance(hex) {
77
69
  }
78
70
 
79
71
  // src/presets/candy.ts
80
- var CANDY_PRESET = createRampPreset([
81
- "#f5c2e7",
82
- "#cba6f7",
83
- "#89b4fa",
84
- "#745f9a",
85
- "#403a5c"
86
- ]);
72
+ var CANDY_PRESET = createRampPreset(["#f5c2e7", "#cba6f7", "#89b4fa", "#745f9a", "#403a5c"]);
87
73
 
88
74
  // src/presets/custom.ts
89
75
  var CUSTOM_PRESET = {
@@ -97,49 +83,19 @@ var CUSTOM_PRESET = {
97
83
  };
98
84
 
99
85
  // src/presets/forest.ts
100
- var FOREST_PRESET = createRampPreset([
101
- "#a7c080",
102
- "#83c092",
103
- "#5f9f75",
104
- "#3f6f55",
105
- "#293f35"
106
- ]);
86
+ var FOREST_PRESET = createRampPreset(["#a7c080", "#83c092", "#5f9f75", "#3f6f55", "#293f35"]);
107
87
 
108
88
  // src/presets/mono.ts
109
- var MONO_PRESET = createRampPreset([
110
- "#d4d4d4",
111
- "#a3a3a3",
112
- "#686868",
113
- "#404040",
114
- "#262626"
115
- ]);
89
+ var MONO_PRESET = createRampPreset(["#d4d4d4", "#a3a3a3", "#686868", "#404040", "#262626"]);
116
90
 
117
91
  // src/presets/neon.ts
118
- var NEON_PRESET = createRampPreset([
119
- "#39ff14",
120
- "#00f5ff",
121
- "#ff4fd8",
122
- "#7a2cf3",
123
- "#29134f"
124
- ]);
92
+ var NEON_PRESET = createRampPreset(["#39ff14", "#00f5ff", "#ff4fd8", "#7a2cf3", "#29134f"]);
125
93
 
126
94
  // src/presets/ocean.ts
127
- var OCEAN_PRESET = createRampPreset([
128
- "#7dcfff",
129
- "#4f9fba",
130
- "#2d6f88",
131
- "#23475b",
132
- "#182b3a"
133
- ]);
95
+ var OCEAN_PRESET = createRampPreset(["#7dcfff", "#4f9fba", "#2d6f88", "#23475b", "#182b3a"]);
134
96
 
135
97
  // src/presets/sunset.ts
136
- var SUNSET_PRESET = createRampPreset([
137
- "#ffcf70",
138
- "#f59e6f",
139
- "#dc718a",
140
- "#8f5b78",
141
- "#493447"
142
- ]);
98
+ var SUNSET_PRESET = createRampPreset(["#ffcf70", "#f59e6f", "#dc718a", "#8f5b78", "#493447"]);
143
99
 
144
100
  // src/presets/tokyo-night.ts
145
101
  var TOKYO_NIGHT_PRESET = {
@@ -185,9 +141,7 @@ function resolvePreset(preset) {
185
141
  }
186
142
  function segmentPaletteForPreset(preset) {
187
143
  const blocks = PRESETS[preset].blocks;
188
- return Object.fromEntries(
189
- SEGMENT_NAMES.map((name) => [name, { ...blocks[SEGMENT_BLOCKS[name]] }])
190
- );
144
+ return Object.fromEntries(SEGMENT_NAMES.map((name) => [name, { ...blocks[SEGMENT_BLOCKS[name]] }]));
191
145
  }
192
146
 
193
147
  // src/information-profiles.ts
@@ -195,19 +149,7 @@ var INFORMATION_PROFILE_NAMES = ["minimal", "balanced", "detailed"];
195
149
  var INFORMATION_PROFILES = {
196
150
  minimal: ["model", "cwd", "branch", "context"],
197
151
  balanced: ["model", "thinking", "cwd", "branch", "tools", "context", "time"],
198
- detailed: [
199
- "provider",
200
- "model",
201
- "thinking",
202
- "cwd",
203
- "branch",
204
- "tools",
205
- "context",
206
- "tokens",
207
- "cache",
208
- "cost",
209
- "time"
210
- ]
152
+ detailed: ["provider", "model", "thinking", "cwd", "branch", "tools", "context", "tokens", "cache", "cost", "time"]
211
153
  };
212
154
  function inferInformationProfile(segments) {
213
155
  for (const name of INFORMATION_PROFILE_NAMES) {
@@ -289,11 +231,7 @@ var DEFAULT_STATUSLINE_DOCUMENT_CONFIG = {
289
231
  segmentText: DEFAULT_STATUSLINE_CONFIG.segmentText,
290
232
  extensionStatusIcons: DEFAULT_DOCUMENT_EXTENSION_STATUS_ICONS
291
233
  };
292
- var DEFAULT_STATUSLINE_DOCUMENT = `${JSON.stringify(
293
- DEFAULT_STATUSLINE_DOCUMENT_CONFIG,
294
- null,
295
- " "
296
- )}
234
+ var DEFAULT_STATUSLINE_DOCUMENT = `${JSON.stringify(DEFAULT_STATUSLINE_DOCUMENT_CONFIG, null, " ")}
297
235
  `;
298
236
  var pendingSettingsNotice;
299
237
  function settingsFilePath(agentDir = getAgentDir()) {
@@ -344,9 +282,7 @@ function normalizeStatuslineConfig(value) {
344
282
  }
345
283
  if (item === LINE_BREAK_SEGMENT_NAME) {
346
284
  if (segments.at(-1) === LINE_BREAK_SEGMENT_NAME) {
347
- diagnostics.push(
348
- invalidDiagnostic(path, "Consecutive line_break segments are not allowed")
349
- );
285
+ diagnostics.push(invalidDiagnostic(path, "Consecutive line_break segments are not allowed"));
350
286
  continue;
351
287
  }
352
288
  segments.push(item);
@@ -529,10 +465,7 @@ function saveStatuslineSettingsDocument(settingsPath, rawDocument, overrides = {
529
465
  };
530
466
  }
531
467
  function removeStatuslineSettingsDocumentIfMatches(settingsPath, expectedRawDocument, expectedIdentity) {
532
- const quarantinePath = join(
533
- dirname(settingsPath),
534
- `.${SETTINGS_FILE_NAME}.${randomUUID()}.rollback`
535
- );
468
+ const quarantinePath = join(dirname(settingsPath), `.${SETTINGS_FILE_NAME}.${randomUUID()}.rollback`);
536
469
  const before = lstatSync(settingsPath);
537
470
  if (before.dev !== expectedIdentity.dev || before.ino !== expectedIdentity.ino) {
538
471
  throw new Error("Statusline settings changed concurrently; the newer file was preserved");
@@ -562,10 +495,7 @@ function normalizePalette(value, config, diagnostics) {
562
495
  if (typeof value === "string") {
563
496
  if (!PALETTE_NAMES.includes(value)) {
564
497
  diagnostics.push(
565
- invalidDiagnostic(
566
- "palette",
567
- `Expected a palette object or one of: ${PALETTE_NAMES.join(", ")}`
568
- )
498
+ invalidDiagnostic("palette", `Expected a palette object or one of: ${PALETTE_NAMES.join(", ")}`)
569
499
  );
570
500
  return;
571
501
  }
@@ -611,9 +541,7 @@ function normalizeModelTruncation(presentation, config, diagnostics) {
611
541
  const length = presentation.truncationLength;
612
542
  if (length !== void 0) {
613
543
  if (typeof length !== "number" || !Number.isInteger(length) || length < 0 || length > 1e3) {
614
- diagnostics.push(
615
- invalidDiagnostic(`${path}.truncationLength`, "Expected an integer from 0 through 1000")
616
- );
544
+ diagnostics.push(invalidDiagnostic(`${path}.truncationLength`, "Expected an integer from 0 through 1000"));
617
545
  } else config.segmentText.model.truncationLength = length;
618
546
  }
619
547
  const symbol = presentation.truncationSymbol;
@@ -624,10 +552,7 @@ function normalizeModelTruncation(presentation, config, diagnostics) {
624
552
  if (direction !== void 0) {
625
553
  if (typeof direction !== "string" || !TRUNCATION_DIRECTIONS.includes(direction)) {
626
554
  diagnostics.push(
627
- invalidDiagnostic(
628
- `${path}.truncationDirection`,
629
- `Expected one of: ${TRUNCATION_DIRECTIONS.join(", ")}`
630
- )
555
+ invalidDiagnostic(`${path}.truncationDirection`, `Expected one of: ${TRUNCATION_DIRECTIONS.join(", ")}`)
631
556
  );
632
557
  } else {
633
558
  config.segmentText.model.truncationDirection = direction;
@@ -653,17 +578,13 @@ function normalizeEnum(value, field, accepted, config, diagnostics) {
653
578
  const candidate = value[field];
654
579
  if (candidate === void 0) return;
655
580
  if (typeof candidate !== "string" || !accepted.includes(candidate)) {
656
- diagnostics.push(
657
- invalidDiagnostic(field, `Expected one of: ${accepted.map(String).join(", ")}`)
658
- );
581
+ diagnostics.push(invalidDiagnostic(field, `Expected one of: ${accepted.map(String).join(", ")}`));
659
582
  return;
660
583
  }
661
584
  config[field] = candidate;
662
585
  }
663
586
  function cloneSegmentPalette(palette) {
664
- return Object.fromEntries(
665
- Object.entries(palette).map(([name, colors]) => [name, { ...colors }])
666
- );
587
+ return Object.fromEntries(Object.entries(palette).map(([name, colors]) => [name, { ...colors }]));
667
588
  }
668
589
  function cloneConfig(config) {
669
590
  return {
@@ -765,4 +686,4 @@ export {
765
686
  removeStatuslineSettingsDocumentIfMatches,
766
687
  consumeStatuslineSettingsNotice
767
688
  };
768
- //# sourceMappingURL=chunk-74QZGJ7L.js.map
689
+ //# sourceMappingURL=chunk-LARLXEUL.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/command-contract.ts", "../../src/types.ts", "../../src/presets/create-ramp.ts", "../../src/presets/candy.ts", "../../src/presets/custom.ts", "../../src/presets/forest.ts", "../../src/presets/mono.ts", "../../src/presets/neon.ts", "../../src/presets/ocean.ts", "../../src/presets/sunset.ts", "../../src/presets/tokyo-night.ts", "../../src/presets/index.ts", "../../src/information-profiles.ts", "../../src/settings.ts"],
4
+ "sourcesContent": ["import type { AutocompleteItem } from \"@earendil-works/pi-tui\";\n\nexport const STATUSLINE_SUBCOMMANDS: readonly AutocompleteItem[] = [\n { value: \"settings\", label: \"settings\", description: \"Edit pi-statusline.json\" },\n { value: \"status\", label: \"status\", description: \"Show effective statusline settings\" },\n { value: \"help\", label: \"help\", description: \"Show configuration help\" },\n];\n\nexport function completeStatuslineArguments(prefix: string): AutocompleteItem[] | null {\n const normalized = prefix.trim().toLowerCase();\n const matches = STATUSLINE_SUBCOMMANDS.filter((item) => item.value.startsWith(normalized));\n return matches.length > 0 ? [...matches] : null;\n}\n", "import type { ThemeColor } from \"@earendil-works/pi-coding-agent\";\n\nexport const SEGMENT_NAMES = [\n \"brand\",\n \"provider\",\n \"model\",\n \"thinking\",\n \"cwd\",\n \"branch\",\n \"tools\",\n \"context\",\n \"tokens\",\n \"cache\",\n \"cost\",\n \"time\",\n \"turn\",\n] as const;\nexport type SegmentName = (typeof SEGMENT_NAMES)[number];\n\nexport const LINE_BREAK_SEGMENT_NAME = \"line_break\" as const;\nexport type ConfigSegmentName = SegmentName | typeof LINE_BREAK_SEGMENT_NAME;\n\nexport const PALETTE_NAMES = [\"tokyo-night\", \"ocean\", \"sunset\", \"forest\", \"candy\", \"neon\", \"mono\"] as const;\nexport type PaletteName = (typeof PALETTE_NAMES)[number];\n\nexport const PALETTE_PRESET_NAMES = [...PALETTE_NAMES, \"custom\"] as const;\nexport type PalettePreset = (typeof PALETTE_PRESET_NAMES)[number];\n\nexport const DENSITIES = [\"compact\", \"cozy\"] as const;\nexport type Density = (typeof DENSITIES)[number];\n\nexport const SEPARATOR_NAMES = [\"none\", \"dot\", \"bar\", \"powerline\", \"round\"] as const;\nexport type SeparatorName = (typeof SEPARATOR_NAMES)[number];\n\nexport const TRUNCATION_DIRECTIONS = [\"start\", \"middle\", \"end\"] as const;\nexport type TruncationDirection = (typeof TRUNCATION_DIRECTIONS)[number];\n\nexport type PowerlineBlockName = \"header\" | \"directory\" | \"git\" | \"runtime\" | \"meter\";\n\nexport interface SegmentTextConfig {\n prefix: string;\n suffix: string;\n}\n\nexport interface ModelSegmentTextConfig extends SegmentTextConfig {\n truncationLength: number;\n truncationSymbol: string;\n truncationDirection: TruncationDirection;\n}\n\nexport interface SegmentPaletteColor {\n fg?: string;\n bg?: string;\n}\n\nexport type SegmentPalette = Partial<Record<SegmentName, SegmentPaletteColor>>;\n\nexport interface StatuslineConfig {\n palettePreset: PalettePreset;\n palette: SegmentPalette;\n density: Density;\n separator: SeparatorName;\n segments: ConfigSegmentName[];\n segmentText: Record<SegmentName, SegmentTextConfig> & { model: ModelSegmentTextConfig };\n extensionStatusIcons: Record<string, string>;\n}\n\nexport interface RenderSegment {\n name: SegmentName;\n text: string;\n color: ThemeColor;\n block: PowerlineBlockName;\n emphasis?: boolean;\n}\n\nexport interface RenderLineBreak {\n name: typeof LINE_BREAK_SEGMENT_NAME;\n}\n\nexport type RenderItem = RenderSegment | RenderLineBreak;\n", "import type { PowerlineBlockName } from \"../types.js\";\nimport type { PowerlinePreset } from \"./types.js\";\n\nconst BLOCK_NAMES: PowerlineBlockName[] = [\"header\", \"directory\", \"git\", \"runtime\", \"meter\"];\n\ntype PaletteRamp = readonly [string, string, string, string, string];\n\nexport function createRampPreset(backgrounds: PaletteRamp): PowerlinePreset {\n return {\n lead: backgrounds[0],\n blocks: Object.fromEntries(\n BLOCK_NAMES.map((block, index) => {\n const background = backgrounds[index];\n return [block, { fg: contrastColor(background), bg: background }];\n }),\n ) as Record<PowerlineBlockName, { fg: string; bg: string }>,\n extensionSeparator: backgrounds[2],\n };\n}\n\nfunction contrastColor(hex: string): string {\n const background = relativeLuminance(hex);\n const dark = relativeLuminance(\"#090c0c\");\n const light = relativeLuminance(\"#f0f0f0\");\n return contrastRatio(background, dark) >= contrastRatio(background, light) ? \"#090c0c\" : \"#f0f0f0\";\n}\n\nfunction contrastRatio(left: number, right: number): number {\n return (Math.max(left, right) + 0.05) / (Math.min(left, right) + 0.05);\n}\n\nfunction relativeLuminance(hex: string): number {\n const normalized = hex.slice(1);\n const channels = [0, 2, 4].map((offset) => {\n const value = Number.parseInt(normalized.slice(offset, offset + 2), 16) / 255;\n return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;\n });\n return 0.2126 * (channels[0] ?? 0) + 0.7152 * (channels[1] ?? 0) + 0.0722 * (channels[2] ?? 0);\n}\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const CANDY_PRESET = createRampPreset([\"#f5c2e7\", \"#cba6f7\", \"#89b4fa\", \"#745f9a\", \"#403a5c\"]);\n", "import type { PowerlinePreset } from \"./types.js\";\n\nexport const CUSTOM_PRESET: PowerlinePreset = {\n blocks: {\n header: {},\n directory: {},\n git: {},\n runtime: {},\n meter: {},\n },\n};\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const FOREST_PRESET = createRampPreset([\"#a7c080\", \"#83c092\", \"#5f9f75\", \"#3f6f55\", \"#293f35\"]);\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const MONO_PRESET = createRampPreset([\"#d4d4d4\", \"#a3a3a3\", \"#686868\", \"#404040\", \"#262626\"]);\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const NEON_PRESET = createRampPreset([\"#39ff14\", \"#00f5ff\", \"#ff4fd8\", \"#7a2cf3\", \"#29134f\"]);\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const OCEAN_PRESET = createRampPreset([\"#7dcfff\", \"#4f9fba\", \"#2d6f88\", \"#23475b\", \"#182b3a\"]);\n", "import { createRampPreset } from \"./create-ramp.js\";\n\nexport const SUNSET_PRESET = createRampPreset([\"#ffcf70\", \"#f59e6f\", \"#dc718a\", \"#8f5b78\", \"#493447\"]);\n", "import type { PowerlinePreset } from \"./types.js\";\n\nexport const TOKYO_NIGHT_PRESET: PowerlinePreset = {\n lead: \"#a3aed2\",\n blocks: {\n header: { fg: \"#090c0c\", bg: \"#a3aed2\" },\n directory: { fg: \"#e3e5e5\", bg: \"#769ff0\" },\n git: { fg: \"#769ff0\", bg: \"#394260\" },\n runtime: { fg: \"#769ff0\", bg: \"#212736\" },\n meter: { fg: \"#a0a9cb\", bg: \"#1d2230\" },\n },\n extensionSeparator: \"#394260\",\n};\n", "import {\n type PaletteName,\n type PalettePreset,\n type PowerlineBlockName,\n SEGMENT_NAMES,\n type SegmentName,\n type SegmentPalette,\n} from \"../types.js\";\nimport { CANDY_PRESET } from \"./candy.js\";\nimport { CUSTOM_PRESET } from \"./custom.js\";\nimport { FOREST_PRESET } from \"./forest.js\";\nimport { MONO_PRESET } from \"./mono.js\";\nimport { NEON_PRESET } from \"./neon.js\";\nimport { OCEAN_PRESET } from \"./ocean.js\";\nimport { SUNSET_PRESET } from \"./sunset.js\";\nimport { TOKYO_NIGHT_PRESET } from \"./tokyo-night.js\";\nimport type { PowerlinePreset } from \"./types.js\";\n\nconst PRESETS = {\n \"tokyo-night\": TOKYO_NIGHT_PRESET,\n ocean: OCEAN_PRESET,\n sunset: SUNSET_PRESET,\n forest: FOREST_PRESET,\n candy: CANDY_PRESET,\n neon: NEON_PRESET,\n mono: MONO_PRESET,\n custom: CUSTOM_PRESET,\n} satisfies Record<PalettePreset, PowerlinePreset>;\n\nconst SEGMENT_BLOCKS: Record<SegmentName, PowerlineBlockName> = {\n brand: \"header\",\n provider: \"header\",\n model: \"header\",\n thinking: \"header\",\n cwd: \"directory\",\n branch: \"git\",\n tools: \"runtime\",\n context: \"runtime\",\n tokens: \"runtime\",\n cache: \"runtime\",\n cost: \"meter\",\n time: \"meter\",\n turn: \"meter\",\n};\n\nexport function resolvePreset(preset: PalettePreset): PowerlinePreset {\n return PRESETS[preset];\n}\n\nexport function segmentPaletteForPreset(preset: PaletteName): SegmentPalette {\n const blocks = PRESETS[preset].blocks;\n return Object.fromEntries(SEGMENT_NAMES.map((name) => [name, { ...blocks[SEGMENT_BLOCKS[name]] }])) as SegmentPalette;\n}\n", "import type { ConfigSegmentName, SegmentName } from \"./types.js\";\n\nexport const INFORMATION_PROFILE_NAMES = [\"minimal\", \"balanced\", \"detailed\"] as const;\nexport type InformationProfileName = (typeof INFORMATION_PROFILE_NAMES)[number];\nexport type InformationProfile = InformationProfileName | \"custom\";\n\nexport const INFORMATION_PROFILES: Readonly<Record<InformationProfileName, readonly SegmentName[]>> = {\n minimal: [\"model\", \"cwd\", \"branch\", \"context\"],\n balanced: [\"model\", \"thinking\", \"cwd\", \"branch\", \"tools\", \"context\", \"time\"],\n detailed: [\"provider\", \"model\", \"thinking\", \"cwd\", \"branch\", \"tools\", \"context\", \"tokens\", \"cache\", \"cost\", \"time\"],\n};\n\nexport function inferInformationProfile(segments: readonly ConfigSegmentName[]): InformationProfile {\n for (const name of INFORMATION_PROFILE_NAMES) {\n const profile = INFORMATION_PROFILES[name];\n if (segments.length === profile.length && segments.every((segment, index) => segment === profile[index])) {\n return name;\n }\n }\n return \"custom\";\n}\n", "import { randomUUID } from \"node:crypto\";\nimport { lstatSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { getAgentDir } from \"@earendil-works/pi-coding-agent\";\nimport { INFORMATION_PROFILES } from \"./information-profiles.js\";\nimport { segmentPaletteForPreset } from \"./presets/index.js\";\nimport {\n type ConfigSegmentName,\n DENSITIES,\n LINE_BREAK_SEGMENT_NAME,\n PALETTE_NAMES,\n PALETTE_PRESET_NAMES,\n type PaletteName,\n SEGMENT_NAMES,\n SEPARATOR_NAMES,\n type SegmentName,\n type SegmentPalette,\n type StatuslineConfig,\n TRUNCATION_DIRECTIONS,\n} from \"./types.js\";\n\nexport const SETTINGS_FILE_NAME = \"pi-statusline.json\";\nconst LEGACY_SETTINGS_FILE_NAME = \"pi-statusline-settings.json\";\n\nconst DEFAULT_DOCUMENT_EXTENSION_STATUS_ICONS: Record<string, string> = {\n accounts: \"\uD83D\uDC64\",\n caffeinate: \"\uD83D\uDC8A\",\n \"chrome-devtools\": \"\uD83C\uDF10\",\n firecrawl: \"\uD83D\uDD25\",\n \"github-pr\": \"\uD83D\uDD0E\",\n goal: \"\uD83C\uDFAF\",\n \"google-genai\": \"\u2728\",\n lsp: \"\uD83E\uDDF0\",\n \"plan-mode\": \"\uD83D\uDCDD\",\n retry: \"\uD83D\uDD01\",\n subagents: \"\uD83E\uDDD1\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1\",\n sync: \"\uD83D\uDD04\",\n usage: \"\uD83D\uDCCA\",\n};\n\nexport const DEFAULT_EXTENSION_STATUS_ICONS: Record<string, string> = {\n ...DEFAULT_DOCUMENT_EXTENSION_STATUS_ICONS,\n \"codex-usage\": \"\uD83D\uDCCA\",\n pisync: \"\uD83D\uDD04\",\n \"unknown-error-retry\": \"\uD83D\uDD01\",\n};\n\nconst LEGACY_STATUS_ICON_KEYS = {\n pisync: \"sync\",\n \"unknown-error-retry\": \"retry\",\n} as const;\n\nconst DEFAULT_SEGMENTS: SegmentName[] = [...INFORMATION_PROFILES.balanced];\n\nexport const DEFAULT_STATUSLINE_CONFIG: StatuslineConfig = {\n palettePreset: \"tokyo-night\",\n palette: segmentPaletteForPreset(\"tokyo-night\"),\n density: \"compact\",\n separator: \"none\",\n segments: DEFAULT_SEGMENTS,\n segmentText: {\n brand: { prefix: \"\", suffix: \"\" },\n provider: { prefix: \"\uD83D\uDD0C \", suffix: \"\" },\n model: {\n prefix: \"\uD83E\uDD16 \",\n suffix: \"\",\n truncationLength: 36,\n truncationSymbol: \"\u2026\",\n truncationDirection: \"start\",\n },\n thinking: { prefix: \"\uD83E\uDDE0 \", suffix: \"\" },\n cwd: { prefix: \"\uD83D\uDCC1 \", suffix: \"\" },\n branch: { prefix: \"\uD83C\uDF3F \", suffix: \"\" },\n tools: { prefix: \"\", suffix: \"\" },\n context: { prefix: \"\uD83E\uDE9F ctx \", suffix: \"\" },\n tokens: { prefix: \"\uD83D\uDD22 \", suffix: \"\" },\n cache: { prefix: \"\uD83D\uDCE6 \", suffix: \"\" },\n cost: { prefix: \"\uD83D\uDCB8 $\", suffix: \"\" },\n time: { prefix: \"\uD83D\uDD52 \", suffix: \"\" },\n turn: { prefix: \"\uD83D\uDD01 #\", suffix: \"\" },\n },\n extensionStatusIcons: DEFAULT_EXTENSION_STATUS_ICONS,\n};\n\nconst DEFAULT_STATUSLINE_DOCUMENT_CONFIG = {\n palettePreset: DEFAULT_STATUSLINE_CONFIG.palettePreset,\n density: DEFAULT_STATUSLINE_CONFIG.density,\n separator: DEFAULT_STATUSLINE_CONFIG.separator,\n segments: DEFAULT_SEGMENTS,\n segmentText: DEFAULT_STATUSLINE_CONFIG.segmentText,\n extensionStatusIcons: DEFAULT_DOCUMENT_EXTENSION_STATUS_ICONS,\n} satisfies Omit<StatuslineConfig, \"palette\">;\n\nexport const DEFAULT_STATUSLINE_DOCUMENT = `${JSON.stringify(DEFAULT_STATUSLINE_DOCUMENT_CONFIG, null, \"\\t\")}\\n`;\n\nexport interface StatuslineConfigDiagnostic {\n severity: \"warning\" | \"error\";\n code: \"unknown\" | \"invalid\" | \"parse\" | \"io\";\n path: string;\n message: string;\n}\n\nexport interface LoadedStatuslineSettings {\n config: StatuslineConfig;\n source: \"built-in\" | \"user\";\n settingsPath: string;\n rawDocument?: string;\n fileIdentity?: { dev: number; ino: number };\n diagnostics: StatuslineConfigDiagnostic[];\n}\n\ninterface AtomicFileSystem {\n mkdirSync: typeof mkdirSync;\n writeFileSync: typeof writeFileSync;\n renameSync: typeof renameSync;\n rmSync: typeof rmSync;\n}\n\nlet pendingSettingsNotice: string | undefined;\n\nexport function settingsFilePath(agentDir = getAgentDir()): string {\n return join(agentDir, SETTINGS_FILE_NAME);\n}\n\nexport function createDefaultConfig(): StatuslineConfig {\n return cloneConfig(DEFAULT_STATUSLINE_CONFIG);\n}\n\nexport function normalizeStatuslineConfig(value: unknown): {\n config: StatuslineConfig;\n diagnostics: StatuslineConfigDiagnostic[];\n} {\n const config = createDefaultConfig();\n const diagnostics: StatuslineConfigDiagnostic[] = [];\n if (!isRecord(value)) {\n return {\n config,\n diagnostics: [invalidDiagnostic(\"\", \"Settings must contain a JSON object\", \"error\")],\n };\n }\n const knownRoot = new Set([\n \"palettePreset\",\n \"palette\",\n \"density\",\n \"separator\",\n \"segments\",\n \"segmentText\",\n \"extensionStatusIcons\",\n ]);\n for (const key of Object.keys(value)) {\n if (!knownRoot.has(key)) diagnostics.push(unknownDiagnostic(key));\n }\n\n normalizePalette(value.palette, config, diagnostics);\n normalizeEnum(value, \"palettePreset\", PALETTE_PRESET_NAMES, config, diagnostics);\n if (!isRecord(value.palette) && isPaletteName(config.palettePreset)) {\n config.palette = segmentPaletteForPreset(config.palettePreset);\n }\n normalizeEnum(value, \"density\", DENSITIES, config, diagnostics);\n normalizeEnum(value, \"separator\", SEPARATOR_NAMES, config, diagnostics);\n\n if (value.segments !== undefined) {\n if (!Array.isArray(value.segments)) {\n diagnostics.push(invalidDiagnostic(\"segments\", \"Expected an array of segment names\"));\n } else {\n const segments: ConfigSegmentName[] = [];\n const seen = new Set<SegmentName>();\n for (const [index, item] of value.segments.entries()) {\n const path = `segments[${index}]`;\n if (typeof item !== \"string\" || !isConfigSegmentName(item)) {\n diagnostics.push(invalidDiagnostic(path, \"Unknown or non-string segment name\"));\n continue;\n }\n if (item === LINE_BREAK_SEGMENT_NAME) {\n if (segments.at(-1) === LINE_BREAK_SEGMENT_NAME) {\n diagnostics.push(invalidDiagnostic(path, \"Consecutive line_break segments are not allowed\"));\n continue;\n }\n segments.push(item);\n continue;\n }\n if (seen.has(item)) {\n diagnostics.push(invalidDiagnostic(path, `Duplicate segment ${JSON.stringify(item)}`));\n continue;\n }\n seen.add(item);\n segments.push(item);\n }\n config.segments = segments;\n }\n }\n\n if (value.segmentText !== undefined) {\n if (!isRecord(value.segmentText)) {\n diagnostics.push(invalidDiagnostic(\"segmentText\", \"Expected an object\"));\n } else {\n for (const [name, presentation] of Object.entries(value.segmentText)) {\n const path = `segmentText.${name}`;\n if (!isSegmentName(name)) {\n diagnostics.push(unknownDiagnostic(path));\n continue;\n }\n if (!isRecord(presentation)) {\n diagnostics.push(invalidDiagnostic(path, \"Expected an object\"));\n continue;\n }\n const knownFields = new Set([\n \"prefix\",\n \"suffix\",\n ...(name === \"model\" ? [\"truncationLength\", \"truncationSymbol\", \"truncationDirection\"] : []),\n ]);\n for (const key of Object.keys(presentation)) {\n if (!knownFields.has(key)) diagnostics.push(unknownDiagnostic(`${path}.${key}`));\n }\n for (const field of [\"prefix\", \"suffix\"] as const) {\n const fieldValue = presentation[field];\n if (fieldValue === undefined) continue;\n if (!isSafeSegmentText(fieldValue, `${path}.${field}`, diagnostics)) continue;\n config.segmentText[name][field] = fieldValue;\n }\n if (name === \"model\") {\n normalizeModelTruncation(presentation, config, diagnostics);\n }\n }\n }\n }\n\n if (value.extensionStatusIcons !== undefined) {\n if (!isRecord(value.extensionStatusIcons)) {\n diagnostics.push(invalidDiagnostic(\"extensionStatusIcons\", \"Expected an object\"));\n } else {\n for (const [key, icon] of Object.entries(value.extensionStatusIcons)) {\n if (typeof icon !== \"string\") {\n diagnostics.push(invalidDiagnostic(`extensionStatusIcons.${key}`, \"Expected a string\"));\n continue;\n }\n Object.defineProperty(config.extensionStatusIcons, key, {\n value: icon,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n for (const [legacyKey, canonicalKey] of Object.entries(LEGACY_STATUS_ICON_KEYS)) {\n const legacyIcon = Object.hasOwn(value.extensionStatusIcons, legacyKey)\n ? value.extensionStatusIcons[legacyKey]\n : undefined;\n const canonicalIcon = Object.hasOwn(value.extensionStatusIcons, canonicalKey)\n ? value.extensionStatusIcons[canonicalKey]\n : undefined;\n const targetKey = typeof canonicalIcon === \"string\" ? legacyKey : canonicalKey;\n const inheritedIcon =\n typeof canonicalIcon === \"string\" ? canonicalIcon : typeof legacyIcon === \"string\" ? legacyIcon : undefined;\n if (inheritedIcon === undefined) continue;\n Object.defineProperty(config.extensionStatusIcons, targetKey, {\n value: inheritedIcon,\n enumerable: true,\n configurable: true,\n writable: true,\n });\n }\n }\n }\n\n return { config, diagnostics };\n}\n\nexport function loadStatuslineSettings(settingsPath: string): LoadedStatuslineSettings {\n let rawDocument: string;\n try {\n rawDocument = readFileSync(settingsPath, \"utf8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\" && !pathExists(settingsPath)) {\n return builtInSettings(settingsPath);\n }\n return builtInSettings(settingsPath, [\n diagnostic(\"error\", \"io\", \"\", `Unable to read settings: ${formatError(error)}`),\n ]);\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawDocument);\n } catch (error) {\n return {\n ...builtInSettings(settingsPath, [\n diagnostic(\"error\", \"parse\", \"\", `Unable to parse JSON: ${formatError(error)}`),\n ]),\n rawDocument,\n };\n }\n const normalized = normalizeStatuslineConfig(parsed);\n return {\n config: normalized.config,\n source: normalized.diagnostics.some((item) => item.severity === \"error\") ? \"built-in\" : \"user\",\n settingsPath,\n rawDocument,\n diagnostics: normalized.diagnostics,\n };\n}\n\nexport function loadStatuslineSettingsForAgent(agentDir = getAgentDir()): LoadedStatuslineSettings {\n pendingSettingsNotice = undefined;\n const canonicalPath = settingsFilePath(agentDir);\n const legacyPath = join(agentDir, LEGACY_SETTINGS_FILE_NAME);\n const canonical = loadStatuslineSettings(canonicalPath);\n if (!isMissingStatuslineSettings(canonical)) {\n if (!isMissingStatuslineSettings(loadStatuslineSettings(legacyPath))) {\n pendingSettingsNotice = `${LEGACY_SETTINGS_FILE_NAME} ignored because ${SETTINGS_FILE_NAME} takes precedence.`;\n }\n return canonical;\n }\n const legacy = loadStatuslineSettings(legacyPath);\n return isMissingStatuslineSettings(legacy) ? canonical : migrateLegacySettings(canonicalPath, legacy);\n}\n\nfunction migrateLegacySettings(canonicalPath: string, legacy: LoadedStatuslineSettings): LoadedStatuslineSettings {\n const racedCanonical = loadStatuslineSettings(canonicalPath);\n if (!isMissingStatuslineSettings(racedCanonical)) {\n pendingSettingsNotice = `${LEGACY_SETTINGS_FILE_NAME} ignored because ${SETTINGS_FILE_NAME} was created concurrently.`;\n return racedCanonical;\n }\n if (\n legacy.source !== \"user\" ||\n legacy.rawDocument === undefined ||\n blockingDiagnostics(legacy.diagnostics).length > 0\n ) {\n pendingSettingsNotice = `${LEGACY_SETTINGS_FILE_NAME} is invalid and was ignored.`;\n return legacy;\n }\n pendingSettingsNotice = `Using legacy ${LEGACY_SETTINGS_FILE_NAME}; rename it to ${SETTINGS_FILE_NAME}. Future saves write ${SETTINGS_FILE_NAME} without modifying the legacy file.`;\n return legacy;\n}\n\nfunction isMissingStatuslineSettings(settings: LoadedStatuslineSettings): boolean {\n return settings.source === \"built-in\" && settings.rawDocument === undefined && settings.diagnostics.length === 0;\n}\n\nexport function saveStatuslineSettingsDocument(\n settingsPath: string,\n rawDocument: string,\n overrides: Partial<AtomicFileSystem> = {},\n): LoadedStatuslineSettings {\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawDocument);\n } catch (error) {\n throw new Error(`Unable to parse JSON: ${formatError(error)}`);\n }\n const normalized = normalizeStatuslineConfig(parsed);\n const blocking = blockingDiagnostics(normalized.diagnostics);\n if (blocking.length > 0) {\n throw new Error(blocking.map((item) => `${item.path || \"root\"}: ${item.message}`).join(\"\\n\"));\n }\n\n const fs = { mkdirSync, writeFileSync, renameSync, rmSync, ...overrides };\n const replaceExisting = pathEntryExists(settingsPath);\n const temporaryPath = temporarySettingsPath(settingsPath);\n let fileIdentity: { dev: number; ino: number } | undefined;\n try {\n fs.mkdirSync(dirname(settingsPath), { recursive: true });\n fs.writeFileSync(temporaryPath, rawDocument, { encoding: \"utf8\", flag: \"wx\" });\n const info = lstatSync(temporaryPath);\n fileIdentity = { dev: info.dev, ino: info.ino };\n if (!replaceExisting && pathEntryExists(settingsPath)) {\n throw new Error(`${SETTINGS_FILE_NAME} was created concurrently; reopen settings and retry.`);\n }\n fs.renameSync(temporaryPath, settingsPath);\n } finally {\n removeTemporaryFile(fs.rmSync, temporaryPath);\n }\n return {\n config: normalized.config,\n source: \"user\",\n settingsPath,\n rawDocument,\n ...(fileIdentity ? { fileIdentity } : {}),\n diagnostics: normalized.diagnostics,\n };\n}\n\nexport function removeStatuslineSettingsDocumentIfMatches(\n settingsPath: string,\n expectedRawDocument: string,\n expectedIdentity: { dev: number; ino: number },\n): void {\n const quarantinePath = join(dirname(settingsPath), `.${SETTINGS_FILE_NAME}.${randomUUID()}.rollback`);\n const before = lstatSync(settingsPath);\n if (before.dev !== expectedIdentity.dev || before.ino !== expectedIdentity.ino) {\n throw new Error(\"Statusline settings changed concurrently; the newer file was preserved\");\n }\n renameSync(settingsPath, quarantinePath);\n const quarantined = lstatSync(quarantinePath);\n const quarantinedSavedFile =\n quarantined.isFile() &&\n !quarantined.isSymbolicLink() &&\n quarantined.dev === expectedIdentity.dev &&\n quarantined.ino === expectedIdentity.ino;\n if (quarantinedSavedFile && readFileSync(quarantinePath, \"utf8\") === expectedRawDocument) {\n rmSync(quarantinePath);\n return;\n }\n if (quarantinedSavedFile && !pathEntryExists(settingsPath)) {\n try {\n renameSync(quarantinePath, settingsPath);\n } catch {\n // Keep the quarantine for recovery when its atomic restoration fails.\n }\n }\n throw new Error(\"Statusline settings changed concurrently; the newer file was preserved\");\n}\n\nexport function consumeStatuslineSettingsNotice(): string | undefined {\n const notice = pendingSettingsNotice;\n pendingSettingsNotice = undefined;\n return notice;\n}\n\nexport function readStatuslineSettings(settingsPath?: string): StatuslineConfig {\n return settingsPath ? loadStatuslineSettings(settingsPath).config : loadStatuslineSettingsForAgent().config;\n}\n\nexport function normalizeStatuslineSettings(value: unknown): StatuslineConfig {\n return normalizeStatuslineConfig(value).config;\n}\n\nfunction normalizePalette(value: unknown, config: StatuslineConfig, diagnostics: StatuslineConfigDiagnostic[]) {\n if (value === undefined) return;\n if (typeof value === \"string\") {\n if (!(PALETTE_NAMES as readonly string[]).includes(value)) {\n diagnostics.push(\n invalidDiagnostic(\"palette\", `Expected a palette object or one of: ${PALETTE_NAMES.join(\", \")}`),\n );\n return;\n }\n config.palettePreset = value as (typeof PALETTE_NAMES)[number];\n return;\n }\n if (!isRecord(value)) {\n diagnostics.push(invalidDiagnostic(\"palette\", \"Expected a palette object\"));\n return;\n }\n\n const palette: SegmentPalette = {};\n config.palette = palette;\n for (const [name, colors] of Object.entries(value)) {\n const path = `palette.${name}`;\n if (!isSegmentName(name)) {\n diagnostics.push(unknownDiagnostic(path));\n continue;\n }\n if (!isRecord(colors)) {\n diagnostics.push(invalidDiagnostic(path, \"Expected an object\"));\n continue;\n }\n const normalizedColors: NonNullable<SegmentPalette[SegmentName]> = {};\n palette[name] = normalizedColors;\n for (const [field, color] of Object.entries(colors)) {\n const colorPath = `${path}.${field}`;\n if (field !== \"fg\" && field !== \"bg\") {\n diagnostics.push(unknownDiagnostic(colorPath));\n continue;\n }\n if (typeof color !== \"string\" || !/^#[0-9a-f]{6}$/iu.test(color)) {\n diagnostics.push(invalidDiagnostic(colorPath, \"Expected a full #RRGGBB hexadecimal color\"));\n continue;\n }\n normalizedColors[field] = color.toLowerCase();\n }\n }\n config.palette = palette;\n config.palettePreset = \"custom\";\n}\n\nfunction normalizeModelTruncation(\n presentation: Record<string, unknown>,\n config: StatuslineConfig,\n diagnostics: StatuslineConfigDiagnostic[],\n) {\n const path = \"segmentText.model\";\n const length = presentation.truncationLength;\n if (length !== undefined) {\n if (typeof length !== \"number\" || !Number.isInteger(length) || length < 0 || length > 1000) {\n diagnostics.push(invalidDiagnostic(`${path}.truncationLength`, \"Expected an integer from 0 through 1000\"));\n } else config.segmentText.model.truncationLength = length;\n }\n\n const symbol = presentation.truncationSymbol;\n if (symbol !== undefined && isSafeSegmentText(symbol, `${path}.truncationSymbol`, diagnostics)) {\n config.segmentText.model.truncationSymbol = symbol;\n }\n\n const direction = presentation.truncationDirection;\n if (direction !== undefined) {\n if (\n typeof direction !== \"string\" ||\n !TRUNCATION_DIRECTIONS.includes(direction as (typeof TRUNCATION_DIRECTIONS)[number])\n ) {\n diagnostics.push(\n invalidDiagnostic(`${path}.truncationDirection`, `Expected one of: ${TRUNCATION_DIRECTIONS.join(\", \")}`),\n );\n } else {\n config.segmentText.model.truncationDirection = direction as (typeof TRUNCATION_DIRECTIONS)[number];\n }\n }\n}\n\nfunction isSafeSegmentText(value: unknown, path: string, diagnostics: StatuslineConfigDiagnostic[]): value is string {\n if (typeof value !== \"string\") {\n diagnostics.push(invalidDiagnostic(path, \"Expected a string\"));\n return false;\n }\n if (/[\\r\\n\\u2028\\u2029]/u.test(value)) {\n diagnostics.push(invalidDiagnostic(path, \"Line breaks are not allowed; use line_break\"));\n return false;\n }\n if (hasControlCharacter(value)) {\n diagnostics.push(invalidDiagnostic(path, \"Control characters are not allowed\"));\n return false;\n }\n return true;\n}\n\nfunction normalizeEnum<K extends \"palettePreset\" | \"density\" | \"separator\", T extends StatuslineConfig[K]>(\n value: Record<string, unknown>,\n field: K,\n accepted: readonly T[],\n config: StatuslineConfig,\n diagnostics: StatuslineConfigDiagnostic[],\n) {\n const candidate = value[field];\n if (candidate === undefined) return;\n if (typeof candidate !== \"string\" || !accepted.includes(candidate as T)) {\n diagnostics.push(invalidDiagnostic(field, `Expected one of: ${accepted.map(String).join(\", \")}`));\n return;\n }\n config[field] = candidate as StatuslineConfig[K];\n}\n\nfunction cloneSegmentPalette(palette: SegmentPalette): SegmentPalette {\n return Object.fromEntries(Object.entries(palette).map(([name, colors]) => [name, { ...colors }])) as SegmentPalette;\n}\n\nfunction cloneConfig(config: StatuslineConfig): StatuslineConfig {\n return {\n ...config,\n palette: cloneSegmentPalette(config.palette),\n segments: [...config.segments],\n segmentText: Object.fromEntries(\n SEGMENT_NAMES.map((name) => [name, { ...config.segmentText[name] }]),\n ) as StatuslineConfig[\"segmentText\"],\n extensionStatusIcons: { ...config.extensionStatusIcons },\n };\n}\n\nfunction builtInSettings(\n settingsPath: string,\n diagnostics: StatuslineConfigDiagnostic[] = [],\n): LoadedStatuslineSettings {\n return {\n config: createDefaultConfig(),\n source: \"built-in\",\n settingsPath,\n diagnostics,\n };\n}\n\nfunction hasControlCharacter(value: string): boolean {\n for (const character of value) {\n const codePoint = character.codePointAt(0) ?? 0;\n if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) return true;\n }\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isConfigSegmentName(value: string): value is ConfigSegmentName {\n return value === LINE_BREAK_SEGMENT_NAME || isSegmentName(value);\n}\n\nfunction isPaletteName(value: StatuslineConfig[\"palettePreset\"]): value is PaletteName {\n return (PALETTE_NAMES as readonly StatuslineConfig[\"palettePreset\"][]).includes(value);\n}\n\nfunction isSegmentName(value: string): value is SegmentName {\n return (SEGMENT_NAMES as readonly string[]).includes(value);\n}\n\nfunction blockingDiagnostics(diagnostics: readonly StatuslineConfigDiagnostic[]): StatuslineConfigDiagnostic[] {\n return diagnostics.filter((item) => item.code !== \"unknown\");\n}\n\nfunction unknownDiagnostic(path: string): StatuslineConfigDiagnostic {\n return diagnostic(\"warning\", \"unknown\", path, `Unknown setting ${JSON.stringify(path)}`);\n}\n\nfunction invalidDiagnostic(\n path: string,\n message: string,\n severity: StatuslineConfigDiagnostic[\"severity\"] = \"warning\",\n): StatuslineConfigDiagnostic {\n return diagnostic(severity, \"invalid\", path, message);\n}\n\nfunction diagnostic(\n severity: StatuslineConfigDiagnostic[\"severity\"],\n code: StatuslineConfigDiagnostic[\"code\"],\n path: string,\n message: string,\n): StatuslineConfigDiagnostic {\n return { severity, code, path, message };\n}\n\nfunction temporarySettingsPath(settingsPath: string): string {\n return join(dirname(settingsPath), `.${SETTINGS_FILE_NAME}.${randomUUID()}.tmp`);\n}\n\nfunction removeTemporaryFile(remove: typeof rmSync, temporaryPath: string) {\n try {\n remove(temporaryPath, { force: true });\n } catch {\n // Best-effort cleanup must not replace the original operation result.\n }\n}\n\nfunction pathExists(path: string): boolean {\n try {\n lstatSync(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction pathEntryExists(path: string): boolean {\n try {\n lstatSync(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw error;\n }\n}\n\nfunction formatError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }