@narumitw/pi-statusline 0.49.15 โ 0.50.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.
- package/README.md +33 -28
- package/dist/index.ts +98 -31
- package/dist/index.ts.map +3 -3
- package/package.json +5 -8
- package/src/ansi.ts +18 -7
- package/src/extension-status.ts +8 -3
- package/src/powerline.ts +14 -8
- package/src/render.ts +45 -5
- package/src/statusline.ts +34 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@narumitw/pi-statusline) [](https://pi.dev) [](./LICENSE)
|
|
4
4
|
|
|
5
|
-
Add
|
|
5
|
+
Add a Powerline-style footer that works without setup and keeps important Pi, workspace, Git, usage, and time context visible as the terminal narrows.
|
|
6
6
|
|
|
7
7
|
A representative uncolored layout:
|
|
8
8
|
|
|
@@ -14,19 +14,16 @@ A representative uncolored layout:
|
|
|
14
14
|
|
|
15
15
|
- Works immediately with a balanced default for model, thinking, workspace, Git, context, activity, and time.
|
|
16
16
|
- Removes lower-priority segments before important information is clipped.
|
|
17
|
-
- Shows
|
|
17
|
+
- Shows when Pi is waiting for an extension UI prompt, streaming, or running tools.
|
|
18
18
|
- Adds optional token, prompt-cache, provider usage, and cost details.
|
|
19
19
|
- Offers three information levels, seven previewable palettes, and advanced custom layouts.
|
|
20
|
+
- Uses ANSI-256 palette colors when Pi's effective terminal capabilities disable true color.
|
|
20
21
|
- Loads a generated split runtime to reduce Pi package startup work.
|
|
21
22
|
|
|
22
23
|
> **Need more customization?**
|
|
23
|
-
> See
|
|
24
|
-
> [
|
|
25
|
-
> It uses a
|
|
26
|
-
> [Starship-inspired](https://starship.rs/) TOML format and style syntax for deeper control over layout, modules, and colors.
|
|
24
|
+
> See [`pi-starship`](https://github.com/narumiruna/pi-extensions/tree/main/packages/pi-starship) ([npm](https://www.npmjs.com/package/@narumitw/pi-starship)).
|
|
25
|
+
> It uses [Starship-inspired](https://starship.rs/) TOML and style syntax for deeper control over layout, modules, and colors.
|
|
27
26
|
> Choose `pi-statusline` for practical defaults and quick setup.
|
|
28
|
-
>
|
|
29
|
-
> Do not enable both extensions at the same time because both own Pi's footer.
|
|
30
27
|
|
|
31
28
|
## ๐ฆ Install
|
|
32
29
|
|
|
@@ -47,9 +44,8 @@ npm --workspace @narumitw/pi-statusline run build
|
|
|
47
44
|
pi -e ./packages/pi-statusline
|
|
48
45
|
```
|
|
49
46
|
|
|
50
|
-
The package declares `dist/index.ts`, so an unbuilt local checkout
|
|
51
|
-
|
|
52
|
-
For the best result, use a terminal font that includes Powerline glyphs and emoji.
|
|
47
|
+
The package declares `dist/index.ts`, so build an unbuilt local checkout before Pi loads the package directory.
|
|
48
|
+
Install only from sources you trust because Pi extensions run with Pi's permissions.
|
|
53
49
|
|
|
54
50
|
## ๐ Quick start
|
|
55
51
|
|
|
@@ -69,15 +65,14 @@ Help
|
|
|
69
65
|
| Menu item | What it does |
|
|
70
66
|
| --- | --- |
|
|
71
67
|
| **Appearance** | Preview palettes with Up/Down; Enter applies and Escape cancels |
|
|
72
|
-
| **Information** | Preview and apply a curated set
|
|
68
|
+
| **Information** | Preview and apply a curated segment set |
|
|
73
69
|
| **Advanced** | Open Custom layout or Edit settings JSON |
|
|
74
70
|
| **Status** | Show the effective source, path, appearance, layout, and diagnostics |
|
|
75
71
|
| **Help** | Show command and schema guidance |
|
|
76
72
|
|
|
77
73
|
### Information levels
|
|
78
74
|
|
|
79
|
-
Selecting a level replaces only
|
|
80
|
-
Unknown and unrelated JSON fields are preserved.
|
|
75
|
+
Selecting a level replaces only `segments` and preserves unrelated JSON fields.
|
|
81
76
|
|
|
82
77
|
| Level | Included segments |
|
|
83
78
|
| --- | --- |
|
|
@@ -99,10 +94,10 @@ The `tools` segment takes no space while idle.
|
|
|
99
94
|
| `/statusline help` | Show command and schema guidance |
|
|
100
95
|
|
|
101
96
|
The direct `settings`, `status`, and `help` routes remain for compatibility.
|
|
102
|
-
The
|
|
103
|
-
RPC receives
|
|
97
|
+
The main menu is TUI-only; Escape returns from Advanced or closes the menu.
|
|
98
|
+
RPC receives notifications instead of TUI-only controls.
|
|
104
99
|
Unknown subcommands and trailing arguments are rejected.
|
|
105
|
-
The standard palette picker owns navigation and cleanup
|
|
100
|
+
The standard palette picker owns navigation and cleanup; pi-statusline owns footer previews, settings, and rollback.
|
|
106
101
|
The width-aware layout editor and JSON editor remain specialized UI.
|
|
107
102
|
|
|
108
103
|
## ๐ Runtime behavior
|
|
@@ -125,12 +120,14 @@ If the last remaining segment is itself wider than the row, that row renders emp
|
|
|
125
120
|
- `cwd` uses Starship's directory presentation defaults: contract the home directory to `~`, contract to the Git repository root when available, then retain at most the last three path components.
|
|
126
121
|
This changes display only; the configured segment list and Pi working directory are untouched.
|
|
127
122
|
- Repository-root discovery is cached with Git status outside footer rendering; a failed root query falls back to home/path-component contraction without hiding the segment.
|
|
128
|
-
- During active work, `tools` shows `๐ญ thinking
|
|
123
|
+
- During active work, `tools` shows `โจ waiting for <kind>`, `๐ญ thinking`, or `โ๏ธ <tool>` with parallel counts.
|
|
124
|
+
- A sanitized prompt title follows the prompt kind when available.
|
|
125
|
+
- Prompt waiting takes precedence without losing the underlying tool or streaming state, which returns when the prompt closes.
|
|
129
126
|
- Activity disappears after the agent settles and resets across session replacement or shutdown.
|
|
130
127
|
- Clean repositories show no Git counters.
|
|
131
128
|
- Dirty counters are `โก` ahead, `โฃ` behind, `+` staged, `~` modified/deleted, `?` untracked, and `!`
|
|
132
129
|
conflicts.
|
|
133
|
-
- A linked GitHub PR appears with the branch when possible, avoiding a duplicate extension status.
|
|
130
|
+
- A linked or plain GitHub PR reference appears with the branch when possible, avoiding a duplicate extension status.
|
|
134
131
|
- Context color changes to warning at 70% and error at 90%.
|
|
135
132
|
- Git state is cached outside footer rendering and stale session results are ignored.
|
|
136
133
|
|
|
@@ -155,7 +152,7 @@ The extension uses one user-level file:
|
|
|
155
152
|
```
|
|
156
153
|
|
|
157
154
|
There are no project or environment overrides.
|
|
158
|
-
When the file is absent, pi-statusline uses
|
|
155
|
+
When the file is absent, pi-statusline uses built-in defaults without creating the file or its parent directory.
|
|
159
156
|
The first successful settings save creates a complete editable document atomically.
|
|
160
157
|
Malformed or unreadable settings are never overwritten.
|
|
161
158
|
Settings reload on startup, `/reload`, and session replacement.
|
|
@@ -177,8 +174,8 @@ If both files exist, `pi-statusline.json` wins.
|
|
|
177
174
|
|
|
178
175
|
All fields are optional in an existing document.
|
|
179
176
|
Missing fields use defaults.
|
|
180
|
-
|
|
181
|
-
Invalid recognized values block saving
|
|
177
|
+
Menu saves warn about and preserve unknown fields.
|
|
178
|
+
Invalid recognized values block saving and leave the file and live footer unchanged.
|
|
182
179
|
|
|
183
180
|
A compact customization example:
|
|
184
181
|
|
|
@@ -229,6 +226,7 @@ When `palettePreset` is `custom`, `palette` maps segment names to foreground/bac
|
|
|
229
226
|
- Legacy string palettes such as `"palette": "ocean"` remain accepted.
|
|
230
227
|
- Missing custom colors remain unstyled instead of inheriting Tokyo Night.
|
|
231
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.
|
|
232
230
|
|
|
233
231
|
`segmentText` values must be single-line text without terminal control characters.
|
|
234
232
|
Use `line_break` for another row rather than inserting a newline into a prefix or suffix.
|
|
@@ -260,7 +258,8 @@ The direction names the removed portion:
|
|
|
260
258
|
Truncation runs after the built-in Claude/GPT shortening rules but before the configured model prefix and suffix.
|
|
261
259
|
It changes display onlyโthe provider model ID is untouched.
|
|
262
260
|
Terminal control sequences in model IDs are removed at render time, and unsafe configured symbols are rejected.
|
|
263
|
-
An empty `truncationSymbol` truncates without a marker.
|
|
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.
|
|
264
263
|
At very narrow widths, the existing responsive priorities may still omit the model rather than overflow the terminal.
|
|
265
264
|
|
|
266
265
|
## ๐งฉ Advanced layout
|
|
@@ -280,7 +279,8 @@ Open **Advanced โ Custom layout** when the curated levels are not enough.
|
|
|
280
279
|
| Ctrl+C | Close the screen immediately, including from Move mode |
|
|
281
280
|
|
|
282
281
|
The layout displays the effective Back key and keeps Ctrl+C available when Back is remapped.
|
|
283
|
-
Every successful change saves and applies immediately
|
|
282
|
+
Every successful change saves and applies immediately.
|
|
283
|
+
Closing the screen does not roll it back.
|
|
284
284
|
|
|
285
285
|
Available data segments:
|
|
286
286
|
|
|
@@ -301,12 +301,11 @@ Manually authored leading/trailing breaks represent empty rows.
|
|
|
301
301
|
```
|
|
302
302
|
|
|
303
303
|
An empty `segments` array hides the main powerline while extension statuses can still render.
|
|
304
|
-
The extension intentionally has no variable or format language; use `pi-starship` when you need one.
|
|
305
304
|
|
|
306
305
|
## ๐ Extension statuses and icons
|
|
307
306
|
|
|
308
307
|
Other extension statuses appear below the main powerline, wrap to terminal width, and are limited to five items.
|
|
309
|
-
Icons
|
|
308
|
+
Icons use this order:
|
|
310
309
|
|
|
311
310
|
1. Exact configured raw key, such as `goal` or `foo:server`.
|
|
312
311
|
2. Longest configured colon wildcard, such as `foo:*` or `foo:server:*`.
|
|
@@ -327,11 +326,17 @@ For interoperable extensions, prefer one aggregated key or a stable coexistence
|
|
|
327
326
|
<extension-id>:<stable-slot>
|
|
328
327
|
```
|
|
329
328
|
|
|
330
|
-
Put transient activity in the value and
|
|
329
|
+
Put transient activity in the value, and clear the exact key that was set.
|
|
330
|
+
|
|
331
|
+
## ๐ง Limitations
|
|
332
|
+
|
|
333
|
+
- The footer needs Powerline glyphs and emoji for its intended appearance.
|
|
334
|
+
- Pi does not arbitrate footer ownership, so another footer extension can replace pi-statusline.
|
|
335
|
+
- Custom layouts support ordered segments and line breaks, not a variable or format language.
|
|
331
336
|
|
|
332
337
|
## ๐ ๏ธ Troubleshooting
|
|
333
338
|
|
|
334
|
-
- **Powerline symbols look wrong:** use a font with Powerline glyphs
|
|
339
|
+
- **Powerline symbols look wrong:** use a font with Powerline glyphs and emoji support.
|
|
335
340
|
- **The footer reports settings warnings:** run `/statusline status`, then `/statusline settings` to fix invalid recognized fields.
|
|
336
341
|
- **The footer appears to be replaced:** disable `pi-starship` or another extension that also calls Pi's `setFooter()`.
|
|
337
342
|
- **A custom segment disappears on a narrow terminal:** check the responsive priority above or add an explicit `line_break`.
|
package/dist/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { homedir } from "node:os";
|
|
|
16
16
|
import {
|
|
17
17
|
getAgentDir as getAgentDir2
|
|
18
18
|
} from "@earendil-works/pi-coding-agent";
|
|
19
|
+
import { getCapabilities } from "@earendil-works/pi-tui";
|
|
19
20
|
|
|
20
21
|
// src/extension-status.ts
|
|
21
22
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -27,17 +28,21 @@ import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
|
27
28
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
28
29
|
|
|
29
30
|
// src/ansi.ts
|
|
30
|
-
function ansiStyle(text, colors) {
|
|
31
|
+
function ansiStyle(text, colors, trueColor = true) {
|
|
31
32
|
const codes = [
|
|
32
|
-
colors.fg ?
|
|
33
|
-
colors.bg ?
|
|
33
|
+
colors.fg ? colorCode("38", colors.fg, trueColor) : void 0,
|
|
34
|
+
colors.bg ? colorCode("48", colors.bg, trueColor) : void 0
|
|
34
35
|
].filter((code) => code !== void 0);
|
|
35
36
|
if (codes.length === 0) return text;
|
|
36
37
|
return `\x1B[${codes.join(";")}m${text}\x1B[0m`;
|
|
37
38
|
}
|
|
38
|
-
function
|
|
39
|
+
function colorCode(prefix, hex, trueColor) {
|
|
39
40
|
const { red, green, blue } = hexToRgb(hex);
|
|
40
|
-
return `${prefix};2;${red};${green};${blue}`;
|
|
41
|
+
return trueColor ? `${prefix};2;${red};${green};${blue}` : `${prefix};5;${rgbToAnsi256(red, green, blue)}`;
|
|
42
|
+
}
|
|
43
|
+
function rgbToAnsi256(red, green, blue) {
|
|
44
|
+
const channels = [red, green, blue].map((value) => Math.round(value / 255 * 5));
|
|
45
|
+
return 16 + 36 * (channels[0] ?? 0) + 6 * (channels[1] ?? 0) + (channels[2] ?? 0);
|
|
41
46
|
}
|
|
42
47
|
function hexToRgb(hex) {
|
|
43
48
|
const normalized = hex.replace(/^#/, "");
|
|
@@ -49,9 +54,9 @@ function hexToRgb(hex) {
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
// src/powerline.ts
|
|
52
|
-
function renderPowerlineStatusline(width, items, config) {
|
|
57
|
+
function renderPowerlineStatusline(width, items, config, trueColor = true) {
|
|
53
58
|
if (items.length === 0 || width <= 0) return "";
|
|
54
|
-
return splitLines(items).map((segments) => fitPowerlineSegments(segments, width, config)).join("\n");
|
|
59
|
+
return splitLines(items).map((segments) => fitPowerlineSegments(segments, width, config, trueColor)).join("\n");
|
|
55
60
|
}
|
|
56
61
|
function splitLines(items) {
|
|
57
62
|
const lines = [[]];
|
|
@@ -76,11 +81,11 @@ var SEGMENT_RETENTION_PRIORITY = {
|
|
|
76
81
|
turn: 20,
|
|
77
82
|
brand: 10
|
|
78
83
|
};
|
|
79
|
-
function fitPowerlineSegments(segments, width, config) {
|
|
84
|
+
function fitPowerlineSegments(segments, width, config, trueColor) {
|
|
80
85
|
if (segments.length === 0) return "";
|
|
81
86
|
const fitted = [...segments];
|
|
82
87
|
while (fitted.length > 1) {
|
|
83
|
-
const rendered2 = joinPowerlineSegments(fitted, config);
|
|
88
|
+
const rendered2 = joinPowerlineSegments(fitted, config, trueColor);
|
|
84
89
|
if (visibleWidth(rendered2) <= width) return rendered2;
|
|
85
90
|
let removalIndex = 0;
|
|
86
91
|
for (let index = 1; index < fitted.length; index += 1) {
|
|
@@ -92,23 +97,25 @@ function fitPowerlineSegments(segments, width, config) {
|
|
|
92
97
|
}
|
|
93
98
|
fitted.splice(removalIndex, 1);
|
|
94
99
|
}
|
|
95
|
-
const rendered = joinPowerlineSegments(fitted, config);
|
|
100
|
+
const rendered = joinPowerlineSegments(fitted, config, trueColor);
|
|
96
101
|
return visibleWidth(rendered) <= width ? rendered : "";
|
|
97
102
|
}
|
|
98
|
-
function powerlineExtensionSeparator(_theme, palettePreset = "tokyo-night") {
|
|
99
|
-
return ansiStyle(" \u2022 ", { fg: resolvePreset(palettePreset).extensionSeparator });
|
|
103
|
+
function powerlineExtensionSeparator(_theme, palettePreset = "tokyo-night", trueColor = true) {
|
|
104
|
+
return ansiStyle(" \u2022 ", { fg: resolvePreset(palettePreset).extensionSeparator }, trueColor);
|
|
100
105
|
}
|
|
101
|
-
function joinPowerlineSegments(segments, config) {
|
|
106
|
+
function joinPowerlineSegments(segments, config, trueColor) {
|
|
102
107
|
const preset = resolvePreset(config.palettePreset);
|
|
103
108
|
const blocks = contiguousBlocks(segments, preset, config.palettePreset, config.palette);
|
|
104
|
-
let line = ansiStyle("\u2591\u2592\u2593", { fg: preset.lead });
|
|
109
|
+
let line = ansiStyle("\u2591\u2592\u2593", { fg: preset.lead }, trueColor);
|
|
105
110
|
for (const [index, block] of blocks.entries()) {
|
|
106
111
|
const previous = index === 0 ? void 0 : blocks[index - 1]?.colors;
|
|
107
|
-
if (previous)
|
|
108
|
-
|
|
112
|
+
if (previous) {
|
|
113
|
+
line += ansiStyle("\uE0B4", { fg: previous.bg, bg: block.colors.bg }, trueColor);
|
|
114
|
+
}
|
|
115
|
+
line += ansiStyle(formatBlockText(block, config), block.colors, trueColor);
|
|
109
116
|
}
|
|
110
117
|
const lastBlock = blocks.at(-1);
|
|
111
|
-
if (lastBlock) line += ansiStyle("\uE0B4", { fg: lastBlock.colors.bg });
|
|
118
|
+
if (lastBlock) line += ansiStyle("\uE0B4", { fg: lastBlock.colors.bg }, trueColor);
|
|
112
119
|
return line;
|
|
113
120
|
}
|
|
114
121
|
function contiguousBlocks(segments, preset, palettePreset, configuredPalette) {
|
|
@@ -161,11 +168,11 @@ var COMPATIBLE_STATUS_ICON_KEYS = {
|
|
|
161
168
|
pisync: "sync"
|
|
162
169
|
};
|
|
163
170
|
var EMPTY_EXTENSION_STATUS_ICON_ALIASES = /* @__PURE__ */ new Map();
|
|
164
|
-
function extensionStatusSeparator(config, theme) {
|
|
165
|
-
return powerlineExtensionSeparator(theme, config.palettePreset);
|
|
171
|
+
function extensionStatusSeparator(config, theme, trueColor) {
|
|
172
|
+
return powerlineExtensionSeparator(theme, config.palettePreset, trueColor);
|
|
166
173
|
}
|
|
167
|
-
function formatExtensionStatuses(statuses, theme, config, runtime, hiddenKeys = /* @__PURE__ */ new Set()) {
|
|
168
|
-
const separator = extensionStatusSeparator(config, theme);
|
|
174
|
+
function formatExtensionStatuses(statuses, theme, config, runtime, hiddenKeys = /* @__PURE__ */ new Set(), trueColor = true) {
|
|
175
|
+
const separator = extensionStatusSeparator(config, theme, trueColor);
|
|
169
176
|
const visibleStatuses = [
|
|
170
177
|
...formatDuplicateExtensionStatus(runtime, theme),
|
|
171
178
|
...[...statuses.entries()].filter(
|
|
@@ -463,6 +470,7 @@ function formatCount(value) {
|
|
|
463
470
|
}
|
|
464
471
|
|
|
465
472
|
// src/render.ts
|
|
473
|
+
import { sliceByColumn, visibleWidth as visibleWidth2 } from "@earendil-works/pi-tui";
|
|
466
474
|
import { sanitizeTerminalText as sanitizeTerminalText2 } from "@narumitw/pi-tui-kit/terminal-text";
|
|
467
475
|
|
|
468
476
|
// src/directory.ts
|
|
@@ -539,7 +547,7 @@ function summarizeFooterUsage(entries) {
|
|
|
539
547
|
// src/render.ts
|
|
540
548
|
var GITHUB_PR_KEY = "github-pr";
|
|
541
549
|
var GITHUB_PR_STATUS_KEYS = /* @__PURE__ */ new Set([GITHUB_PR_KEY]);
|
|
542
|
-
function renderStatusline(width, ctx, footerData, _theme, config, runtime) {
|
|
550
|
+
function renderStatusline(width, ctx, footerData, _theme, config, runtime, trueColor = true) {
|
|
543
551
|
if (width <= 0) return "";
|
|
544
552
|
const usageSummary = summarizeFooterUsage(ctx.sessionManager.getEntries());
|
|
545
553
|
const rows = [
|
|
@@ -564,9 +572,9 @@ function renderStatusline(width, ctx, footerData, _theme, config, runtime) {
|
|
|
564
572
|
if (index > 0) segments.push({ name: LINE_BREAK_SEGMENT_NAME });
|
|
565
573
|
segments.push(...row.segments);
|
|
566
574
|
}
|
|
567
|
-
return renderPowerlineStatusline(width, segments, config);
|
|
575
|
+
return renderPowerlineStatusline(width, segments, config, trueColor);
|
|
568
576
|
}
|
|
569
|
-
function renderExtensionStatusline(width, footerData, theme, config, runtime, mainLine) {
|
|
577
|
+
function renderExtensionStatusline(width, footerData, theme, config, runtime, mainLine, trueColor = true) {
|
|
570
578
|
const statuses = footerData.getExtensionStatuses();
|
|
571
579
|
const prContext = prContextFromStatuses(statuses);
|
|
572
580
|
const rendersPrInline = prContext !== void 0 && mainLine.includes(prContext);
|
|
@@ -575,7 +583,8 @@ function renderExtensionStatusline(width, footerData, theme, config, runtime, ma
|
|
|
575
583
|
theme,
|
|
576
584
|
config,
|
|
577
585
|
runtime,
|
|
578
|
-
rendersPrInline ? GITHUB_PR_STATUS_KEYS : void 0
|
|
586
|
+
rendersPrInline ? GITHUB_PR_STATUS_KEYS : void 0,
|
|
587
|
+
trueColor
|
|
579
588
|
);
|
|
580
589
|
return wrapExtensionStatusline(status, width);
|
|
581
590
|
}
|
|
@@ -701,12 +710,36 @@ function contextColor(percent) {
|
|
|
701
710
|
if (percent >= 70) return "warning";
|
|
702
711
|
return "success";
|
|
703
712
|
}
|
|
713
|
+
var MAX_UI_PROMPT_TITLE_CODE_POINTS = 256;
|
|
714
|
+
var MAX_UI_PROMPT_TITLE_WIDTH = 40;
|
|
715
|
+
function boundUIPromptTitleLength(title) {
|
|
716
|
+
let end = 0;
|
|
717
|
+
let ellipsisEnd = 0;
|
|
718
|
+
let codePoints = 0;
|
|
719
|
+
while (end < title.length && codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) {
|
|
720
|
+
const codePoint = title.codePointAt(end) ?? 0;
|
|
721
|
+
end += codePoint > 65535 ? 2 : 1;
|
|
722
|
+
codePoints += 1;
|
|
723
|
+
if (codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) ellipsisEnd = end;
|
|
724
|
+
}
|
|
725
|
+
return end < title.length ? `${title.slice(0, ellipsisEnd)}\u2026` : title;
|
|
726
|
+
}
|
|
727
|
+
function formatUIPromptTitle(title) {
|
|
728
|
+
const safeTitle = title ? sanitizeTerminalText2(title).trim() : "";
|
|
729
|
+
const boundedTitle = boundUIPromptTitleLength(safeTitle);
|
|
730
|
+
if (visibleWidth2(boundedTitle) <= MAX_UI_PROMPT_TITLE_WIDTH) return boundedTitle;
|
|
731
|
+
return `${sliceByColumn(boundedTitle, 0, MAX_UI_PROMPT_TITLE_WIDTH - 1, true)}\u2026`;
|
|
732
|
+
}
|
|
704
733
|
function formatToolActivity(runtime) {
|
|
734
|
+
if (runtime.uiPrompt) {
|
|
735
|
+
const title = formatUIPromptTitle(runtime.uiPrompt.title);
|
|
736
|
+
return `\u2328 waiting for ${runtime.uiPrompt.kind}${title ? ` \xB7 ${title}` : ""}`;
|
|
737
|
+
}
|
|
705
738
|
const active = [...runtime.activeTools.entries()];
|
|
706
739
|
if (active.length > 0) {
|
|
707
740
|
const [name, count] = active[0] ?? ["tool", 1];
|
|
708
741
|
const suffix = count > 1 ? `\xD7${count}` : active.length > 1 ? `+${active.length - 1}` : "";
|
|
709
|
-
return `\u2699 ${name}${suffix}`;
|
|
742
|
+
return `\u2699\uFE0F ${name}${suffix}`;
|
|
710
743
|
}
|
|
711
744
|
return runtime.isStreaming ? "\u{1F4AD} thinking" : void 0;
|
|
712
745
|
}
|
|
@@ -721,10 +754,15 @@ function prLinkFromStatuses(statuses) {
|
|
|
721
754
|
}
|
|
722
755
|
function prContextFromStatuses(statuses) {
|
|
723
756
|
const value = statuses.get(GITHUB_PR_KEY);
|
|
757
|
+
if (!value) return void 0;
|
|
724
758
|
const link = prLinkFromStatuses(statuses);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
759
|
+
const reference = link ?? plainPrReference(value);
|
|
760
|
+
if (!reference) return void 0;
|
|
761
|
+
const state = compactPrState(link ? value.replace(link, "") : value);
|
|
762
|
+
return state ? `${reference} \xB7 ${state}` : void 0;
|
|
763
|
+
}
|
|
764
|
+
function plainPrReference(value) {
|
|
765
|
+
return /^PR\s+(#\d+):/u.exec(value)?.[1];
|
|
728
766
|
}
|
|
729
767
|
function compactPrState(value) {
|
|
730
768
|
if (/:\s*merged\s*$/.test(value)) return "merged";
|
|
@@ -927,10 +965,27 @@ function statusline(pi) {
|
|
|
927
965
|
render(width) {
|
|
928
966
|
if (!loaded) return [];
|
|
929
967
|
const config = previewPalettePreset ? { ...loaded.config, palettePreset: previewPalettePreset } : loaded.config;
|
|
930
|
-
const
|
|
968
|
+
const trueColor = getCapabilities().trueColor;
|
|
969
|
+
const mainLine = renderStatusline(
|
|
970
|
+
width,
|
|
971
|
+
ctx,
|
|
972
|
+
footerData,
|
|
973
|
+
theme,
|
|
974
|
+
config,
|
|
975
|
+
runtime,
|
|
976
|
+
trueColor
|
|
977
|
+
);
|
|
931
978
|
const lines = mainLine ? mainLine.split("\n") : [];
|
|
932
979
|
lines.push(
|
|
933
|
-
...renderExtensionStatusline(
|
|
980
|
+
...renderExtensionStatusline(
|
|
981
|
+
width,
|
|
982
|
+
footerData,
|
|
983
|
+
theme,
|
|
984
|
+
config,
|
|
985
|
+
runtime,
|
|
986
|
+
mainLine,
|
|
987
|
+
trueColor
|
|
988
|
+
)
|
|
934
989
|
);
|
|
935
990
|
return lines;
|
|
936
991
|
}
|
|
@@ -975,6 +1030,7 @@ function statusline(pi) {
|
|
|
975
1030
|
runtime.turnCount = 0;
|
|
976
1031
|
runtime.activeTools.clear();
|
|
977
1032
|
runtime.isStreaming = false;
|
|
1033
|
+
runtime.uiPrompt = void 0;
|
|
978
1034
|
loaded = loadStatuslineSettingsForAgent(agentDir);
|
|
979
1035
|
const settingsNotice = consumeStatuslineSettingsNotice();
|
|
980
1036
|
if (settingsNotice) ctx.ui.notify(settingsNotice, "warning");
|
|
@@ -1001,6 +1057,7 @@ function statusline(pi) {
|
|
|
1001
1057
|
runtime.gitStatus = void 0;
|
|
1002
1058
|
runtime.activeTools.clear();
|
|
1003
1059
|
runtime.isStreaming = false;
|
|
1060
|
+
runtime.uiPrompt = void 0;
|
|
1004
1061
|
runtime.duplicateExtensions = [];
|
|
1005
1062
|
runtime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES2;
|
|
1006
1063
|
ctx.ui.setFooter(void 0);
|
|
@@ -1029,6 +1086,16 @@ function statusline(pi) {
|
|
|
1029
1086
|
runtime.activeTools.clear();
|
|
1030
1087
|
refresh();
|
|
1031
1088
|
});
|
|
1089
|
+
pi.on("ui_prompt_start", (event, ctx) => {
|
|
1090
|
+
if (!ownsRuntime(ctx)) return;
|
|
1091
|
+
runtime.uiPrompt = { kind: event.kind, title: event.title };
|
|
1092
|
+
refresh();
|
|
1093
|
+
});
|
|
1094
|
+
pi.on("ui_prompt_end", (_event, ctx) => {
|
|
1095
|
+
if (!ownsRuntime(ctx)) return;
|
|
1096
|
+
runtime.uiPrompt = void 0;
|
|
1097
|
+
refresh();
|
|
1098
|
+
});
|
|
1032
1099
|
pi.on("turn_start", (_event, ctx) => {
|
|
1033
1100
|
if (!ownsRuntime(ctx)) return;
|
|
1034
1101
|
runtime.turnCount += 1;
|
package/dist/index.ts.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/statusline.ts", "../src/extension-status.ts", "../src/powerline.ts", "../src/ansi.ts", "../src/git-status.ts", "../src/render.ts", "../src/directory.ts", "../src/usage.ts"],
|
|
4
|
-
"sourcesContent": ["import { homedir } from \"node:os\";\nimport {\n\ttype ExtensionAPI,\n\ttype ExtensionContext,\n\tgetAgentDir,\n} from \"@earendil-works/pi-coding-agent\";\nimport { completeStatuslineArguments } from \"./command-contract.js\";\nimport type { StatuslineCommandOptions } from \"./commands.js\";\nimport {\n\tbuildExtensionStatusIconAliases,\n\ttype ExtensionStatusIconAliasMap,\n\tfindDuplicateExtensions,\n\treadInstalledExtensionPackages,\n} from \"./extension-status.js\";\nimport { type GitStatusSummary, gitStatusSummaryEqual, readGitStatus } from \"./git-status.js\";\nimport { type RuntimeState, renderExtensionStatusline, renderStatusline } from \"./render.js\";\nimport {\n\tconsumeStatuslineSettingsNotice,\n\ttype LoadedStatuslineSettings,\n\tloadStatuslineSettings,\n\tloadStatuslineSettingsForAgent,\n\tsettingsFilePath,\n} from \"./settings.js\";\nimport type { PalettePreset } from \"./types.js\";\n\nconst STATUSLINE_KEY = \"statusline\";\nconst GIT_STATUS_REFRESH_INTERVAL_MS = 30_000;\nconst GIT_STATUS_EVENT_DEBOUNCE_MS = 250;\nconst EMPTY_EXTENSION_STATUS_ICON_ALIASES: ExtensionStatusIconAliasMap = new Map();\n\ntype StatuslineCommands = typeof import(\"./commands.js\");\nlet statuslineCommandsPromise: Promise<StatuslineCommands> | undefined;\n\nfunction loadStatuslineCommands(): Promise<StatuslineCommands> {\n\tif (!statuslineCommandsPromise) {\n\t\tstatuslineCommandsPromise = import(\"./commands.js\").catch((error) => {\n\t\t\tstatuslineCommandsPromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t}\n\treturn statuslineCommandsPromise;\n}\n\nexport default function statusline(pi: ExtensionAPI) {\n\tlet loaded: LoadedStatuslineSettings | undefined;\n\tlet previewPalettePreset: PalettePreset | undefined;\n\tlet activeSessionManager: ExtensionContext[\"sessionManager\"] | undefined;\n\tconst runtime: RuntimeState = {\n\t\tturnCount: 0,\n\t\tactiveTools: new Map(),\n\t\tisStreaming: false,\n\t\tthinkingLevel: \"off\",\n\t\tduplicateExtensions: [],\n\t\textensionStatusIconAliases: EMPTY_EXTENSION_STATUS_ICON_ALIASES,\n\t};\n\n\tlet sessionGeneration = 0;\n\tlet menuController = new AbortController();\n\tlet gitStatusRequestId = 0;\n\tlet activeGitStatusTarget: { cwd: string; generation: number } | undefined;\n\tlet gitStatusRefreshInFlight = false;\n\tlet gitStatusAbortController: AbortController | undefined;\n\tlet gitStatusDebounceTimer: ReturnType<typeof setTimeout> | undefined;\n\tlet pendingGitStatusRefresh: { cwd: string; generation: number; requestId: number } | undefined;\n\n\tconst refresh = () => runtime.requestRender?.();\n\tconst ownsRuntime = (ctx: ExtensionContext) => ctx.sessionManager === activeSessionManager;\n\n\tconst setGitStatus = (summary: GitStatusSummary | undefined) => {\n\t\tif (gitStatusSummaryEqual(runtime.gitStatus, summary)) return;\n\t\truntime.gitStatus = summary;\n\t\trefresh();\n\t};\n\n\tconst clearGitStatusDebounce = () => {\n\t\tif (!gitStatusDebounceTimer) return;\n\t\tclearTimeout(gitStatusDebounceTimer);\n\t\tgitStatusDebounceTimer = undefined;\n\t};\n\n\tconst abortGitStatusRefresh = (reason: string) => {\n\t\tgitStatusAbortController?.abort(new DOMException(reason, \"AbortError\"));\n\t};\n\n\tconst isActiveGitStatusTarget = (cwd: string, generation: number) =>\n\t\tactiveGitStatusTarget?.cwd === cwd &&\n\t\tactiveGitStatusTarget.generation === generation &&\n\t\tgeneration === sessionGeneration;\n\n\tconst isCurrentGitStatusRequest = (cwd: string, generation: number, requestId: number) =>\n\t\tisActiveGitStatusTarget(cwd, generation) && requestId === gitStatusRequestId;\n\n\tconst runGitStatusRefresh = (cwd: string, generation: number, requestId: number) => {\n\t\tif (!isCurrentGitStatusRequest(cwd, generation, requestId)) return;\n\t\tif (gitStatusRefreshInFlight) {\n\t\t\tpendingGitStatusRefresh = { cwd, generation, requestId };\n\t\t\treturn;\n\t\t}\n\n\t\tgitStatusRefreshInFlight = true;\n\t\tconst abortController = new AbortController();\n\t\tgitStatusAbortController = abortController;\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst summary = await readGitStatus(pi, cwd, abortController.signal);\n\t\t\t\tif (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(summary);\n\t\t\t} catch {\n\t\t\t\tif (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(undefined);\n\t\t\t} finally {\n\t\t\t\tgitStatusRefreshInFlight = false;\n\t\t\t\tif (gitStatusAbortController === abortController) gitStatusAbortController = undefined;\n\t\t\t\tconst pending = pendingGitStatusRefresh;\n\t\t\t\tpendingGitStatusRefresh = undefined;\n\t\t\t\tif (pending) runGitStatusRefresh(pending.cwd, pending.generation, pending.requestId);\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst refreshGitStatus = (cwd: string, generation = sessionGeneration) => {\n\t\tif (!isActiveGitStatusTarget(cwd, generation)) return;\n\t\trunGitStatusRefresh(cwd, generation, ++gitStatusRequestId);\n\t};\n\n\tconst scheduleGitStatusRefresh = (cwd: string, generation = sessionGeneration) => {\n\t\tif (!isActiveGitStatusTarget(cwd, generation)) return;\n\t\tconst requestId = ++gitStatusRequestId;\n\t\tclearGitStatusDebounce();\n\t\tgitStatusDebounceTimer = setTimeout(() => {\n\t\t\tgitStatusDebounceTimer = undefined;\n\t\t\trunGitStatusRefresh(cwd, generation, requestId);\n\t\t}, GIT_STATUS_EVENT_DEBOUNCE_MS);\n\t};\n\n\tconst scheduleGitStatusRefreshForContext = (ctx: ExtensionContext) => {\n\t\tif (!activeGitStatusTarget || activeGitStatusTarget.cwd !== ctx.cwd) return;\n\t\tscheduleGitStatusRefresh(activeGitStatusTarget.cwd, activeGitStatusTarget.generation);\n\t};\n\n\tconst installFooter = (ctx: ExtensionContext) => {\n\t\tconst generation = ++sessionGeneration;\n\t\tmenuController.abort(new DOMException(\"Statusline session context replaced\", \"AbortError\"));\n\t\tmenuController = new AbortController();\n\t\tconst cwd = ctx.cwd;\n\t\tactiveSessionManager = ctx.sessionManager;\n\t\truntime.homeDir = homedir();\n\t\tpreviewPalettePreset = undefined;\n\t\tabortGitStatusRefresh(\"Statusline session context replaced\");\n\t\tclearGitStatusDebounce();\n\t\tactiveGitStatusTarget = ctx.mode === \"tui\" ? { cwd, generation } : undefined;\n\t\truntime.gitStatus = undefined;\n\t\truntime.duplicateExtensions = [];\n\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\tctx.ui.setStatus(STATUSLINE_KEY, undefined);\n\t\tif (!activeGitStatusTarget || !loaded) return;\n\t\tconst installedPackages = readInstalledExtensionPackages(cwd);\n\t\truntime.duplicateExtensions = findDuplicateExtensions(installedPackages);\n\t\truntime.extensionStatusIconAliases = buildExtensionStatusIconAliases(installedPackages);\n\t\tctx.ui.setFooter((tui, theme, footerData) => {\n\t\t\truntime.requestRender = () => tui.requestRender();\n\n\t\t\tconst refreshFooterGitStatus = () => refreshGitStatus(cwd, generation);\n\t\t\tconst branchUnsubscribe = footerData.onBranchChange(() => {\n\t\t\t\truntime.gitStatus = undefined;\n\t\t\t\tabortGitStatusRefresh(\"Statusline Git branch changed\");\n\t\t\t\tclearGitStatusDebounce();\n\t\t\t\trefreshFooterGitStatus();\n\t\t\t\ttui.requestRender();\n\t\t\t});\n\t\t\tconst clock = setInterval(() => {\n\t\t\t\tclearGitStatusDebounce();\n\t\t\t\trefreshFooterGitStatus();\n\t\t\t\ttui.requestRender();\n\t\t\t}, GIT_STATUS_REFRESH_INTERVAL_MS);\n\n\t\t\treturn {\n\t\t\t\tdispose() {\n\t\t\t\t\tbranchUnsubscribe();\n\t\t\t\t\tclearInterval(clock);\n\t\t\t\t\tif (isActiveGitStatusTarget(cwd, generation)) {\n\t\t\t\t\t\tactiveGitStatusTarget = undefined;\n\t\t\t\t\t\tabortGitStatusRefresh(\"Statusline footer disposed\");\n\t\t\t\t\t\tclearGitStatusDebounce();\n\t\t\t\t\t\tpendingGitStatusRefresh = undefined;\n\t\t\t\t\t\truntime.gitStatus = undefined;\n\t\t\t\t\t\truntime.duplicateExtensions = [];\n\t\t\t\t\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\t\t\t\t\truntime.requestRender = undefined;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tinvalidate() {},\n\t\t\t\trender(width: number): string[] {\n\t\t\t\t\tif (!loaded) return [];\n\t\t\t\t\tconst config = previewPalettePreset\n\t\t\t\t\t\t? { ...loaded.config, palettePreset: previewPalettePreset }\n\t\t\t\t\t\t: loaded.config;\n\t\t\t\t\tconst mainLine = renderStatusline(width, ctx, footerData, theme, config, runtime);\n\t\t\t\t\tconst lines = mainLine ? mainLine.split(\"\\n\") : [];\n\t\t\t\t\tlines.push(\n\t\t\t\t\t\t...renderExtensionStatusline(width, footerData, theme, config, runtime, mainLine),\n\t\t\t\t\t);\n\t\t\t\t\treturn lines;\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t\trefreshGitStatus(cwd, generation);\n\t};\n\n\tconst agentDir = getAgentDir();\n\tconst configPath = settingsFilePath(agentDir);\n\tconst commandOptions: StatuslineCommandOptions = {\n\t\tsettingsPath: configPath,\n\t\tgetLoaded: () => loaded ?? loadStatuslineSettings(configPath),\n\t\tgetMenuOwner: () => {\n\t\t\tconst generation = sessionGeneration;\n\t\t\treturn {\n\t\t\t\tsignal: menuController.signal,\n\t\t\t\tisCurrent: () => generation === sessionGeneration && !menuController.signal.aborted,\n\t\t\t};\n\t\t},\n\t\tapply(next, ctx) {\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tpreviewPalettePreset = undefined;\n\t\t\tloaded = next;\n\t\t\trefresh();\n\t\t},\n\t\tpreview(palettePreset, ctx) {\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tpreviewPalettePreset = palettePreset;\n\t\t\trefresh();\n\t\t},\n\t};\n\tpi.registerCommand(\"statusline\", {\n\t\tdescription: \"Open or inspect the statusline settings\",\n\t\tgetArgumentCompletions: completeStatuslineArguments,\n\t\thandler: async (args, ctx) => {\n\t\t\tconst commands = await loadStatuslineCommands();\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tawait commands.handleStatuslineCommand(args, ctx, commandOptions);\n\t\t},\n\t});\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\truntime.turnCount = 0;\n\t\truntime.activeTools.clear();\n\t\truntime.isStreaming = false;\n\t\tloaded = loadStatuslineSettingsForAgent(agentDir);\n\t\tconst settingsNotice = consumeStatuslineSettingsNotice();\n\t\tif (settingsNotice) ctx.ui.notify(settingsNotice, \"warning\");\n\t\tif (loaded.diagnostics.length > 0) {\n\t\t\tctx.ui.notify(formatSettingsDiagnostics(loaded), \"warning\");\n\t\t}\n\t\truntime.thinkingLevel = pi.getThinkingLevel();\n\t\tinstallFooter(ctx);\n\t});\n\n\tpi.on(\"session_tree\", (_event, ctx) => {\n\t\tinstallFooter(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tsessionGeneration += 1;\n\t\tmenuController.abort(new DOMException(\"Statusline session shut down\", \"AbortError\"));\n\t\tactiveSessionManager = undefined;\n\t\tpreviewPalettePreset = undefined;\n\t\tactiveGitStatusTarget = undefined;\n\t\tabortGitStatusRefresh(\"Statusline session shut down\");\n\t\tclearGitStatusDebounce();\n\t\tpendingGitStatusRefresh = undefined;\n\t\truntime.gitStatus = undefined;\n\t\truntime.activeTools.clear();\n\t\truntime.isStreaming = false;\n\t\truntime.duplicateExtensions = [];\n\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\tctx.ui.setFooter(undefined);\n\t\tctx.ui.setStatus(STATUSLINE_KEY, undefined);\n\t\truntime.requestRender = undefined;\n\t});\n\n\tpi.on(\"model_select\", () => refresh());\n\n\tpi.on(\"thinking_level_select\", (event) => {\n\t\truntime.thinkingLevel = event.level;\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_start\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.isStreaming = true;\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_end\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.activeTools.clear();\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_settled\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.isStreaming = false;\n\t\truntime.activeTools.clear();\n\t\trefresh();\n\t});\n\n\tpi.on(\"turn_start\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.turnCount += 1;\n\t\truntime.isStreaming = true;\n\t\trefresh();\n\t});\n\n\tpi.on(\"turn_end\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"tool_execution_start\", (event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tconst currentCount = runtime.activeTools.get(event.toolName) ?? 0;\n\t\truntime.activeTools.set(event.toolName, currentCount + 1);\n\t\trefresh();\n\t});\n\n\tpi.on(\"tool_execution_end\", (event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tconst currentCount = runtime.activeTools.get(event.toolName) ?? 0;\n\t\tif (currentCount <= 1) runtime.activeTools.delete(event.toolName);\n\t\telse runtime.activeTools.set(event.toolName, currentCount - 1);\n\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n}\n\nfunction formatSettingsDiagnostics(loaded: LoadedStatuslineSettings): string {\n\tconst details = loaded.diagnostics.slice(0, 5).map((item) => item.message);\n\tconst remaining = loaded.diagnostics.length - details.length;\n\treturn [\n\t\t`pi-statusline settings: ${details.join(\"; \")}`,\n\t\t...(remaining > 0 ? [`+${remaining} more`] : []),\n\t].join(\" \");\n}\n\nexport {\n\tbuildExtensionStatusIconAliases,\n\ttype ExtensionStatusIconAliasMap,\n\textensionColor,\n\tformatExtensionStatus,\n\tnpmPackageName,\n\tsimplifyExtensionStatusText,\n\tsplitExtensionStatusIcon,\n\tstripExtensionStatusPrefix,\n\twrapExtensionStatusline,\n} from \"./extension-status.js\";\nexport {\n\tformatGitBranchText,\n\tformatGitBranchValue,\n\tformatGitStatusSummary,\n\ttype GitStatusSummary,\n\tparseGitRoot,\n\tparseGitStatusPorcelain,\n\treadGitStatus,\n} from \"./git-status.js\";\nexport {\n\tcontextColor,\n\tformatCount,\n\tformatToolActivity,\n\tprContextFromStatuses,\n\tprLinkFromStatuses,\n\tshortenModel,\n} from \"./render.js\";\nexport { normalizeStatuslineSettings, readStatuslineSettings } from \"./settings.js\";\n", "import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { getAgentDir, type Theme, type ThemeColor } from \"@earendil-works/pi-coding-agent\";\nimport { wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport { powerlineExtensionSeparator } from \"./powerline.js\";\nimport { DEFAULT_EXTENSION_STATUS_ICONS } from \"./settings.js\";\nimport type { StatuslineConfig } from \"./types.js\";\n\nexport type ExtensionStatusIconAliasMap = ReadonlyMap<string, readonly string[]>;\nexport interface ExtensionStatusRuntime {\n\tduplicateExtensions: string[];\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap;\n}\n\nconst STATUSLINE_KEY = \"statusline\";\nconst COMPATIBLE_STATUS_ICON_KEYS: Readonly<Record<string, string>> = {\n\tretry: \"unknown-error-retry\",\n\tsync: \"pisync\",\n\t\"unknown-error-retry\": \"retry\",\n\tpisync: \"sync\",\n};\nconst EMPTY_EXTENSION_STATUS_ICON_ALIASES: ExtensionStatusIconAliasMap = new Map();\nfunction extensionStatusSeparator(config: StatuslineConfig, theme: Theme): string {\n\treturn powerlineExtensionSeparator(theme, config.palettePreset);\n}\n\nexport function formatExtensionStatuses(\n\tstatuses: ReadonlyMap<string, string>,\n\ttheme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: ExtensionStatusRuntime,\n\thiddenKeys: ReadonlySet<string> = new Set(),\n): string {\n\tconst separator = extensionStatusSeparator(config, theme);\n\tconst visibleStatuses = [\n\t\t...formatDuplicateExtensionStatus(runtime, theme),\n\t\t...[...statuses.entries()]\n\t\t\t.filter(\n\t\t\t\t([key, value]) => key !== STATUSLINE_KEY && !hiddenKeys.has(key) && value.trim().length > 0,\n\t\t\t)\n\t\t\t.map(([key, value]) =>\n\t\t\t\tformatExtensionStatus(key, value, theme, config, runtime.extensionStatusIconAliases),\n\t\t\t),\n\t].slice(0, 5);\n\n\treturn visibleStatuses.join(separator);\n}\n\nexport function formatExtensionStatus(\n\tkey: string,\n\tvalue: string,\n\ttheme: Theme,\n\tconfig: Pick<StatuslineConfig, \"extensionStatusIcons\">,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap = EMPTY_EXTENSION_STATUS_ICON_ALIASES,\n): string {\n\tconst status = splitExtensionStatusIcon(stripExtensionStatusPrefix(key, value));\n\tconst text = simplifyExtensionStatusText(status.text);\n\tconst color = extensionColor(key, value);\n\tconst textColor = color === \"warning\" ? \"warning\" : \"muted\";\n\tconst icon = extensionStatusIcon(\n\t\tkey,\n\t\tstatus.icon,\n\t\tconfig.extensionStatusIcons,\n\t\textensionStatusIconAliases,\n\t);\n\tconst renderedText = theme.fg(textColor, text);\n\treturn icon ? `${theme.fg(color, icon)} ${renderedText}` : renderedText;\n}\n\nfunction extensionStatusIcon(\n\tkey: string,\n\tleadingIcon: string | undefined,\n\tconfiguredIcons: Record<string, string>,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap,\n) {\n\tif (Object.hasOwn(configuredIcons, key)) return configuredIcons[key];\n\tconst namespaceIcon = configuredNamespaceIcon(key, configuredIcons);\n\tif (namespaceIcon !== undefined) return namespaceIcon;\n\tconst compatibleKey = COMPATIBLE_STATUS_ICON_KEYS[key];\n\tif (compatibleKey && Object.hasOwn(configuredIcons, compatibleKey)) {\n\t\treturn configuredIcons[compatibleKey];\n\t}\n\tfor (const alias of extensionStatusAliasesForKey(key, extensionStatusIconAliases)) {\n\t\tif (Object.hasOwn(configuredIcons, alias)) return configuredIcons[alias];\n\t}\n\treturn leadingIcon ?? DEFAULT_EXTENSION_STATUS_ICONS[key] ?? \"\uD83D\uDD0C\";\n}\n\nfunction configuredNamespaceIcon(\n\tkey: string,\n\tconfiguredIcons: Readonly<Record<string, string>>,\n): string | undefined {\n\tlet match: { baseLength: number; icon: string } | undefined;\n\tfor (const [selector, icon] of Object.entries(configuredIcons)) {\n\t\tif (!selector.endsWith(\":*\")) continue;\n\t\tconst base = selector.slice(0, -2);\n\t\tif (!base || !key.startsWith(`${base}:`)) continue;\n\t\tif (!match || base.length > match.baseLength) match = { baseLength: base.length, icon };\n\t}\n\treturn match?.icon;\n}\n\nfunction extensionStatusAliasesForKey(\n\tkey: string,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap,\n): readonly string[] {\n\tfor (const [statusBase, aliases] of extensionStatusIconAliases) {\n\t\tif (statusKeyMatchesStatusBase(key, statusBase)) return aliases;\n\t}\n\treturn [];\n}\n\nfunction statusKeyMatchesStatusBase(key: string, statusBase: string): boolean {\n\treturn key === statusBase || key.startsWith(`${statusBase}:`) || key.startsWith(`${statusBase}/`);\n}\n\nexport function wrapExtensionStatusline(status: string, width: number): string[] {\n\tif (!status || width <= 0) return [];\n\treturn wrapTextWithAnsi(status, width);\n}\n\nfunction formatDuplicateExtensionStatus(runtime: ExtensionStatusRuntime, theme: Theme): string[] {\n\tif (runtime.duplicateExtensions.length === 0) return [];\n\tconst names = runtime.duplicateExtensions.slice(0, 2).join(\", \");\n\tconst suffix =\n\t\truntime.duplicateExtensions.length > 2 ? ` +${runtime.duplicateExtensions.length - 2}` : \"\";\n\treturn [`${theme.fg(\"warning\", \"\u26A0\uFE0F\")} ${theme.fg(\"warning\", `dup ${names}${suffix}`)}`];\n}\n\nexport function splitExtensionStatusIcon(value: string): { icon?: string; text: string } {\n\tconst trimmed = value.trim();\n\tconst [firstToken, ...restTokens] = trimmed.split(/\\s+/);\n\tif (firstToken && isEmojiOnlyToken(firstToken)) {\n\t\treturn { icon: firstToken, text: restTokens.join(\" \") };\n\t}\n\treturn { text: trimmed };\n}\n\nfunction isEmojiOnlyToken(value: string): boolean {\n\treturn /^(?=.*(?:\\p{Extended_Pictographic}|\\p{Regional_Indicator}|[0-9#*]\\ufe0f?\\u20e3))(?:\\p{Extended_Pictographic}|\\p{Emoji_Modifier}|\\p{Regional_Indicator}|\\u200d|\\ufe0f|[0-9#*]\\ufe0f?\\u20e3)+$/u.test(\n\t\tvalue,\n\t);\n}\n\nexport function extensionColor(key: string, value: string): ThemeColor {\n\tconst normalized = `${key} ${value}`.toLowerCase();\n\tif (/missing|error|fail|conflict|duplicate|unavailable/.test(normalized)) return \"warning\";\n\tif (normalized.includes(\"codex\")) return \"accent\";\n\tif (/ready|active|running|enabled|awake|ok/.test(normalized)) return \"success\";\n\treturn \"muted\";\n}\n\nexport function stripExtensionStatusPrefix(key: string, value: string): string {\n\treturn value.trim().replace(new RegExp(`^${escapeRegExp(key)}\\\\s*:\\\\s*`, \"iu\"), \"\");\n}\n\nexport function simplifyExtensionStatusText(value: string): string {\n\treturn value\n\t\t.trim()\n\t\t.replace(/\\bready\\b/giu, \"\u2713\")\n\t\t.replace(/\\bmissing\\b/giu, \"\u2717\")\n\t\t.replace(/,\\s*/g, \" \")\n\t\t.replace(/\\s+\\([^)]*\\)\\s*$/, \"\")\n\t\t.replace(/\\s+/g, \" \");\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\ninterface InstalledExtensionPackage {\n\tpackageName: string;\n\tsource: string;\n\tidentity: string;\n}\n\nexport function readInstalledExtensionPackages(cwd: string): InstalledExtensionPackage[] {\n\tconst packages: InstalledExtensionPackage[] = [];\n\tconst settingsFiles = extensionSettingsFiles(cwd);\n\n\tfor (const settingsFile of settingsFiles) {\n\t\tconst baseDirectory = dirname(settingsFile);\n\t\tfor (const rawSource of readPackageSources(settingsFile)) {\n\t\t\tconst source = rawSource.trim();\n\t\t\tif (!source) continue;\n\t\t\tconst packageName = packageNameForSource(source, baseDirectory);\n\t\t\tif (!packageName) continue;\n\t\t\tpackages.push({ packageName, source, identity: sourceIdentity(source, baseDirectory) });\n\t\t}\n\t}\n\n\treturn packages;\n}\n\nfunction extensionSettingsFiles(cwd: string): string[] {\n\treturn [join(getAgentDir(), \"settings.json\"), join(cwd, \".pi\", \"settings.json\")].filter((file) =>\n\t\texistsSync(file),\n\t);\n}\n\nexport function findDuplicateExtensions(\n\tinstalledPackages: readonly InstalledExtensionPackage[],\n): string[] {\n\tconst sourcesByPackage = new Map<string, Set<string>>();\n\n\tfor (const extensionPackage of installedPackages) {\n\t\tconst sources = sourcesByPackage.get(extensionPackage.packageName) ?? new Set<string>();\n\t\tsources.add(extensionPackage.identity);\n\t\tsourcesByPackage.set(extensionPackage.packageName, sources);\n\t}\n\n\treturn [...sourcesByPackage.entries()]\n\t\t.filter(([, sources]) => sources.size > 1)\n\t\t.map(([packageName]) => packageName.replace(/^@[^/]+\\//, \"\").replace(/^pi-/, \"\"));\n}\n\nexport function buildExtensionStatusIconAliases(\n\tinstalledPackages: readonly { packageName: string; source?: string }[],\n): Map<string, string[]> {\n\tconst packageAliasesByStatusBase = new Map<string, Map<string, string[]>>();\n\n\tfor (const extensionPackage of installedPackages) {\n\t\tconst candidate = extensionStatusIconAliasCandidate(\n\t\t\textensionPackage.packageName,\n\t\t\textensionPackage.source,\n\t\t);\n\t\tif (!candidate) continue;\n\t\tconst aliasesByPackage =\n\t\t\tpackageAliasesByStatusBase.get(candidate.statusBase) ?? new Map<string, string[]>();\n\t\tconst existingAliases = aliasesByPackage.get(extensionPackage.packageName) ?? [];\n\t\taliasesByPackage.set(\n\t\t\textensionPackage.packageName,\n\t\t\tuniqueStrings([...existingAliases, ...candidate.aliases]),\n\t\t);\n\t\tpackageAliasesByStatusBase.set(candidate.statusBase, aliasesByPackage);\n\t}\n\n\tconst aliases = new Map<string, string[]>();\n\tfor (const [statusBase, aliasesByPackage] of packageAliasesByStatusBase) {\n\t\tif (aliasesByPackage.size === 1)\n\t\t\taliases.set(statusBase, [...aliasesByPackage.values()][0] ?? []);\n\t}\n\treturn aliases;\n}\n\nfunction extensionStatusIconAliasCandidate(\n\tpackageName: string,\n\tsource?: string,\n): { statusBase: string; aliases: string[] } | undefined {\n\tconst packageBase = packageBaseName(packageName);\n\tconst statusBase = statusBaseFromPackageBase(packageBase);\n\tif (!statusBase) return undefined;\n\n\tconst sourceAliases = source?.startsWith(\"npm:\") ? [source, `npm:${npmPackageName(source)}`] : [];\n\treturn {\n\t\tstatusBase,\n\t\taliases: uniqueStrings([...sourceAliases, packageName, packageBase, statusBase]),\n\t};\n}\n\nfunction packageBaseName(packageName: string): string {\n\tconst slashIndex = packageName.lastIndexOf(\"/\");\n\treturn slashIndex === -1 ? packageName : packageName.slice(slashIndex + 1);\n}\n\nfunction statusBaseFromPackageBase(packageBase: string): string {\n\treturn packageBase.startsWith(\"pi-\") && packageBase.length > \"pi-\".length\n\t\t? packageBase.slice(\"pi-\".length)\n\t\t: packageBase;\n}\n\nfunction uniqueStrings(values: readonly string[]): string[] {\n\treturn [...new Set(values.filter((value) => value.length > 0))];\n}\n\nfunction readPackageSources(settingsFile: string): string[] {\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsFile, \"utf8\")) as { packages?: unknown[] };\n\t\treturn (settings.packages ?? [])\n\t\t\t.map((entry) => {\n\t\t\t\tif (typeof entry === \"string\") return entry;\n\t\t\t\tif (\n\t\t\t\t\tentry &&\n\t\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\t\ttypeof (entry as { source?: unknown }).source === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (entry as { source: string }).source;\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t})\n\t\t\t.filter((source): source is string => source !== undefined);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction packageNameForSource(source: string, baseDirectory: string): string | undefined {\n\tif (source.startsWith(\"npm:\")) return npmPackageName(source);\n\tconst packageJson = join(resolveSourcePath(source, baseDirectory), \"package.json\");\n\ttry {\n\t\tconst packageData = JSON.parse(readFileSync(packageJson, \"utf8\")) as { name?: unknown };\n\t\treturn typeof packageData.name === \"string\" ? packageData.name : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function npmPackageName(source: string): string {\n\tconst spec = source.slice(\"npm:\".length);\n\tif (spec.startsWith(\"@\")) return spec.split(\"@\").slice(0, 2).join(\"@\");\n\treturn spec.split(\"@\")[0] ?? spec;\n}\n\nfunction sourceIdentity(source: string, baseDirectory: string): string {\n\tif (source.startsWith(\"npm:\")) return `npm:${npmPackageName(source)}`;\n\treturn resolveSourcePath(source, baseDirectory);\n}\n\nfunction resolveSourcePath(source: string, baseDirectory: string): string {\n\treturn isAbsolute(source) ? source : resolve(baseDirectory, source);\n}\n", "import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport { visibleWidth } from \"@earendil-works/pi-tui\";\nimport { ansiStyle } from \"./ansi.js\";\nimport { resolvePreset } from \"./presets/index.js\";\nimport type { BlockColors, PowerlinePreset } from \"./presets/types.js\";\nimport {\n\tLINE_BREAK_SEGMENT_NAME,\n\ttype PalettePreset,\n\ttype PowerlineBlockName,\n\ttype RenderItem,\n\ttype RenderSegment,\n\ttype SegmentPalette,\n\ttype SeparatorName,\n\ttype StatuslineConfig,\n} from \"./types.js\";\n\ninterface PowerlineBlock {\n\tbaseBlock: PowerlineBlockName;\n\tcolors: BlockColors;\n\tsegments: RenderSegment[];\n}\n\nexport function renderPowerlineStatusline(\n\twidth: number,\n\titems: RenderItem[],\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n): string {\n\tif (items.length === 0 || width <= 0) return \"\";\n\treturn splitLines(items)\n\t\t.map((segments) => fitPowerlineSegments(segments, width, config))\n\t\t.join(\"\\n\");\n}\n\nfunction splitLines(items: RenderItem[]): RenderSegment[][] {\n\tconst lines: RenderSegment[][] = [[]];\n\tfor (const item of items) {\n\t\tif (item.name === LINE_BREAK_SEGMENT_NAME) lines.push([]);\n\t\telse lines.at(-1)?.push(item);\n\t}\n\treturn lines;\n}\n\nconst SEGMENT_RETENTION_PRIORITY: Readonly<Record<RenderSegment[\"name\"], number>> = {\n\tcontext: 120,\n\tmodel: 110,\n\tbranch: 100,\n\ttools: 90,\n\tcwd: 80,\n\tthinking: 70,\n\tcost: 60,\n\tprovider: 50,\n\tcache: 45,\n\ttokens: 40,\n\ttime: 30,\n\tturn: 20,\n\tbrand: 10,\n};\n\nfunction fitPowerlineSegments(\n\tsegments: readonly RenderSegment[],\n\twidth: number,\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n): string {\n\tif (segments.length === 0) return \"\";\n\tconst fitted = [...segments];\n\twhile (fitted.length > 1) {\n\t\tconst rendered = joinPowerlineSegments(fitted, config);\n\t\tif (visibleWidth(rendered) <= width) return rendered;\n\t\tlet removalIndex = 0;\n\t\tfor (let index = 1; index < fitted.length; index += 1) {\n\t\t\tconst candidate = fitted[index];\n\t\t\tconst current = fitted[removalIndex];\n\t\t\tif (\n\t\t\t\tcandidate &&\n\t\t\t\tcurrent &&\n\t\t\t\tSEGMENT_RETENTION_PRIORITY[candidate.name] < SEGMENT_RETENTION_PRIORITY[current.name]\n\t\t\t) {\n\t\t\t\tremovalIndex = index;\n\t\t\t}\n\t\t}\n\t\tfitted.splice(removalIndex, 1);\n\t}\n\tconst rendered = joinPowerlineSegments(fitted, config);\n\treturn visibleWidth(rendered) <= width ? rendered : \"\";\n}\n\nexport function powerlineExtensionSeparator(\n\t_theme: Theme,\n\tpalettePreset: PalettePreset = \"tokyo-night\",\n): string {\n\treturn ansiStyle(\" \u2022 \", { fg: resolvePreset(palettePreset).extensionSeparator });\n}\n\nfunction joinPowerlineSegments(\n\tsegments: RenderSegment[],\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n): string {\n\tconst preset = resolvePreset(config.palettePreset);\n\tconst blocks = contiguousBlocks(segments, preset, config.palettePreset, config.palette);\n\tlet line = ansiStyle(\"\u2591\u2592\u2593\", { fg: preset.lead });\n\n\tfor (const [index, block] of blocks.entries()) {\n\t\tconst previous = index === 0 ? undefined : blocks[index - 1]?.colors;\n\t\tif (previous) line += ansiStyle(\"\uE0B4\", { fg: previous.bg, bg: block.colors.bg });\n\t\tline += ansiStyle(formatBlockText(block, config), block.colors);\n\t}\n\n\tconst lastBlock = blocks.at(-1);\n\tif (lastBlock) line += ansiStyle(\"\uE0B4\", { fg: lastBlock.colors.bg });\n\treturn line;\n}\n\nfunction contiguousBlocks(\n\tsegments: RenderSegment[],\n\tpreset: PowerlinePreset,\n\tpalettePreset: PalettePreset,\n\tconfiguredPalette: SegmentPalette,\n): PowerlineBlock[] {\n\tconst blocks: PowerlineBlock[] = [];\n\tconst usesConfiguredColors = palettePreset === \"custom\";\n\tfor (const segment of segments) {\n\t\tconst colors = usesConfiguredColors\n\t\t\t? (configuredPalette[segment.name] ?? {})\n\t\t\t: preset.blocks[segment.block];\n\t\tconst previous = blocks.at(-1);\n\t\tconst matchesPrevious =\n\t\t\tprevious !== undefined &&\n\t\t\t(usesConfiguredColors\n\t\t\t\t? colorsEqual(previous.colors, colors)\n\t\t\t\t: previous.baseBlock === segment.block);\n\t\tif (matchesPrevious) previous.segments.push(segment);\n\t\telse blocks.push({ baseBlock: segment.block, colors, segments: [segment] });\n\t}\n\treturn blocks;\n}\n\nfunction colorsEqual(left: BlockColors, right: BlockColors): boolean {\n\treturn left.fg === right.fg && left.bg === right.bg;\n}\n\nfunction formatBlockText(\n\tblock: PowerlineBlock,\n\tconfig: Pick<StatuslineConfig, \"density\" | \"separator\">,\n): string {\n\tconst texts = block.segments.map(formatSegmentText);\n\tconst separator = separatorText(config.separator, config.density === \"cozy\");\n\tconst leading = config.density === \"cozy\" ? \" \" : \" \";\n\tconst trailing = config.density === \"cozy\" ? \" \" : \"\";\n\treturn `${leading}${texts.join(separator)}${trailing}`;\n}\n\nfunction formatSegmentText(segment: RenderSegment): string {\n\treturn segment.emphasis ? `\\u001b[1m${segment.text}\\u001b[22m` : segment.text;\n}\n\nfunction separatorText(separator: SeparatorName, cozy: boolean): string {\n\tconst padding = cozy ? \" \" : \" \";\n\tswitch (separator) {\n\t\tcase \"dot\":\n\t\t\treturn `${padding}\u2022${padding}`;\n\t\tcase \"bar\":\n\t\t\treturn `${padding}\u2502${padding}`;\n\t\tcase \"powerline\":\n\t\t\treturn `${padding}\uE0B1${padding}`;\n\t\tcase \"round\":\n\t\t\treturn `${padding}\u276F${padding}`;\n\t\tcase \"none\":\n\t\t\treturn padding;\n\t}\n}\n", "export function ansiStyle(text: string, colors: { fg?: string; bg?: string }): string {\n\tconst codes = [\n\t\tcolors.fg ? truecolorCode(\"38\", colors.fg) : undefined,\n\t\tcolors.bg ? truecolorCode(\"48\", colors.bg) : undefined,\n\t].filter((code): code is string => code !== undefined);\n\tif (codes.length === 0) return text;\n\treturn `\\u001b[${codes.join(\";\")}m${text}\\u001b[0m`;\n}\n\nexport function ansiFg(hex: string, text: string): string {\n\treturn ansiStyle(text, { fg: hex });\n}\n\nfunction truecolorCode(prefix: \"38\" | \"48\", hex: string): string {\n\tconst { red, green, blue } = hexToRgb(hex);\n\treturn `${prefix};2;${red};${green};${blue}`;\n}\n\nfunction hexToRgb(hex: string): { red: number; green: number; blue: number } {\n\tconst normalized = hex.replace(/^#/, \"\");\n\treturn {\n\t\tred: Number.parseInt(normalized.slice(0, 2), 16),\n\t\tgreen: Number.parseInt(normalized.slice(2, 4), 16),\n\t\tblue: Number.parseInt(normalized.slice(4, 6), 16),\n\t};\n}\n", "import { isAbsolute } from \"node:path\";\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\n\nconst GIT_STATUS_TIMEOUT_MS = 3_000;\n\nexport interface GitStatusSummary {\n\troot?: string;\n\tahead: number;\n\tbehind: number;\n\tstaged: number;\n\tmodified: number;\n\tuntracked: number;\n\tconflicts: number;\n}\n\nexport async function readGitStatus(\n\tpi: ExtensionAPI,\n\tcwd: string,\n\tsignal?: AbortSignal,\n): Promise<GitStatusSummary | undefined> {\n\tconst [statusResult, rootResult] = await Promise.all([\n\t\tpi.exec(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"status\", \"--porcelain=v1\", \"--branch\", \"--untracked-files=normal\"],\n\t\t\t{ cwd, timeout: GIT_STATUS_TIMEOUT_MS, signal },\n\t\t),\n\t\tpi\n\t\t\t.exec(\"git\", [\"rev-parse\", \"--path-format=absolute\", \"--show-toplevel\"], {\n\t\t\t\tcwd,\n\t\t\t\ttimeout: GIT_STATUS_TIMEOUT_MS,\n\t\t\t\tsignal,\n\t\t\t})\n\t\t\t.catch(() => undefined),\n\t]);\n\tif (statusResult.code !== 0 || statusResult.killed) return undefined;\n\tconst summary = parseGitStatusPorcelain(statusResult.stdout);\n\tif (rootResult && rootResult.code === 0 && !rootResult.killed) {\n\t\tconst root = parseGitRoot(rootResult.stdout);\n\t\tif (root) summary.root = root;\n\t}\n\treturn summary;\n}\n\nexport function parseGitStatusPorcelain(output: string): GitStatusSummary {\n\tconst summary: GitStatusSummary = {\n\t\tahead: 0,\n\t\tbehind: 0,\n\t\tstaged: 0,\n\t\tmodified: 0,\n\t\tuntracked: 0,\n\t\tconflicts: 0,\n\t};\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tif (!line) continue;\n\t\tif (line.startsWith(\"## \")) {\n\t\t\tconst ahead = line.match(/\\bahead (\\d+)/u);\n\t\t\tconst behind = line.match(/\\bbehind (\\d+)/u);\n\t\t\tsummary.ahead = ahead ? Number(ahead[1]) : 0;\n\t\t\tsummary.behind = behind ? Number(behind[1]) : 0;\n\t\t\tcontinue;\n\t\t}\n\t\tconst indexStatus = line[0] ?? \" \";\n\t\tconst worktreeStatus = line[1] ?? \" \";\n\t\tif (indexStatus === \"?\" && worktreeStatus === \"?\") {\n\t\t\tsummary.untracked += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isConflictStatus(indexStatus, worktreeStatus)) {\n\t\t\tsummary.conflicts += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isChangedStatus(indexStatus)) summary.staged += 1;\n\t\tif (isChangedStatus(worktreeStatus)) summary.modified += 1;\n\t}\n\treturn summary;\n}\n\nfunction isConflictStatus(indexStatus: string, worktreeStatus: string): boolean {\n\treturn (\n\t\t(indexStatus === \"D\" && worktreeStatus === \"D\") ||\n\t\t(indexStatus === \"A\" && worktreeStatus === \"A\") ||\n\t\tindexStatus === \"U\" ||\n\t\tworktreeStatus === \"U\"\n\t);\n}\n\nfunction isChangedStatus(status: string): boolean {\n\treturn status !== \" \" && status !== \"?\" && status !== \"!\";\n}\n\nexport function parseGitRoot(output: string): string | undefined {\n\tconst root = output.split(/\\r?\\n/u)[0]?.trim();\n\treturn root && isAbsolute(root) ? root : undefined;\n}\n\nexport function formatGitStatusSummary(summary: GitStatusSummary | undefined): string {\n\tif (!summary) return \"\";\n\tconst tokens = [\n\t\t[\"\u21E1\", summary.ahead],\n\t\t[\"\u21E3\", summary.behind],\n\t\t[\"+\", summary.staged],\n\t\t[\"~\", summary.modified],\n\t\t[\"?\", summary.untracked],\n\t\t[\"!\", summary.conflicts],\n\t] as const;\n\treturn tokens\n\t\t.filter(([, count]) => count > 0)\n\t\t.map(([prefix, count]) => `${prefix}${formatCount(count)}`)\n\t\t.join(\" \");\n}\n\nexport function formatGitBranchValue(\n\tbranch: string | null,\n\tstatus: GitStatusSummary | undefined,\n\tpr?: string,\n): string {\n\tif (!branch) return \"no-git\";\n\tconst suffixes = [formatGitStatusSummary(status), pr ? `(${pr})` : \"\"].filter(Boolean);\n\treturn suffixes.length > 0 ? `${branch} ${suffixes.join(\" \")}` : branch;\n}\n\nexport function formatGitBranchText(\n\tbranch: string | null,\n\tstatus: GitStatusSummary | undefined,\n\tpr?: string,\n): string {\n\treturn `\uD83C\uDF3F ${formatGitBranchValue(branch, status, pr)}`;\n}\n\nexport function gitStatusSummaryEqual(\n\tleft: GitStatusSummary | undefined,\n\tright: GitStatusSummary | undefined,\n): boolean {\n\tif (!left || !right) return left === right;\n\treturn (\n\t\tleft.root === right.root &&\n\t\tleft.ahead === right.ahead &&\n\t\tleft.behind === right.behind &&\n\t\tleft.staged === right.staged &&\n\t\tleft.modified === right.modified &&\n\t\tleft.untracked === right.untracked &&\n\t\tleft.conflicts === right.conflicts\n\t);\n}\n\nfunction formatCount(value: number): string {\n\treturn Intl.NumberFormat(\"en\", { notation: \"compact\", maximumFractionDigits: 1 }).format(value);\n}\n", "import type {\n\tExtensionAPI,\n\tExtensionContext,\n\tReadonlyFooterDataProvider,\n\tTheme,\n\tThemeColor,\n} from \"@earendil-works/pi-coding-agent\";\nimport { sanitizeTerminalText } from \"@narumitw/pi-tui-kit/terminal-text\";\nimport { formatDirectoryPath } from \"./directory.js\";\nimport {\n\ttype ExtensionStatusRuntime,\n\tformatExtensionStatuses,\n\twrapExtensionStatusline,\n} from \"./extension-status.js\";\nimport { formatGitBranchValue, type GitStatusSummary } from \"./git-status.js\";\nimport { renderPowerlineStatusline } from \"./powerline.js\";\nimport {\n\tLINE_BREAK_SEGMENT_NAME,\n\ttype PowerlineBlockName,\n\ttype RenderItem,\n\ttype RenderSegment,\n\ttype SegmentName,\n\ttype StatuslineConfig,\n\ttype TruncationDirection,\n} from \"./types.js\";\nimport { type FooterUsageSummary, summarizeFooterUsage } from \"./usage.js\";\n\ntype ThinkingLevel = ReturnType<ExtensionAPI[\"getThinkingLevel\"]>;\nexport interface RuntimeState extends ExtensionStatusRuntime {\n\thomeDir?: string;\n\tturnCount: number;\n\tactiveTools: Map<string, number>;\n\tisStreaming: boolean;\n\tthinkingLevel: ThinkingLevel;\n\tgitStatus?: GitStatusSummary;\n\trequestRender?: () => void;\n}\nconst GITHUB_PR_KEY = \"github-pr\";\nconst GITHUB_PR_STATUS_KEYS = new Set([GITHUB_PR_KEY]);\nexport function renderStatusline(\n\twidth: number,\n\tctx: ExtensionContext,\n\tfooterData: ReadonlyFooterDataProvider,\n\t_theme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n): string {\n\tif (width <= 0) return \"\";\n\n\tconst usageSummary = summarizeFooterUsage(ctx.sessionManager.getEntries());\n\tconst rows: Array<{ configuredSegments: number; segments: RenderSegment[] }> = [\n\t\t{ configuredSegments: 0, segments: [] },\n\t];\n\tfor (const name of config.segments) {\n\t\tif (name === LINE_BREAK_SEGMENT_NAME) {\n\t\t\trows.push({ configuredSegments: 0, segments: [] });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst row = rows.at(-1);\n\t\tif (!row) continue;\n\t\trow.configuredSegments += 1;\n\t\tconst rendered = buildSegment(name, ctx, footerData, config, runtime, usageSummary);\n\t\tif (rendered && rendered.text.length > 0) row.segments.push(rendered);\n\t}\n\n\tconst segments: RenderItem[] = [];\n\tconst renderedRows = rows.filter(\n\t\t(row) => row.configuredSegments === 0 || row.segments.length > 0,\n\t);\n\tfor (const [index, row] of renderedRows.entries()) {\n\t\tif (index > 0) segments.push({ name: LINE_BREAK_SEGMENT_NAME });\n\t\tsegments.push(...row.segments);\n\t}\n\n\treturn renderPowerlineStatusline(width, segments, config);\n}\n\nexport function renderExtensionStatusline(\n\twidth: number,\n\tfooterData: ReadonlyFooterDataProvider,\n\ttheme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n\tmainLine: string,\n): string[] {\n\tconst statuses = footerData.getExtensionStatuses();\n\tconst prContext = prContextFromStatuses(statuses);\n\tconst rendersPrInline = prContext !== undefined && mainLine.includes(prContext);\n\tconst status = formatExtensionStatuses(\n\t\tstatuses,\n\t\ttheme,\n\t\tconfig,\n\t\truntime,\n\t\trendersPrInline ? GITHUB_PR_STATUS_KEYS : undefined,\n\t);\n\treturn wrapExtensionStatusline(status, width);\n}\n\nfunction buildSegment(\n\tname: SegmentName,\n\tctx: ExtensionContext,\n\tfooterData: ReadonlyFooterDataProvider,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n\tusageSummary: FooterUsageSummary,\n): RenderSegment | undefined {\n\tswitch (name) {\n\t\tcase \"brand\":\n\t\t\treturn segment(name, \"\u03C0\", config, \"accent\", \"header\", true);\n\t\tcase \"provider\":\n\t\t\treturn segment(name, ctx.model?.provider ?? \"no-provider\", config, \"accent\", \"header\");\n\t\tcase \"model\": {\n\t\t\tconst presentation = config.segmentText.model;\n\t\t\tconst model = truncateModel(\n\t\t\t\tshortenModel(ctx.model?.id ?? \"no-model\"),\n\t\t\t\tpresentation.truncationLength,\n\t\t\t\tpresentation.truncationSymbol,\n\t\t\t\tpresentation.truncationDirection,\n\t\t\t);\n\t\t\treturn segment(name, model, config, \"accent\", \"header\");\n\t\t}\n\t\tcase \"thinking\":\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\truntime.thinkingLevel,\n\t\t\t\tconfig,\n\t\t\t\tthinkingColor(runtime.thinkingLevel),\n\t\t\t\t\"header\",\n\t\t\t);\n\t\tcase \"branch\": {\n\t\t\tconst branch = footerData.getGitBranch();\n\t\t\tconst pr = branch ? prContextFromStatuses(footerData.getExtensionStatuses()) : undefined;\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\tformatGitBranchValue(branch, runtime.gitStatus, pr),\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"git\",\n\t\t\t);\n\t\t}\n\t\tcase \"cwd\":\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\tformatDirectoryPath(ctx.cwd, runtime.homeDir, runtime.gitStatus?.root),\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"directory\",\n\t\t\t);\n\t\tcase \"tools\": {\n\t\t\tconst activity = formatToolActivity(runtime);\n\t\t\treturn activity ? segment(name, activity, config, \"accent\", \"runtime\") : undefined;\n\t\t}\n\t\tcase \"context\": {\n\t\t\tconst usage = ctx.getContextUsage();\n\t\t\tconst percentage =\n\t\t\t\tusage?.percent === null || usage?.percent === undefined\n\t\t\t\t\t? \"?\"\n\t\t\t\t\t: `${usage.percent.toFixed(1)}%`;\n\t\t\tconst contextWindow = usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\t`${percentage}/${formatCount(contextWindow)}`,\n\t\t\t\tconfig,\n\t\t\t\tcontextColor(usage?.percent),\n\t\t\t\t\"runtime\",\n\t\t\t);\n\t\t}\n\t\tcase \"tokens\": {\n\t\t\tconst value =\n\t\t\t\tusageSummary.input === 0 && usageSummary.output === 0\n\t\t\t\t\t? \"tok 0\"\n\t\t\t\t\t: `\u2191${formatCount(usageSummary.input)} \u2193${formatCount(usageSummary.output)}`;\n\t\t\treturn segment(name, value, config, \"accent\", \"runtime\");\n\t\t}\n\t\tcase \"cache\": {\n\t\t\tif (usageSummary.cacheRead === 0 && usageSummary.cacheWrite === 0) return undefined;\n\t\t\tconst values: string[] = [];\n\t\t\tif (usageSummary.cacheRead > 0) values.push(`R${formatCount(usageSummary.cacheRead)}`);\n\t\t\tif (usageSummary.cacheWrite > 0) values.push(`W${formatCount(usageSummary.cacheWrite)}`);\n\t\t\tif (usageSummary.latestCacheHitRate !== undefined) {\n\t\t\t\tvalues.push(`CH${usageSummary.latestCacheHitRate.toFixed(1)}%`);\n\t\t\t}\n\t\t\treturn segment(name, values.join(\" \"), config, \"accent\", \"runtime\");\n\t\t}\n\t\tcase \"cost\": {\n\t\t\tconst subscription = isSubscriptionBacked(ctx) ? \" (sub)\" : \"\";\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\t`${usageSummary.cost.toFixed(usageSummary.cost >= 1 ? 2 : 3)}${subscription}`,\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"meter\",\n\t\t\t);\n\t\t}\n\t\tcase \"time\":\n\t\t\treturn segment(name, formatTime(), config, \"accent\", \"meter\");\n\t\tcase \"turn\":\n\t\t\treturn segment(name, `${runtime.turnCount}`, config, \"accent\", \"meter\");\n\t}\n}\n\nfunction segment(\n\tname: SegmentName,\n\tvalue: string,\n\tconfig: StatuslineConfig,\n\tcolor: RenderSegment[\"color\"],\n\tblock: PowerlineBlockName,\n\temphasis = false,\n): RenderSegment {\n\treturn { name, text: formatConfiguredSegment(name, value, config), color, block, emphasis };\n}\n\nexport function formatConfiguredSegment(\n\tname: SegmentName,\n\tvalue: string,\n\tconfig: Pick<StatuslineConfig, \"segmentText\">,\n): string {\n\tconst presentation = config.segmentText[name];\n\treturn `${presentation.prefix}${value}${presentation.suffix}`;\n}\n\nfunction thinkingColor(level: ThinkingLevel): ThemeColor {\n\tswitch (level as string) {\n\t\tcase \"off\":\n\t\t\treturn \"dim\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\" as ThemeColor;\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\nexport function contextColor(percent: number | null | undefined): ThemeColor {\n\tif (percent === null || percent === undefined) return \"dim\";\n\tif (percent >= 90) return \"error\";\n\tif (percent >= 70) return \"warning\";\n\treturn \"success\";\n}\n\nexport function formatToolActivity(runtime: RuntimeState): string | undefined {\n\tconst active = [...runtime.activeTools.entries()];\n\tif (active.length > 0) {\n\t\tconst [name, count] = active[0] ?? [\"tool\", 1];\n\t\tconst suffix = count > 1 ? `\u00D7${count}` : active.length > 1 ? `+${active.length - 1}` : \"\";\n\t\treturn `\u2699 ${name}${suffix}`;\n\t}\n\n\treturn runtime.isStreaming ? \"\uD83D\uDCAD thinking\" : undefined;\n}\n\nexport function prLinkFromStatuses(statuses: ReadonlyMap<string, string>): string | undefined {\n\tconst value = statuses.get(GITHUB_PR_KEY);\n\tif (!value) return undefined;\n\t// Extract the OSC 8 hyperlink span (the clickable \"#123\"); skip non-PR states\n\t// like \"PR gh missing\" that carry no link. github-pr emits exactly one link, so the\n\t// first OSC 8 span is the PR number.\n\tconst open = value.indexOf(\"\\x1b]8;;\");\n\tif (open === -1) return undefined;\n\tconst closeMarker = \"\\x1b]8;;\\x07\";\n\tconst close = value.indexOf(closeMarker, open + 1);\n\treturn close === -1 ? undefined : value.slice(open, close + closeMarker.length);\n}\n\nexport function prContextFromStatuses(statuses: ReadonlyMap<string, string>): string | undefined {\n\tconst value = statuses.get(GITHUB_PR_KEY);\n\tconst link = prLinkFromStatuses(statuses);\n\tif (!value || !link) return undefined;\n\n\tconst state = compactPrState(value.replace(link, \"\"));\n\treturn state ? `${link} \u00B7 ${state}` : undefined;\n}\n\nfunction compactPrState(value: string): string | undefined {\n\tif (/:\\s*merged\\s*$/.test(value)) return \"merged\";\n\tif (/:\\s*closed\\s*$/.test(value)) return \"closed\";\n\tif (/\\bdraft\\b/.test(value)) return \"draft\";\n\n\tconst failing = /\\bchecks failing \\((\\d+)\\)/.exec(value);\n\tif (failing) return `${failing[1]} failing`;\n\tif (/\\bchanges requested\\b/.test(value)) return \"changes requested\";\n\n\tconst pending = /\\bchecks pending \\((\\d+)\\)/.exec(value);\n\tif (pending) return `${pending[1]} pending`;\n\tif (/\\bapproved\\b/.test(value)) return \"approved\";\n\tif (/\\breview required\\b/.test(value)) return \"review required\";\n\tif (/\\bchecks passing\\b/.test(value)) return \"checks passing\";\n\tif (/\\bno checks\\b/.test(value)) return \"no checks\";\n\treturn undefined;\n}\n\nfunction isSubscriptionBacked(ctx: ExtensionContext): boolean {\n\tconst model = ctx.model;\n\treturn (\n\t\tmodel !== undefined &&\n\t\t(model.provider === \"kimi-coding\" || ctx.modelRegistry.isUsingOAuth(model))\n\t);\n}\n\nexport function formatCount(value: number): string {\n\tif (value < 1000) return `${value}`;\n\tif (value < 1_000_000) return `${(value / 1000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}m`;\n}\n\nfunction formatTime(): string {\n\tconst now = new Date();\n\tconst hours = now.getHours().toString().padStart(2, \"0\");\n\tconst minutes = now.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n\nexport function truncateModel(\n\tmodel: string,\n\tlength: number,\n\tsymbol: string,\n\tdirection: TruncationDirection,\n): string {\n\tconst safeModel = sanitizeTerminalText(model);\n\tif (length === 0) return safeModel;\n\tconst graphemes = [...graphemeSegmenter.segment(safeModel)].map(({ segment }) => segment);\n\tif (graphemes.length <= length) return safeModel;\n\tconst safeSymbol = sanitizeTerminalText(symbol);\n\n\tswitch (direction) {\n\t\tcase \"start\":\n\t\t\treturn `${safeSymbol}${graphemes.slice(-length).join(\"\")}`;\n\t\tcase \"middle\": {\n\t\t\tconst headLength = Math.ceil(length / 2);\n\t\t\tconst tailLength = Math.floor(length / 2);\n\t\t\tconst tail = tailLength > 0 ? graphemes.slice(-tailLength).join(\"\") : \"\";\n\t\t\treturn `${graphemes.slice(0, headLength).join(\"\")}${safeSymbol}${tail}`;\n\t\t}\n\t\tcase \"end\":\n\t\t\treturn `${graphemes.slice(0, length).join(\"\")}${safeSymbol}`;\n\t}\n}\n\nexport function shortenModel(model: string): string {\n\treturn model\n\t\t.replace(/^claude-/, \"\")\n\t\t.replace(/^gpt-/, \"gpt \")\n\t\t.replace(/-20\\d{6}$/, \"\")\n\t\t.replace(/-latest$/, \"\");\n}\n", "import { basename, isAbsolute, relative, sep } from \"node:path\";\nimport { sanitizeTerminalText } from \"@narumitw/pi-tui-kit/terminal-text\";\n\nconst DEFAULT_TRUNCATION_LENGTH = 3;\nconst DEFAULT_HOME_SYMBOL = \"~\";\n\n/** Apply Starship's default directory presentation without exposing a format language. */\nexport function formatDirectoryPath(\n\tcwd: string,\n\thomeDir: string | undefined,\n\tgitRoot: string | undefined,\n): string {\n\tconst contracted =\n\t\tgitRoot && (!homeDir || !samePath(gitRoot, homeDir))\n\t\t\t? (contractRepositoryPath(cwd, gitRoot) ?? contractPath(cwd, homeDir, DEFAULT_HOME_SYMBOL))\n\t\t\t: contractPath(cwd, homeDir, DEFAULT_HOME_SYMBOL);\n\tconst safeContracted = sanitizeTerminalText(contracted);\n\tconst components = safeContracted.split(\"/\").filter((component) => component.length > 0);\n\tconst displayed =\n\t\tcomponents.length > DEFAULT_TRUNCATION_LENGTH\n\t\t\t? components.slice(-DEFAULT_TRUNCATION_LENGTH).join(\"/\")\n\t\t\t: safeContracted;\n\tconst native = sep === \"/\" ? displayed : displayed.replaceAll(\"/\", sep);\n\treturn sanitizeTerminalText(native || basename(cwd) || cwd);\n}\n\nfunction toSlashPath(value: string): string {\n\treturn sep === \"\\\\\" ? value.replaceAll(\"\\\\\", \"/\") : value;\n}\n\nfunction contractPath(path: string, root: string | undefined, replacement: string): string {\n\tif (!root) return toSlashPath(path);\n\tconst child = relativeWithin(path, root);\n\tif (child === undefined) return toSlashPath(path);\n\treturn child ? `${replacement}/${child}` : replacement;\n}\n\nfunction contractRepositoryPath(path: string, root: string): string | undefined {\n\tconst child = relativeWithin(path, root);\n\tif (child === undefined) return undefined;\n\tconst name = basename(root) || toSlashPath(root);\n\treturn child ? `${name}/${child}` : name;\n}\n\nfunction relativeWithin(path: string, root: string): string | undefined {\n\tconst child = relative(root, path);\n\tif (child === \"\") return \"\";\n\tif (child === \"..\" || child.startsWith(`..${sep}`) || isAbsolute(child)) return undefined;\n\treturn toSlashPath(child);\n}\n\nfunction samePath(left: string, right: string): boolean {\n\treturn relative(left, right) === \"\";\n}\n", "import type { SessionEntry } from \"@earendil-works/pi-coding-agent\";\n\ninterface UsageLike {\n\tinput?: number;\n\toutput?: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost?: { total?: number };\n}\n\nexport interface FooterUsageSummary {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\tcost: number;\n\tlatestCacheHitRate?: number;\n}\n\nexport function summarizeFooterUsage(entries: readonly SessionEntry[]): FooterUsageSummary {\n\tconst totals: FooterUsageSummary = {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\tcost: 0,\n\t};\n\n\tfor (const entry of entries) {\n\t\tlet usage: UsageLike | undefined;\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tusage = entry.message.usage;\n\t\t\tconst input = usage.input ?? 0;\n\t\t\tconst cacheRead = usage.cacheRead ?? 0;\n\t\t\tconst cacheWrite = usage.cacheWrite ?? 0;\n\t\t\tconst promptTokens = input + cacheRead + cacheWrite;\n\t\t\ttotals.latestCacheHitRate = promptTokens > 0 ? (cacheRead / promptTokens) * 100 : undefined;\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\") {\n\t\t\tusage = entry.message.usage;\n\t\t} else if (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n\t\t\tusage = entry.usage;\n\t\t}\n\t\tif (!usage) continue;\n\n\t\ttotals.input += usage.input ?? 0;\n\t\ttotals.output += usage.output ?? 0;\n\t\ttotals.cacheRead += usage.cacheRead ?? 0;\n\t\ttotals.cacheWrite += usage.cacheWrite ?? 0;\n\t\ttotals.cost += usage.cost?.total ?? 0;\n\t}\n\n\treturn totals;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["getAgentDir", "rendered", "segment", "isAbsolute", "sanitizeTerminalText", "isAbsolute", "formatCount", "sanitizeTerminalText", "segment", "STATUSLINE_KEY", "EMPTY_EXTENSION_STATUS_ICON_ALIASES", "getAgentDir"]
|
|
4
|
+
"sourcesContent": ["import { homedir } from \"node:os\";\nimport {\n\ttype ExtensionAPI,\n\ttype ExtensionContext,\n\tgetAgentDir,\n} from \"@earendil-works/pi-coding-agent\";\nimport { getCapabilities } from \"@earendil-works/pi-tui\";\nimport { completeStatuslineArguments } from \"./command-contract.js\";\nimport type { StatuslineCommandOptions } from \"./commands.js\";\nimport {\n\tbuildExtensionStatusIconAliases,\n\ttype ExtensionStatusIconAliasMap,\n\tfindDuplicateExtensions,\n\treadInstalledExtensionPackages,\n} from \"./extension-status.js\";\nimport { type GitStatusSummary, gitStatusSummaryEqual, readGitStatus } from \"./git-status.js\";\nimport { type RuntimeState, renderExtensionStatusline, renderStatusline } from \"./render.js\";\nimport {\n\tconsumeStatuslineSettingsNotice,\n\ttype LoadedStatuslineSettings,\n\tloadStatuslineSettings,\n\tloadStatuslineSettingsForAgent,\n\tsettingsFilePath,\n} from \"./settings.js\";\nimport type { PalettePreset } from \"./types.js\";\n\nconst STATUSLINE_KEY = \"statusline\";\nconst GIT_STATUS_REFRESH_INTERVAL_MS = 30_000;\nconst GIT_STATUS_EVENT_DEBOUNCE_MS = 250;\nconst EMPTY_EXTENSION_STATUS_ICON_ALIASES: ExtensionStatusIconAliasMap = new Map();\n\ntype StatuslineCommands = typeof import(\"./commands.js\");\nlet statuslineCommandsPromise: Promise<StatuslineCommands> | undefined;\n\nfunction loadStatuslineCommands(): Promise<StatuslineCommands> {\n\tif (!statuslineCommandsPromise) {\n\t\tstatuslineCommandsPromise = import(\"./commands.js\").catch((error) => {\n\t\t\tstatuslineCommandsPromise = undefined;\n\t\t\tthrow error;\n\t\t});\n\t}\n\treturn statuslineCommandsPromise;\n}\n\nexport default function statusline(pi: ExtensionAPI) {\n\tlet loaded: LoadedStatuslineSettings | undefined;\n\tlet previewPalettePreset: PalettePreset | undefined;\n\tlet activeSessionManager: ExtensionContext[\"sessionManager\"] | undefined;\n\tconst runtime: RuntimeState = {\n\t\tturnCount: 0,\n\t\tactiveTools: new Map(),\n\t\tisStreaming: false,\n\t\tthinkingLevel: \"off\",\n\t\tduplicateExtensions: [],\n\t\textensionStatusIconAliases: EMPTY_EXTENSION_STATUS_ICON_ALIASES,\n\t};\n\n\tlet sessionGeneration = 0;\n\tlet menuController = new AbortController();\n\tlet gitStatusRequestId = 0;\n\tlet activeGitStatusTarget: { cwd: string; generation: number } | undefined;\n\tlet gitStatusRefreshInFlight = false;\n\tlet gitStatusAbortController: AbortController | undefined;\n\tlet gitStatusDebounceTimer: ReturnType<typeof setTimeout> | undefined;\n\tlet pendingGitStatusRefresh: { cwd: string; generation: number; requestId: number } | undefined;\n\n\tconst refresh = () => runtime.requestRender?.();\n\tconst ownsRuntime = (ctx: ExtensionContext) => ctx.sessionManager === activeSessionManager;\n\n\tconst setGitStatus = (summary: GitStatusSummary | undefined) => {\n\t\tif (gitStatusSummaryEqual(runtime.gitStatus, summary)) return;\n\t\truntime.gitStatus = summary;\n\t\trefresh();\n\t};\n\n\tconst clearGitStatusDebounce = () => {\n\t\tif (!gitStatusDebounceTimer) return;\n\t\tclearTimeout(gitStatusDebounceTimer);\n\t\tgitStatusDebounceTimer = undefined;\n\t};\n\n\tconst abortGitStatusRefresh = (reason: string) => {\n\t\tgitStatusAbortController?.abort(new DOMException(reason, \"AbortError\"));\n\t};\n\n\tconst isActiveGitStatusTarget = (cwd: string, generation: number) =>\n\t\tactiveGitStatusTarget?.cwd === cwd &&\n\t\tactiveGitStatusTarget.generation === generation &&\n\t\tgeneration === sessionGeneration;\n\n\tconst isCurrentGitStatusRequest = (cwd: string, generation: number, requestId: number) =>\n\t\tisActiveGitStatusTarget(cwd, generation) && requestId === gitStatusRequestId;\n\n\tconst runGitStatusRefresh = (cwd: string, generation: number, requestId: number) => {\n\t\tif (!isCurrentGitStatusRequest(cwd, generation, requestId)) return;\n\t\tif (gitStatusRefreshInFlight) {\n\t\t\tpendingGitStatusRefresh = { cwd, generation, requestId };\n\t\t\treturn;\n\t\t}\n\n\t\tgitStatusRefreshInFlight = true;\n\t\tconst abortController = new AbortController();\n\t\tgitStatusAbortController = abortController;\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tconst summary = await readGitStatus(pi, cwd, abortController.signal);\n\t\t\t\tif (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(summary);\n\t\t\t} catch {\n\t\t\t\tif (isCurrentGitStatusRequest(cwd, generation, requestId)) setGitStatus(undefined);\n\t\t\t} finally {\n\t\t\t\tgitStatusRefreshInFlight = false;\n\t\t\t\tif (gitStatusAbortController === abortController) gitStatusAbortController = undefined;\n\t\t\t\tconst pending = pendingGitStatusRefresh;\n\t\t\t\tpendingGitStatusRefresh = undefined;\n\t\t\t\tif (pending) runGitStatusRefresh(pending.cwd, pending.generation, pending.requestId);\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst refreshGitStatus = (cwd: string, generation = sessionGeneration) => {\n\t\tif (!isActiveGitStatusTarget(cwd, generation)) return;\n\t\trunGitStatusRefresh(cwd, generation, ++gitStatusRequestId);\n\t};\n\n\tconst scheduleGitStatusRefresh = (cwd: string, generation = sessionGeneration) => {\n\t\tif (!isActiveGitStatusTarget(cwd, generation)) return;\n\t\tconst requestId = ++gitStatusRequestId;\n\t\tclearGitStatusDebounce();\n\t\tgitStatusDebounceTimer = setTimeout(() => {\n\t\t\tgitStatusDebounceTimer = undefined;\n\t\t\trunGitStatusRefresh(cwd, generation, requestId);\n\t\t}, GIT_STATUS_EVENT_DEBOUNCE_MS);\n\t};\n\n\tconst scheduleGitStatusRefreshForContext = (ctx: ExtensionContext) => {\n\t\tif (!activeGitStatusTarget || activeGitStatusTarget.cwd !== ctx.cwd) return;\n\t\tscheduleGitStatusRefresh(activeGitStatusTarget.cwd, activeGitStatusTarget.generation);\n\t};\n\n\tconst installFooter = (ctx: ExtensionContext) => {\n\t\tconst generation = ++sessionGeneration;\n\t\tmenuController.abort(new DOMException(\"Statusline session context replaced\", \"AbortError\"));\n\t\tmenuController = new AbortController();\n\t\tconst cwd = ctx.cwd;\n\t\tactiveSessionManager = ctx.sessionManager;\n\t\truntime.homeDir = homedir();\n\t\tpreviewPalettePreset = undefined;\n\t\tabortGitStatusRefresh(\"Statusline session context replaced\");\n\t\tclearGitStatusDebounce();\n\t\tactiveGitStatusTarget = ctx.mode === \"tui\" ? { cwd, generation } : undefined;\n\t\truntime.gitStatus = undefined;\n\t\truntime.duplicateExtensions = [];\n\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\tctx.ui.setStatus(STATUSLINE_KEY, undefined);\n\t\tif (!activeGitStatusTarget || !loaded) return;\n\t\tconst installedPackages = readInstalledExtensionPackages(cwd);\n\t\truntime.duplicateExtensions = findDuplicateExtensions(installedPackages);\n\t\truntime.extensionStatusIconAliases = buildExtensionStatusIconAliases(installedPackages);\n\t\tctx.ui.setFooter((tui, theme, footerData) => {\n\t\t\truntime.requestRender = () => tui.requestRender();\n\n\t\t\tconst refreshFooterGitStatus = () => refreshGitStatus(cwd, generation);\n\t\t\tconst branchUnsubscribe = footerData.onBranchChange(() => {\n\t\t\t\truntime.gitStatus = undefined;\n\t\t\t\tabortGitStatusRefresh(\"Statusline Git branch changed\");\n\t\t\t\tclearGitStatusDebounce();\n\t\t\t\trefreshFooterGitStatus();\n\t\t\t\ttui.requestRender();\n\t\t\t});\n\t\t\tconst clock = setInterval(() => {\n\t\t\t\tclearGitStatusDebounce();\n\t\t\t\trefreshFooterGitStatus();\n\t\t\t\ttui.requestRender();\n\t\t\t}, GIT_STATUS_REFRESH_INTERVAL_MS);\n\n\t\t\treturn {\n\t\t\t\tdispose() {\n\t\t\t\t\tbranchUnsubscribe();\n\t\t\t\t\tclearInterval(clock);\n\t\t\t\t\tif (isActiveGitStatusTarget(cwd, generation)) {\n\t\t\t\t\t\tactiveGitStatusTarget = undefined;\n\t\t\t\t\t\tabortGitStatusRefresh(\"Statusline footer disposed\");\n\t\t\t\t\t\tclearGitStatusDebounce();\n\t\t\t\t\t\tpendingGitStatusRefresh = undefined;\n\t\t\t\t\t\truntime.gitStatus = undefined;\n\t\t\t\t\t\truntime.duplicateExtensions = [];\n\t\t\t\t\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\t\t\t\t\truntime.requestRender = undefined;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tinvalidate() {},\n\t\t\t\trender(width: number): string[] {\n\t\t\t\t\tif (!loaded) return [];\n\t\t\t\t\tconst config = previewPalettePreset\n\t\t\t\t\t\t? { ...loaded.config, palettePreset: previewPalettePreset }\n\t\t\t\t\t\t: loaded.config;\n\t\t\t\t\tconst trueColor = getCapabilities().trueColor;\n\t\t\t\t\tconst mainLine = renderStatusline(\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\tfooterData,\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t\tconfig,\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\ttrueColor,\n\t\t\t\t\t);\n\t\t\t\t\tconst lines = mainLine ? mainLine.split(\"\\n\") : [];\n\t\t\t\t\tlines.push(\n\t\t\t\t\t\t...renderExtensionStatusline(\n\t\t\t\t\t\t\twidth,\n\t\t\t\t\t\t\tfooterData,\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tconfig,\n\t\t\t\t\t\t\truntime,\n\t\t\t\t\t\t\tmainLine,\n\t\t\t\t\t\t\ttrueColor,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn lines;\n\t\t\t\t},\n\t\t\t};\n\t\t});\n\t\trefreshGitStatus(cwd, generation);\n\t};\n\n\tconst agentDir = getAgentDir();\n\tconst configPath = settingsFilePath(agentDir);\n\tconst commandOptions: StatuslineCommandOptions = {\n\t\tsettingsPath: configPath,\n\t\tgetLoaded: () => loaded ?? loadStatuslineSettings(configPath),\n\t\tgetMenuOwner: () => {\n\t\t\tconst generation = sessionGeneration;\n\t\t\treturn {\n\t\t\t\tsignal: menuController.signal,\n\t\t\t\tisCurrent: () => generation === sessionGeneration && !menuController.signal.aborted,\n\t\t\t};\n\t\t},\n\t\tapply(next, ctx) {\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tpreviewPalettePreset = undefined;\n\t\t\tloaded = next;\n\t\t\trefresh();\n\t\t},\n\t\tpreview(palettePreset, ctx) {\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tpreviewPalettePreset = palettePreset;\n\t\t\trefresh();\n\t\t},\n\t};\n\tpi.registerCommand(\"statusline\", {\n\t\tdescription: \"Open or inspect the statusline settings\",\n\t\tgetArgumentCompletions: completeStatuslineArguments,\n\t\thandler: async (args, ctx) => {\n\t\t\tconst commands = await loadStatuslineCommands();\n\t\t\tif (ctx.sessionManager !== activeSessionManager) return;\n\t\t\tawait commands.handleStatuslineCommand(args, ctx, commandOptions);\n\t\t},\n\t});\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\truntime.turnCount = 0;\n\t\truntime.activeTools.clear();\n\t\truntime.isStreaming = false;\n\t\truntime.uiPrompt = undefined;\n\t\tloaded = loadStatuslineSettingsForAgent(agentDir);\n\t\tconst settingsNotice = consumeStatuslineSettingsNotice();\n\t\tif (settingsNotice) ctx.ui.notify(settingsNotice, \"warning\");\n\t\tif (loaded.diagnostics.length > 0) {\n\t\t\tctx.ui.notify(formatSettingsDiagnostics(loaded), \"warning\");\n\t\t}\n\t\truntime.thinkingLevel = pi.getThinkingLevel();\n\t\tinstallFooter(ctx);\n\t});\n\n\tpi.on(\"session_tree\", (_event, ctx) => {\n\t\tinstallFooter(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tsessionGeneration += 1;\n\t\tmenuController.abort(new DOMException(\"Statusline session shut down\", \"AbortError\"));\n\t\tactiveSessionManager = undefined;\n\t\tpreviewPalettePreset = undefined;\n\t\tactiveGitStatusTarget = undefined;\n\t\tabortGitStatusRefresh(\"Statusline session shut down\");\n\t\tclearGitStatusDebounce();\n\t\tpendingGitStatusRefresh = undefined;\n\t\truntime.gitStatus = undefined;\n\t\truntime.activeTools.clear();\n\t\truntime.isStreaming = false;\n\t\truntime.uiPrompt = undefined;\n\t\truntime.duplicateExtensions = [];\n\t\truntime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;\n\t\tctx.ui.setFooter(undefined);\n\t\tctx.ui.setStatus(STATUSLINE_KEY, undefined);\n\t\truntime.requestRender = undefined;\n\t});\n\n\tpi.on(\"model_select\", () => refresh());\n\n\tpi.on(\"thinking_level_select\", (event) => {\n\t\truntime.thinkingLevel = event.level;\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_start\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.isStreaming = true;\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_end\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.activeTools.clear();\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"agent_settled\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.isStreaming = false;\n\t\truntime.activeTools.clear();\n\t\trefresh();\n\t});\n\n\tpi.on(\"ui_prompt_start\", (event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.uiPrompt = { kind: event.kind, title: event.title };\n\t\trefresh();\n\t});\n\n\tpi.on(\"ui_prompt_end\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.uiPrompt = undefined;\n\t\trefresh();\n\t});\n\n\tpi.on(\"turn_start\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\truntime.turnCount += 1;\n\t\truntime.isStreaming = true;\n\t\trefresh();\n\t});\n\n\tpi.on(\"turn_end\", (_event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n\n\tpi.on(\"tool_execution_start\", (event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tconst currentCount = runtime.activeTools.get(event.toolName) ?? 0;\n\t\truntime.activeTools.set(event.toolName, currentCount + 1);\n\t\trefresh();\n\t});\n\n\tpi.on(\"tool_execution_end\", (event, ctx) => {\n\t\tif (!ownsRuntime(ctx)) return;\n\t\tconst currentCount = runtime.activeTools.get(event.toolName) ?? 0;\n\t\tif (currentCount <= 1) runtime.activeTools.delete(event.toolName);\n\t\telse runtime.activeTools.set(event.toolName, currentCount - 1);\n\n\t\tscheduleGitStatusRefreshForContext(ctx);\n\t\trefresh();\n\t});\n}\n\nfunction formatSettingsDiagnostics(loaded: LoadedStatuslineSettings): string {\n\tconst details = loaded.diagnostics.slice(0, 5).map((item) => item.message);\n\tconst remaining = loaded.diagnostics.length - details.length;\n\treturn [\n\t\t`pi-statusline settings: ${details.join(\"; \")}`,\n\t\t...(remaining > 0 ? [`+${remaining} more`] : []),\n\t].join(\" \");\n}\n\nexport {\n\tbuildExtensionStatusIconAliases,\n\ttype ExtensionStatusIconAliasMap,\n\textensionColor,\n\tformatExtensionStatus,\n\tnpmPackageName,\n\tsimplifyExtensionStatusText,\n\tsplitExtensionStatusIcon,\n\tstripExtensionStatusPrefix,\n\twrapExtensionStatusline,\n} from \"./extension-status.js\";\nexport {\n\tformatGitBranchText,\n\tformatGitBranchValue,\n\tformatGitStatusSummary,\n\ttype GitStatusSummary,\n\tparseGitRoot,\n\tparseGitStatusPorcelain,\n\treadGitStatus,\n} from \"./git-status.js\";\nexport {\n\tcontextColor,\n\tformatCount,\n\tformatToolActivity,\n\tprContextFromStatuses,\n\tprLinkFromStatuses,\n\tshortenModel,\n} from \"./render.js\";\nexport { normalizeStatuslineSettings, readStatuslineSettings } from \"./settings.js\";\n", "import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { getAgentDir, type Theme, type ThemeColor } from \"@earendil-works/pi-coding-agent\";\nimport { wrapTextWithAnsi } from \"@earendil-works/pi-tui\";\nimport { powerlineExtensionSeparator } from \"./powerline.js\";\nimport { DEFAULT_EXTENSION_STATUS_ICONS } from \"./settings.js\";\nimport type { StatuslineConfig } from \"./types.js\";\n\nexport type ExtensionStatusIconAliasMap = ReadonlyMap<string, readonly string[]>;\nexport interface ExtensionStatusRuntime {\n\tduplicateExtensions: string[];\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap;\n}\n\nconst STATUSLINE_KEY = \"statusline\";\nconst COMPATIBLE_STATUS_ICON_KEYS: Readonly<Record<string, string>> = {\n\tretry: \"unknown-error-retry\",\n\tsync: \"pisync\",\n\t\"unknown-error-retry\": \"retry\",\n\tpisync: \"sync\",\n};\nconst EMPTY_EXTENSION_STATUS_ICON_ALIASES: ExtensionStatusIconAliasMap = new Map();\nfunction extensionStatusSeparator(\n\tconfig: StatuslineConfig,\n\ttheme: Theme,\n\ttrueColor: boolean,\n): string {\n\treturn powerlineExtensionSeparator(theme, config.palettePreset, trueColor);\n}\n\nexport function formatExtensionStatuses(\n\tstatuses: ReadonlyMap<string, string>,\n\ttheme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: ExtensionStatusRuntime,\n\thiddenKeys: ReadonlySet<string> = new Set(),\n\ttrueColor = true,\n): string {\n\tconst separator = extensionStatusSeparator(config, theme, trueColor);\n\tconst visibleStatuses = [\n\t\t...formatDuplicateExtensionStatus(runtime, theme),\n\t\t...[...statuses.entries()]\n\t\t\t.filter(\n\t\t\t\t([key, value]) => key !== STATUSLINE_KEY && !hiddenKeys.has(key) && value.trim().length > 0,\n\t\t\t)\n\t\t\t.map(([key, value]) =>\n\t\t\t\tformatExtensionStatus(key, value, theme, config, runtime.extensionStatusIconAliases),\n\t\t\t),\n\t].slice(0, 5);\n\n\treturn visibleStatuses.join(separator);\n}\n\nexport function formatExtensionStatus(\n\tkey: string,\n\tvalue: string,\n\ttheme: Theme,\n\tconfig: Pick<StatuslineConfig, \"extensionStatusIcons\">,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap = EMPTY_EXTENSION_STATUS_ICON_ALIASES,\n): string {\n\tconst status = splitExtensionStatusIcon(stripExtensionStatusPrefix(key, value));\n\tconst text = simplifyExtensionStatusText(status.text);\n\tconst color = extensionColor(key, value);\n\tconst textColor = color === \"warning\" ? \"warning\" : \"muted\";\n\tconst icon = extensionStatusIcon(\n\t\tkey,\n\t\tstatus.icon,\n\t\tconfig.extensionStatusIcons,\n\t\textensionStatusIconAliases,\n\t);\n\tconst renderedText = theme.fg(textColor, text);\n\treturn icon ? `${theme.fg(color, icon)} ${renderedText}` : renderedText;\n}\n\nfunction extensionStatusIcon(\n\tkey: string,\n\tleadingIcon: string | undefined,\n\tconfiguredIcons: Record<string, string>,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap,\n) {\n\tif (Object.hasOwn(configuredIcons, key)) return configuredIcons[key];\n\tconst namespaceIcon = configuredNamespaceIcon(key, configuredIcons);\n\tif (namespaceIcon !== undefined) return namespaceIcon;\n\tconst compatibleKey = COMPATIBLE_STATUS_ICON_KEYS[key];\n\tif (compatibleKey && Object.hasOwn(configuredIcons, compatibleKey)) {\n\t\treturn configuredIcons[compatibleKey];\n\t}\n\tfor (const alias of extensionStatusAliasesForKey(key, extensionStatusIconAliases)) {\n\t\tif (Object.hasOwn(configuredIcons, alias)) return configuredIcons[alias];\n\t}\n\treturn leadingIcon ?? DEFAULT_EXTENSION_STATUS_ICONS[key] ?? \"\uD83D\uDD0C\";\n}\n\nfunction configuredNamespaceIcon(\n\tkey: string,\n\tconfiguredIcons: Readonly<Record<string, string>>,\n): string | undefined {\n\tlet match: { baseLength: number; icon: string } | undefined;\n\tfor (const [selector, icon] of Object.entries(configuredIcons)) {\n\t\tif (!selector.endsWith(\":*\")) continue;\n\t\tconst base = selector.slice(0, -2);\n\t\tif (!base || !key.startsWith(`${base}:`)) continue;\n\t\tif (!match || base.length > match.baseLength) match = { baseLength: base.length, icon };\n\t}\n\treturn match?.icon;\n}\n\nfunction extensionStatusAliasesForKey(\n\tkey: string,\n\textensionStatusIconAliases: ExtensionStatusIconAliasMap,\n): readonly string[] {\n\tfor (const [statusBase, aliases] of extensionStatusIconAliases) {\n\t\tif (statusKeyMatchesStatusBase(key, statusBase)) return aliases;\n\t}\n\treturn [];\n}\n\nfunction statusKeyMatchesStatusBase(key: string, statusBase: string): boolean {\n\treturn key === statusBase || key.startsWith(`${statusBase}:`) || key.startsWith(`${statusBase}/`);\n}\n\nexport function wrapExtensionStatusline(status: string, width: number): string[] {\n\tif (!status || width <= 0) return [];\n\treturn wrapTextWithAnsi(status, width);\n}\n\nfunction formatDuplicateExtensionStatus(runtime: ExtensionStatusRuntime, theme: Theme): string[] {\n\tif (runtime.duplicateExtensions.length === 0) return [];\n\tconst names = runtime.duplicateExtensions.slice(0, 2).join(\", \");\n\tconst suffix =\n\t\truntime.duplicateExtensions.length > 2 ? ` +${runtime.duplicateExtensions.length - 2}` : \"\";\n\treturn [`${theme.fg(\"warning\", \"\u26A0\uFE0F\")} ${theme.fg(\"warning\", `dup ${names}${suffix}`)}`];\n}\n\nexport function splitExtensionStatusIcon(value: string): { icon?: string; text: string } {\n\tconst trimmed = value.trim();\n\tconst [firstToken, ...restTokens] = trimmed.split(/\\s+/);\n\tif (firstToken && isEmojiOnlyToken(firstToken)) {\n\t\treturn { icon: firstToken, text: restTokens.join(\" \") };\n\t}\n\treturn { text: trimmed };\n}\n\nfunction isEmojiOnlyToken(value: string): boolean {\n\treturn /^(?=.*(?:\\p{Extended_Pictographic}|\\p{Regional_Indicator}|[0-9#*]\\ufe0f?\\u20e3))(?:\\p{Extended_Pictographic}|\\p{Emoji_Modifier}|\\p{Regional_Indicator}|\\u200d|\\ufe0f|[0-9#*]\\ufe0f?\\u20e3)+$/u.test(\n\t\tvalue,\n\t);\n}\n\nexport function extensionColor(key: string, value: string): ThemeColor {\n\tconst normalized = `${key} ${value}`.toLowerCase();\n\tif (/missing|error|fail|conflict|duplicate|unavailable/.test(normalized)) return \"warning\";\n\tif (normalized.includes(\"codex\")) return \"accent\";\n\tif (/ready|active|running|enabled|awake|ok/.test(normalized)) return \"success\";\n\treturn \"muted\";\n}\n\nexport function stripExtensionStatusPrefix(key: string, value: string): string {\n\treturn value.trim().replace(new RegExp(`^${escapeRegExp(key)}\\\\s*:\\\\s*`, \"iu\"), \"\");\n}\n\nexport function simplifyExtensionStatusText(value: string): string {\n\treturn value\n\t\t.trim()\n\t\t.replace(/\\bready\\b/giu, \"\u2713\")\n\t\t.replace(/\\bmissing\\b/giu, \"\u2717\")\n\t\t.replace(/,\\s*/g, \" \")\n\t\t.replace(/\\s+\\([^)]*\\)\\s*$/, \"\")\n\t\t.replace(/\\s+/g, \" \");\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\ninterface InstalledExtensionPackage {\n\tpackageName: string;\n\tsource: string;\n\tidentity: string;\n}\n\nexport function readInstalledExtensionPackages(cwd: string): InstalledExtensionPackage[] {\n\tconst packages: InstalledExtensionPackage[] = [];\n\tconst settingsFiles = extensionSettingsFiles(cwd);\n\n\tfor (const settingsFile of settingsFiles) {\n\t\tconst baseDirectory = dirname(settingsFile);\n\t\tfor (const rawSource of readPackageSources(settingsFile)) {\n\t\t\tconst source = rawSource.trim();\n\t\t\tif (!source) continue;\n\t\t\tconst packageName = packageNameForSource(source, baseDirectory);\n\t\t\tif (!packageName) continue;\n\t\t\tpackages.push({ packageName, source, identity: sourceIdentity(source, baseDirectory) });\n\t\t}\n\t}\n\n\treturn packages;\n}\n\nfunction extensionSettingsFiles(cwd: string): string[] {\n\treturn [join(getAgentDir(), \"settings.json\"), join(cwd, \".pi\", \"settings.json\")].filter((file) =>\n\t\texistsSync(file),\n\t);\n}\n\nexport function findDuplicateExtensions(\n\tinstalledPackages: readonly InstalledExtensionPackage[],\n): string[] {\n\tconst sourcesByPackage = new Map<string, Set<string>>();\n\n\tfor (const extensionPackage of installedPackages) {\n\t\tconst sources = sourcesByPackage.get(extensionPackage.packageName) ?? new Set<string>();\n\t\tsources.add(extensionPackage.identity);\n\t\tsourcesByPackage.set(extensionPackage.packageName, sources);\n\t}\n\n\treturn [...sourcesByPackage.entries()]\n\t\t.filter(([, sources]) => sources.size > 1)\n\t\t.map(([packageName]) => packageName.replace(/^@[^/]+\\//, \"\").replace(/^pi-/, \"\"));\n}\n\nexport function buildExtensionStatusIconAliases(\n\tinstalledPackages: readonly { packageName: string; source?: string }[],\n): Map<string, string[]> {\n\tconst packageAliasesByStatusBase = new Map<string, Map<string, string[]>>();\n\n\tfor (const extensionPackage of installedPackages) {\n\t\tconst candidate = extensionStatusIconAliasCandidate(\n\t\t\textensionPackage.packageName,\n\t\t\textensionPackage.source,\n\t\t);\n\t\tif (!candidate) continue;\n\t\tconst aliasesByPackage =\n\t\t\tpackageAliasesByStatusBase.get(candidate.statusBase) ?? new Map<string, string[]>();\n\t\tconst existingAliases = aliasesByPackage.get(extensionPackage.packageName) ?? [];\n\t\taliasesByPackage.set(\n\t\t\textensionPackage.packageName,\n\t\t\tuniqueStrings([...existingAliases, ...candidate.aliases]),\n\t\t);\n\t\tpackageAliasesByStatusBase.set(candidate.statusBase, aliasesByPackage);\n\t}\n\n\tconst aliases = new Map<string, string[]>();\n\tfor (const [statusBase, aliasesByPackage] of packageAliasesByStatusBase) {\n\t\tif (aliasesByPackage.size === 1)\n\t\t\taliases.set(statusBase, [...aliasesByPackage.values()][0] ?? []);\n\t}\n\treturn aliases;\n}\n\nfunction extensionStatusIconAliasCandidate(\n\tpackageName: string,\n\tsource?: string,\n): { statusBase: string; aliases: string[] } | undefined {\n\tconst packageBase = packageBaseName(packageName);\n\tconst statusBase = statusBaseFromPackageBase(packageBase);\n\tif (!statusBase) return undefined;\n\n\tconst sourceAliases = source?.startsWith(\"npm:\") ? [source, `npm:${npmPackageName(source)}`] : [];\n\treturn {\n\t\tstatusBase,\n\t\taliases: uniqueStrings([...sourceAliases, packageName, packageBase, statusBase]),\n\t};\n}\n\nfunction packageBaseName(packageName: string): string {\n\tconst slashIndex = packageName.lastIndexOf(\"/\");\n\treturn slashIndex === -1 ? packageName : packageName.slice(slashIndex + 1);\n}\n\nfunction statusBaseFromPackageBase(packageBase: string): string {\n\treturn packageBase.startsWith(\"pi-\") && packageBase.length > \"pi-\".length\n\t\t? packageBase.slice(\"pi-\".length)\n\t\t: packageBase;\n}\n\nfunction uniqueStrings(values: readonly string[]): string[] {\n\treturn [...new Set(values.filter((value) => value.length > 0))];\n}\n\nfunction readPackageSources(settingsFile: string): string[] {\n\ttry {\n\t\tconst settings = JSON.parse(readFileSync(settingsFile, \"utf8\")) as { packages?: unknown[] };\n\t\treturn (settings.packages ?? [])\n\t\t\t.map((entry) => {\n\t\t\t\tif (typeof entry === \"string\") return entry;\n\t\t\t\tif (\n\t\t\t\t\tentry &&\n\t\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\t\ttypeof (entry as { source?: unknown }).source === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (entry as { source: string }).source;\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t})\n\t\t\t.filter((source): source is string => source !== undefined);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nfunction packageNameForSource(source: string, baseDirectory: string): string | undefined {\n\tif (source.startsWith(\"npm:\")) return npmPackageName(source);\n\tconst packageJson = join(resolveSourcePath(source, baseDirectory), \"package.json\");\n\ttry {\n\t\tconst packageData = JSON.parse(readFileSync(packageJson, \"utf8\")) as { name?: unknown };\n\t\treturn typeof packageData.name === \"string\" ? packageData.name : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport function npmPackageName(source: string): string {\n\tconst spec = source.slice(\"npm:\".length);\n\tif (spec.startsWith(\"@\")) return spec.split(\"@\").slice(0, 2).join(\"@\");\n\treturn spec.split(\"@\")[0] ?? spec;\n}\n\nfunction sourceIdentity(source: string, baseDirectory: string): string {\n\tif (source.startsWith(\"npm:\")) return `npm:${npmPackageName(source)}`;\n\treturn resolveSourcePath(source, baseDirectory);\n}\n\nfunction resolveSourcePath(source: string, baseDirectory: string): string {\n\treturn isAbsolute(source) ? source : resolve(baseDirectory, source);\n}\n", "import type { Theme } from \"@earendil-works/pi-coding-agent\";\nimport { visibleWidth } from \"@earendil-works/pi-tui\";\nimport { ansiStyle } from \"./ansi.js\";\nimport { resolvePreset } from \"./presets/index.js\";\nimport type { BlockColors, PowerlinePreset } from \"./presets/types.js\";\nimport {\n\tLINE_BREAK_SEGMENT_NAME,\n\ttype PalettePreset,\n\ttype PowerlineBlockName,\n\ttype RenderItem,\n\ttype RenderSegment,\n\ttype SegmentPalette,\n\ttype SeparatorName,\n\ttype StatuslineConfig,\n} from \"./types.js\";\n\ninterface PowerlineBlock {\n\tbaseBlock: PowerlineBlockName;\n\tcolors: BlockColors;\n\tsegments: RenderSegment[];\n}\n\nexport function renderPowerlineStatusline(\n\twidth: number,\n\titems: RenderItem[],\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n\ttrueColor = true,\n): string {\n\tif (items.length === 0 || width <= 0) return \"\";\n\treturn splitLines(items)\n\t\t.map((segments) => fitPowerlineSegments(segments, width, config, trueColor))\n\t\t.join(\"\\n\");\n}\n\nfunction splitLines(items: RenderItem[]): RenderSegment[][] {\n\tconst lines: RenderSegment[][] = [[]];\n\tfor (const item of items) {\n\t\tif (item.name === LINE_BREAK_SEGMENT_NAME) lines.push([]);\n\t\telse lines.at(-1)?.push(item);\n\t}\n\treturn lines;\n}\n\nconst SEGMENT_RETENTION_PRIORITY: Readonly<Record<RenderSegment[\"name\"], number>> = {\n\tcontext: 120,\n\tmodel: 110,\n\tbranch: 100,\n\ttools: 90,\n\tcwd: 80,\n\tthinking: 70,\n\tcost: 60,\n\tprovider: 50,\n\tcache: 45,\n\ttokens: 40,\n\ttime: 30,\n\tturn: 20,\n\tbrand: 10,\n};\n\nfunction fitPowerlineSegments(\n\tsegments: readonly RenderSegment[],\n\twidth: number,\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n\ttrueColor: boolean,\n): string {\n\tif (segments.length === 0) return \"\";\n\tconst fitted = [...segments];\n\twhile (fitted.length > 1) {\n\t\tconst rendered = joinPowerlineSegments(fitted, config, trueColor);\n\t\tif (visibleWidth(rendered) <= width) return rendered;\n\t\tlet removalIndex = 0;\n\t\tfor (let index = 1; index < fitted.length; index += 1) {\n\t\t\tconst candidate = fitted[index];\n\t\t\tconst current = fitted[removalIndex];\n\t\t\tif (\n\t\t\t\tcandidate &&\n\t\t\t\tcurrent &&\n\t\t\t\tSEGMENT_RETENTION_PRIORITY[candidate.name] < SEGMENT_RETENTION_PRIORITY[current.name]\n\t\t\t) {\n\t\t\t\tremovalIndex = index;\n\t\t\t}\n\t\t}\n\t\tfitted.splice(removalIndex, 1);\n\t}\n\tconst rendered = joinPowerlineSegments(fitted, config, trueColor);\n\treturn visibleWidth(rendered) <= width ? rendered : \"\";\n}\n\nexport function powerlineExtensionSeparator(\n\t_theme: Theme,\n\tpalettePreset: PalettePreset = \"tokyo-night\",\n\ttrueColor = true,\n): string {\n\treturn ansiStyle(\" \u2022 \", { fg: resolvePreset(palettePreset).extensionSeparator }, trueColor);\n}\n\nfunction joinPowerlineSegments(\n\tsegments: RenderSegment[],\n\tconfig: Pick<StatuslineConfig, \"palettePreset\" | \"palette\" | \"density\" | \"separator\">,\n\ttrueColor: boolean,\n): string {\n\tconst preset = resolvePreset(config.palettePreset);\n\tconst blocks = contiguousBlocks(segments, preset, config.palettePreset, config.palette);\n\tlet line = ansiStyle(\"\u2591\u2592\u2593\", { fg: preset.lead }, trueColor);\n\n\tfor (const [index, block] of blocks.entries()) {\n\t\tconst previous = index === 0 ? undefined : blocks[index - 1]?.colors;\n\t\tif (previous) {\n\t\t\tline += ansiStyle(\"\uE0B4\", { fg: previous.bg, bg: block.colors.bg }, trueColor);\n\t\t}\n\t\tline += ansiStyle(formatBlockText(block, config), block.colors, trueColor);\n\t}\n\n\tconst lastBlock = blocks.at(-1);\n\tif (lastBlock) line += ansiStyle(\"\uE0B4\", { fg: lastBlock.colors.bg }, trueColor);\n\treturn line;\n}\n\nfunction contiguousBlocks(\n\tsegments: RenderSegment[],\n\tpreset: PowerlinePreset,\n\tpalettePreset: PalettePreset,\n\tconfiguredPalette: SegmentPalette,\n): PowerlineBlock[] {\n\tconst blocks: PowerlineBlock[] = [];\n\tconst usesConfiguredColors = palettePreset === \"custom\";\n\tfor (const segment of segments) {\n\t\tconst colors = usesConfiguredColors\n\t\t\t? (configuredPalette[segment.name] ?? {})\n\t\t\t: preset.blocks[segment.block];\n\t\tconst previous = blocks.at(-1);\n\t\tconst matchesPrevious =\n\t\t\tprevious !== undefined &&\n\t\t\t(usesConfiguredColors\n\t\t\t\t? colorsEqual(previous.colors, colors)\n\t\t\t\t: previous.baseBlock === segment.block);\n\t\tif (matchesPrevious) previous.segments.push(segment);\n\t\telse blocks.push({ baseBlock: segment.block, colors, segments: [segment] });\n\t}\n\treturn blocks;\n}\n\nfunction colorsEqual(left: BlockColors, right: BlockColors): boolean {\n\treturn left.fg === right.fg && left.bg === right.bg;\n}\n\nfunction formatBlockText(\n\tblock: PowerlineBlock,\n\tconfig: Pick<StatuslineConfig, \"density\" | \"separator\">,\n): string {\n\tconst texts = block.segments.map(formatSegmentText);\n\tconst separator = separatorText(config.separator, config.density === \"cozy\");\n\tconst leading = config.density === \"cozy\" ? \" \" : \" \";\n\tconst trailing = config.density === \"cozy\" ? \" \" : \"\";\n\treturn `${leading}${texts.join(separator)}${trailing}`;\n}\n\nfunction formatSegmentText(segment: RenderSegment): string {\n\treturn segment.emphasis ? `\\u001b[1m${segment.text}\\u001b[22m` : segment.text;\n}\n\nfunction separatorText(separator: SeparatorName, cozy: boolean): string {\n\tconst padding = cozy ? \" \" : \" \";\n\tswitch (separator) {\n\t\tcase \"dot\":\n\t\t\treturn `${padding}\u2022${padding}`;\n\t\tcase \"bar\":\n\t\t\treturn `${padding}\u2502${padding}`;\n\t\tcase \"powerline\":\n\t\t\treturn `${padding}\uE0B1${padding}`;\n\t\tcase \"round\":\n\t\t\treturn `${padding}\u276F${padding}`;\n\t\tcase \"none\":\n\t\t\treturn padding;\n\t}\n}\n", "export function ansiStyle(\n\ttext: string,\n\tcolors: { fg?: string; bg?: string },\n\ttrueColor = true,\n): string {\n\tconst codes = [\n\t\tcolors.fg ? colorCode(\"38\", colors.fg, trueColor) : undefined,\n\t\tcolors.bg ? colorCode(\"48\", colors.bg, trueColor) : undefined,\n\t].filter((code): code is string => code !== undefined);\n\tif (codes.length === 0) return text;\n\treturn `\\u001b[${codes.join(\";\")}m${text}\\u001b[0m`;\n}\n\nexport function ansiFg(hex: string, text: string, trueColor = true): string {\n\treturn ansiStyle(text, { fg: hex }, trueColor);\n}\n\nfunction colorCode(prefix: \"38\" | \"48\", hex: string, trueColor: boolean): string {\n\tconst { red, green, blue } = hexToRgb(hex);\n\treturn trueColor\n\t\t? `${prefix};2;${red};${green};${blue}`\n\t\t: `${prefix};5;${rgbToAnsi256(red, green, blue)}`;\n}\n\nfunction rgbToAnsi256(red: number, green: number, blue: number): number {\n\tconst channels = [red, green, blue].map((value) => Math.round((value / 255) * 5));\n\treturn 16 + 36 * (channels[0] ?? 0) + 6 * (channels[1] ?? 0) + (channels[2] ?? 0);\n}\n\nfunction hexToRgb(hex: string): { red: number; green: number; blue: number } {\n\tconst normalized = hex.replace(/^#/, \"\");\n\treturn {\n\t\tred: Number.parseInt(normalized.slice(0, 2), 16),\n\t\tgreen: Number.parseInt(normalized.slice(2, 4), 16),\n\t\tblue: Number.parseInt(normalized.slice(4, 6), 16),\n\t};\n}\n", "import { isAbsolute } from \"node:path\";\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\n\nconst GIT_STATUS_TIMEOUT_MS = 3_000;\n\nexport interface GitStatusSummary {\n\troot?: string;\n\tahead: number;\n\tbehind: number;\n\tstaged: number;\n\tmodified: number;\n\tuntracked: number;\n\tconflicts: number;\n}\n\nexport async function readGitStatus(\n\tpi: ExtensionAPI,\n\tcwd: string,\n\tsignal?: AbortSignal,\n): Promise<GitStatusSummary | undefined> {\n\tconst [statusResult, rootResult] = await Promise.all([\n\t\tpi.exec(\n\t\t\t\"git\",\n\t\t\t[\"--no-optional-locks\", \"status\", \"--porcelain=v1\", \"--branch\", \"--untracked-files=normal\"],\n\t\t\t{ cwd, timeout: GIT_STATUS_TIMEOUT_MS, signal },\n\t\t),\n\t\tpi\n\t\t\t.exec(\"git\", [\"rev-parse\", \"--path-format=absolute\", \"--show-toplevel\"], {\n\t\t\t\tcwd,\n\t\t\t\ttimeout: GIT_STATUS_TIMEOUT_MS,\n\t\t\t\tsignal,\n\t\t\t})\n\t\t\t.catch(() => undefined),\n\t]);\n\tif (statusResult.code !== 0 || statusResult.killed) return undefined;\n\tconst summary = parseGitStatusPorcelain(statusResult.stdout);\n\tif (rootResult && rootResult.code === 0 && !rootResult.killed) {\n\t\tconst root = parseGitRoot(rootResult.stdout);\n\t\tif (root) summary.root = root;\n\t}\n\treturn summary;\n}\n\nexport function parseGitStatusPorcelain(output: string): GitStatusSummary {\n\tconst summary: GitStatusSummary = {\n\t\tahead: 0,\n\t\tbehind: 0,\n\t\tstaged: 0,\n\t\tmodified: 0,\n\t\tuntracked: 0,\n\t\tconflicts: 0,\n\t};\n\tfor (const line of output.split(/\\r?\\n/)) {\n\t\tif (!line) continue;\n\t\tif (line.startsWith(\"## \")) {\n\t\t\tconst ahead = line.match(/\\bahead (\\d+)/u);\n\t\t\tconst behind = line.match(/\\bbehind (\\d+)/u);\n\t\t\tsummary.ahead = ahead ? Number(ahead[1]) : 0;\n\t\t\tsummary.behind = behind ? Number(behind[1]) : 0;\n\t\t\tcontinue;\n\t\t}\n\t\tconst indexStatus = line[0] ?? \" \";\n\t\tconst worktreeStatus = line[1] ?? \" \";\n\t\tif (indexStatus === \"?\" && worktreeStatus === \"?\") {\n\t\t\tsummary.untracked += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isConflictStatus(indexStatus, worktreeStatus)) {\n\t\t\tsummary.conflicts += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isChangedStatus(indexStatus)) summary.staged += 1;\n\t\tif (isChangedStatus(worktreeStatus)) summary.modified += 1;\n\t}\n\treturn summary;\n}\n\nfunction isConflictStatus(indexStatus: string, worktreeStatus: string): boolean {\n\treturn (\n\t\t(indexStatus === \"D\" && worktreeStatus === \"D\") ||\n\t\t(indexStatus === \"A\" && worktreeStatus === \"A\") ||\n\t\tindexStatus === \"U\" ||\n\t\tworktreeStatus === \"U\"\n\t);\n}\n\nfunction isChangedStatus(status: string): boolean {\n\treturn status !== \" \" && status !== \"?\" && status !== \"!\";\n}\n\nexport function parseGitRoot(output: string): string | undefined {\n\tconst root = output.split(/\\r?\\n/u)[0]?.trim();\n\treturn root && isAbsolute(root) ? root : undefined;\n}\n\nexport function formatGitStatusSummary(summary: GitStatusSummary | undefined): string {\n\tif (!summary) return \"\";\n\tconst tokens = [\n\t\t[\"\u21E1\", summary.ahead],\n\t\t[\"\u21E3\", summary.behind],\n\t\t[\"+\", summary.staged],\n\t\t[\"~\", summary.modified],\n\t\t[\"?\", summary.untracked],\n\t\t[\"!\", summary.conflicts],\n\t] as const;\n\treturn tokens\n\t\t.filter(([, count]) => count > 0)\n\t\t.map(([prefix, count]) => `${prefix}${formatCount(count)}`)\n\t\t.join(\" \");\n}\n\nexport function formatGitBranchValue(\n\tbranch: string | null,\n\tstatus: GitStatusSummary | undefined,\n\tpr?: string,\n): string {\n\tif (!branch) return \"no-git\";\n\tconst suffixes = [formatGitStatusSummary(status), pr ? `(${pr})` : \"\"].filter(Boolean);\n\treturn suffixes.length > 0 ? `${branch} ${suffixes.join(\" \")}` : branch;\n}\n\nexport function formatGitBranchText(\n\tbranch: string | null,\n\tstatus: GitStatusSummary | undefined,\n\tpr?: string,\n): string {\n\treturn `\uD83C\uDF3F ${formatGitBranchValue(branch, status, pr)}`;\n}\n\nexport function gitStatusSummaryEqual(\n\tleft: GitStatusSummary | undefined,\n\tright: GitStatusSummary | undefined,\n): boolean {\n\tif (!left || !right) return left === right;\n\treturn (\n\t\tleft.root === right.root &&\n\t\tleft.ahead === right.ahead &&\n\t\tleft.behind === right.behind &&\n\t\tleft.staged === right.staged &&\n\t\tleft.modified === right.modified &&\n\t\tleft.untracked === right.untracked &&\n\t\tleft.conflicts === right.conflicts\n\t);\n}\n\nfunction formatCount(value: number): string {\n\treturn Intl.NumberFormat(\"en\", { notation: \"compact\", maximumFractionDigits: 1 }).format(value);\n}\n", "import type {\n\tExtensionAPI,\n\tExtensionContext,\n\tReadonlyFooterDataProvider,\n\tTheme,\n\tThemeColor,\n\tUIPromptKind,\n} from \"@earendil-works/pi-coding-agent\";\nimport { sliceByColumn, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { sanitizeTerminalText } from \"@narumitw/pi-tui-kit/terminal-text\";\nimport { formatDirectoryPath } from \"./directory.js\";\nimport {\n\ttype ExtensionStatusRuntime,\n\tformatExtensionStatuses,\n\twrapExtensionStatusline,\n} from \"./extension-status.js\";\nimport { formatGitBranchValue, type GitStatusSummary } from \"./git-status.js\";\nimport { renderPowerlineStatusline } from \"./powerline.js\";\nimport {\n\tLINE_BREAK_SEGMENT_NAME,\n\ttype PowerlineBlockName,\n\ttype RenderItem,\n\ttype RenderSegment,\n\ttype SegmentName,\n\ttype StatuslineConfig,\n\ttype TruncationDirection,\n} from \"./types.js\";\nimport { type FooterUsageSummary, summarizeFooterUsage } from \"./usage.js\";\n\ntype ThinkingLevel = ReturnType<ExtensionAPI[\"getThinkingLevel\"]>;\nexport interface RuntimeState extends ExtensionStatusRuntime {\n\thomeDir?: string;\n\tturnCount: number;\n\tactiveTools: Map<string, number>;\n\tisStreaming: boolean;\n\tuiPrompt?: { kind: UIPromptKind; title?: string };\n\tthinkingLevel: ThinkingLevel;\n\tgitStatus?: GitStatusSummary;\n\trequestRender?: () => void;\n}\nconst GITHUB_PR_KEY = \"github-pr\";\nconst GITHUB_PR_STATUS_KEYS = new Set([GITHUB_PR_KEY]);\nexport function renderStatusline(\n\twidth: number,\n\tctx: ExtensionContext,\n\tfooterData: ReadonlyFooterDataProvider,\n\t_theme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n\ttrueColor = true,\n): string {\n\tif (width <= 0) return \"\";\n\n\tconst usageSummary = summarizeFooterUsage(ctx.sessionManager.getEntries());\n\tconst rows: Array<{ configuredSegments: number; segments: RenderSegment[] }> = [\n\t\t{ configuredSegments: 0, segments: [] },\n\t];\n\tfor (const name of config.segments) {\n\t\tif (name === LINE_BREAK_SEGMENT_NAME) {\n\t\t\trows.push({ configuredSegments: 0, segments: [] });\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst row = rows.at(-1);\n\t\tif (!row) continue;\n\t\trow.configuredSegments += 1;\n\t\tconst rendered = buildSegment(name, ctx, footerData, config, runtime, usageSummary);\n\t\tif (rendered && rendered.text.length > 0) row.segments.push(rendered);\n\t}\n\n\tconst segments: RenderItem[] = [];\n\tconst renderedRows = rows.filter(\n\t\t(row) => row.configuredSegments === 0 || row.segments.length > 0,\n\t);\n\tfor (const [index, row] of renderedRows.entries()) {\n\t\tif (index > 0) segments.push({ name: LINE_BREAK_SEGMENT_NAME });\n\t\tsegments.push(...row.segments);\n\t}\n\n\treturn renderPowerlineStatusline(width, segments, config, trueColor);\n}\n\nexport function renderExtensionStatusline(\n\twidth: number,\n\tfooterData: ReadonlyFooterDataProvider,\n\ttheme: Theme,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n\tmainLine: string,\n\ttrueColor = true,\n): string[] {\n\tconst statuses = footerData.getExtensionStatuses();\n\tconst prContext = prContextFromStatuses(statuses);\n\tconst rendersPrInline = prContext !== undefined && mainLine.includes(prContext);\n\tconst status = formatExtensionStatuses(\n\t\tstatuses,\n\t\ttheme,\n\t\tconfig,\n\t\truntime,\n\t\trendersPrInline ? GITHUB_PR_STATUS_KEYS : undefined,\n\t\ttrueColor,\n\t);\n\treturn wrapExtensionStatusline(status, width);\n}\n\nfunction buildSegment(\n\tname: SegmentName,\n\tctx: ExtensionContext,\n\tfooterData: ReadonlyFooterDataProvider,\n\tconfig: StatuslineConfig,\n\truntime: RuntimeState,\n\tusageSummary: FooterUsageSummary,\n): RenderSegment | undefined {\n\tswitch (name) {\n\t\tcase \"brand\":\n\t\t\treturn segment(name, \"\u03C0\", config, \"accent\", \"header\", true);\n\t\tcase \"provider\":\n\t\t\treturn segment(name, ctx.model?.provider ?? \"no-provider\", config, \"accent\", \"header\");\n\t\tcase \"model\": {\n\t\t\tconst presentation = config.segmentText.model;\n\t\t\tconst model = truncateModel(\n\t\t\t\tshortenModel(ctx.model?.id ?? \"no-model\"),\n\t\t\t\tpresentation.truncationLength,\n\t\t\t\tpresentation.truncationSymbol,\n\t\t\t\tpresentation.truncationDirection,\n\t\t\t);\n\t\t\treturn segment(name, model, config, \"accent\", \"header\");\n\t\t}\n\t\tcase \"thinking\":\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\truntime.thinkingLevel,\n\t\t\t\tconfig,\n\t\t\t\tthinkingColor(runtime.thinkingLevel),\n\t\t\t\t\"header\",\n\t\t\t);\n\t\tcase \"branch\": {\n\t\t\tconst branch = footerData.getGitBranch();\n\t\t\tconst pr = branch ? prContextFromStatuses(footerData.getExtensionStatuses()) : undefined;\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\tformatGitBranchValue(branch, runtime.gitStatus, pr),\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"git\",\n\t\t\t);\n\t\t}\n\t\tcase \"cwd\":\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\tformatDirectoryPath(ctx.cwd, runtime.homeDir, runtime.gitStatus?.root),\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"directory\",\n\t\t\t);\n\t\tcase \"tools\": {\n\t\t\tconst activity = formatToolActivity(runtime);\n\t\t\treturn activity ? segment(name, activity, config, \"accent\", \"runtime\") : undefined;\n\t\t}\n\t\tcase \"context\": {\n\t\t\tconst usage = ctx.getContextUsage();\n\t\t\tconst percentage =\n\t\t\t\tusage?.percent === null || usage?.percent === undefined\n\t\t\t\t\t? \"?\"\n\t\t\t\t\t: `${usage.percent.toFixed(1)}%`;\n\t\t\tconst contextWindow = usage?.contextWindow ?? ctx.model?.contextWindow ?? 0;\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\t`${percentage}/${formatCount(contextWindow)}`,\n\t\t\t\tconfig,\n\t\t\t\tcontextColor(usage?.percent),\n\t\t\t\t\"runtime\",\n\t\t\t);\n\t\t}\n\t\tcase \"tokens\": {\n\t\t\tconst value =\n\t\t\t\tusageSummary.input === 0 && usageSummary.output === 0\n\t\t\t\t\t? \"tok 0\"\n\t\t\t\t\t: `\u2191${formatCount(usageSummary.input)} \u2193${formatCount(usageSummary.output)}`;\n\t\t\treturn segment(name, value, config, \"accent\", \"runtime\");\n\t\t}\n\t\tcase \"cache\": {\n\t\t\tif (usageSummary.cacheRead === 0 && usageSummary.cacheWrite === 0) return undefined;\n\t\t\tconst values: string[] = [];\n\t\t\tif (usageSummary.cacheRead > 0) values.push(`R${formatCount(usageSummary.cacheRead)}`);\n\t\t\tif (usageSummary.cacheWrite > 0) values.push(`W${formatCount(usageSummary.cacheWrite)}`);\n\t\t\tif (usageSummary.latestCacheHitRate !== undefined) {\n\t\t\t\tvalues.push(`CH${usageSummary.latestCacheHitRate.toFixed(1)}%`);\n\t\t\t}\n\t\t\treturn segment(name, values.join(\" \"), config, \"accent\", \"runtime\");\n\t\t}\n\t\tcase \"cost\": {\n\t\t\tconst subscription = isSubscriptionBacked(ctx) ? \" (sub)\" : \"\";\n\t\t\treturn segment(\n\t\t\t\tname,\n\t\t\t\t`${usageSummary.cost.toFixed(usageSummary.cost >= 1 ? 2 : 3)}${subscription}`,\n\t\t\t\tconfig,\n\t\t\t\t\"accent\",\n\t\t\t\t\"meter\",\n\t\t\t);\n\t\t}\n\t\tcase \"time\":\n\t\t\treturn segment(name, formatTime(), config, \"accent\", \"meter\");\n\t\tcase \"turn\":\n\t\t\treturn segment(name, `${runtime.turnCount}`, config, \"accent\", \"meter\");\n\t}\n}\n\nfunction segment(\n\tname: SegmentName,\n\tvalue: string,\n\tconfig: StatuslineConfig,\n\tcolor: RenderSegment[\"color\"],\n\tblock: PowerlineBlockName,\n\temphasis = false,\n): RenderSegment {\n\treturn { name, text: formatConfiguredSegment(name, value, config), color, block, emphasis };\n}\n\nexport function formatConfiguredSegment(\n\tname: SegmentName,\n\tvalue: string,\n\tconfig: Pick<StatuslineConfig, \"segmentText\">,\n): string {\n\tconst presentation = config.segmentText[name];\n\treturn `${presentation.prefix}${value}${presentation.suffix}`;\n}\n\nfunction thinkingColor(level: ThinkingLevel): ThemeColor {\n\tswitch (level as string) {\n\t\tcase \"off\":\n\t\t\treturn \"dim\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\" as ThemeColor;\n\t\tdefault:\n\t\t\treturn \"dim\";\n\t}\n}\n\nexport function contextColor(percent: number | null | undefined): ThemeColor {\n\tif (percent === null || percent === undefined) return \"dim\";\n\tif (percent >= 90) return \"error\";\n\tif (percent >= 70) return \"warning\";\n\treturn \"success\";\n}\n\nconst MAX_UI_PROMPT_TITLE_CODE_POINTS = 256;\nconst MAX_UI_PROMPT_TITLE_WIDTH = 40;\n\nfunction boundUIPromptTitleLength(title: string): string {\n\tlet end = 0;\n\tlet ellipsisEnd = 0;\n\tlet codePoints = 0;\n\twhile (end < title.length && codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) {\n\t\tconst codePoint = title.codePointAt(end) ?? 0;\n\t\tend += codePoint > 0xffff ? 2 : 1;\n\t\tcodePoints += 1;\n\t\tif (codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) ellipsisEnd = end;\n\t}\n\treturn end < title.length ? `${title.slice(0, ellipsisEnd)}\u2026` : title;\n}\n\nfunction formatUIPromptTitle(title: string | undefined): string {\n\tconst safeTitle = title ? sanitizeTerminalText(title).trim() : \"\";\n\tconst boundedTitle = boundUIPromptTitleLength(safeTitle);\n\tif (visibleWidth(boundedTitle) <= MAX_UI_PROMPT_TITLE_WIDTH) return boundedTitle;\n\treturn `${sliceByColumn(boundedTitle, 0, MAX_UI_PROMPT_TITLE_WIDTH - 1, true)}\u2026`;\n}\n\nexport function formatToolActivity(runtime: RuntimeState): string | undefined {\n\tif (runtime.uiPrompt) {\n\t\tconst title = formatUIPromptTitle(runtime.uiPrompt.title);\n\t\treturn `\u2328 waiting for ${runtime.uiPrompt.kind}${title ? ` \u00B7 ${title}` : \"\"}`;\n\t}\n\n\tconst active = [...runtime.activeTools.entries()];\n\tif (active.length > 0) {\n\t\tconst [name, count] = active[0] ?? [\"tool\", 1];\n\t\tconst suffix = count > 1 ? `\u00D7${count}` : active.length > 1 ? `+${active.length - 1}` : \"\";\n\t\treturn `\u2699\uFE0F ${name}${suffix}`;\n\t}\n\n\treturn runtime.isStreaming ? \"\uD83D\uDCAD thinking\" : undefined;\n}\n\nexport function prLinkFromStatuses(statuses: ReadonlyMap<string, string>): string | undefined {\n\tconst value = statuses.get(GITHUB_PR_KEY);\n\tif (!value) return undefined;\n\t// Extract the OSC 8 hyperlink span (the clickable \"#123\"); skip non-PR states\n\t// like \"PR gh missing\" that carry no link. github-pr emits exactly one link, so the\n\t// first OSC 8 span is the PR number.\n\tconst open = value.indexOf(\"\\x1b]8;;\");\n\tif (open === -1) return undefined;\n\tconst closeMarker = \"\\x1b]8;;\\x07\";\n\tconst close = value.indexOf(closeMarker, open + 1);\n\treturn close === -1 ? undefined : value.slice(open, close + closeMarker.length);\n}\n\nexport function prContextFromStatuses(statuses: ReadonlyMap<string, string>): string | undefined {\n\tconst value = statuses.get(GITHUB_PR_KEY);\n\tif (!value) return undefined;\n\tconst link = prLinkFromStatuses(statuses);\n\tconst reference = link ?? plainPrReference(value);\n\tif (!reference) return undefined;\n\n\tconst state = compactPrState(link ? value.replace(link, \"\") : value);\n\treturn state ? `${reference} \u00B7 ${state}` : undefined;\n}\n\nfunction plainPrReference(value: string): string | undefined {\n\treturn /^PR\\s+(#\\d+):/u.exec(value)?.[1];\n}\n\nfunction compactPrState(value: string): string | undefined {\n\tif (/:\\s*merged\\s*$/.test(value)) return \"merged\";\n\tif (/:\\s*closed\\s*$/.test(value)) return \"closed\";\n\tif (/\\bdraft\\b/.test(value)) return \"draft\";\n\n\tconst failing = /\\bchecks failing \\((\\d+)\\)/.exec(value);\n\tif (failing) return `${failing[1]} failing`;\n\tif (/\\bchanges requested\\b/.test(value)) return \"changes requested\";\n\n\tconst pending = /\\bchecks pending \\((\\d+)\\)/.exec(value);\n\tif (pending) return `${pending[1]} pending`;\n\tif (/\\bapproved\\b/.test(value)) return \"approved\";\n\tif (/\\breview required\\b/.test(value)) return \"review required\";\n\tif (/\\bchecks passing\\b/.test(value)) return \"checks passing\";\n\tif (/\\bno checks\\b/.test(value)) return \"no checks\";\n\treturn undefined;\n}\n\nfunction isSubscriptionBacked(ctx: ExtensionContext): boolean {\n\tconst model = ctx.model;\n\treturn (\n\t\tmodel !== undefined &&\n\t\t(model.provider === \"kimi-coding\" || ctx.modelRegistry.isUsingOAuth(model))\n\t);\n}\n\nexport function formatCount(value: number): string {\n\tif (value < 1000) return `${value}`;\n\tif (value < 1_000_000) return `${(value / 1000).toFixed(value < 10_000 ? 1 : 0)}k`;\n\treturn `${(value / 1_000_000).toFixed(1)}m`;\n}\n\nfunction formatTime(): string {\n\tconst now = new Date();\n\tconst hours = now.getHours().toString().padStart(2, \"0\");\n\tconst minutes = now.getMinutes().toString().padStart(2, \"0\");\n\treturn `${hours}:${minutes}`;\n}\n\nconst graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n\nexport function truncateModel(\n\tmodel: string,\n\tlength: number,\n\tsymbol: string,\n\tdirection: TruncationDirection,\n): string {\n\tconst safeModel = sanitizeTerminalText(model);\n\tif (length === 0) return safeModel;\n\tconst graphemes = [...graphemeSegmenter.segment(safeModel)].map(({ segment }) => segment);\n\tif (graphemes.length <= length) return safeModel;\n\tconst safeSymbol = sanitizeTerminalText(symbol);\n\n\tswitch (direction) {\n\t\tcase \"start\":\n\t\t\treturn `${safeSymbol}${graphemes.slice(-length).join(\"\")}`;\n\t\tcase \"middle\": {\n\t\t\tconst headLength = Math.ceil(length / 2);\n\t\t\tconst tailLength = Math.floor(length / 2);\n\t\t\tconst tail = tailLength > 0 ? graphemes.slice(-tailLength).join(\"\") : \"\";\n\t\t\treturn `${graphemes.slice(0, headLength).join(\"\")}${safeSymbol}${tail}`;\n\t\t}\n\t\tcase \"end\":\n\t\t\treturn `${graphemes.slice(0, length).join(\"\")}${safeSymbol}`;\n\t}\n}\n\nexport function shortenModel(model: string): string {\n\treturn model\n\t\t.replace(/^claude-/, \"\")\n\t\t.replace(/^gpt-/, \"gpt \")\n\t\t.replace(/-20\\d{6}$/, \"\")\n\t\t.replace(/-latest$/, \"\");\n}\n", "import { basename, isAbsolute, relative, sep } from \"node:path\";\nimport { sanitizeTerminalText } from \"@narumitw/pi-tui-kit/terminal-text\";\n\nconst DEFAULT_TRUNCATION_LENGTH = 3;\nconst DEFAULT_HOME_SYMBOL = \"~\";\n\n/** Apply Starship's default directory presentation without exposing a format language. */\nexport function formatDirectoryPath(\n\tcwd: string,\n\thomeDir: string | undefined,\n\tgitRoot: string | undefined,\n): string {\n\tconst contracted =\n\t\tgitRoot && (!homeDir || !samePath(gitRoot, homeDir))\n\t\t\t? (contractRepositoryPath(cwd, gitRoot) ?? contractPath(cwd, homeDir, DEFAULT_HOME_SYMBOL))\n\t\t\t: contractPath(cwd, homeDir, DEFAULT_HOME_SYMBOL);\n\tconst safeContracted = sanitizeTerminalText(contracted);\n\tconst components = safeContracted.split(\"/\").filter((component) => component.length > 0);\n\tconst displayed =\n\t\tcomponents.length > DEFAULT_TRUNCATION_LENGTH\n\t\t\t? components.slice(-DEFAULT_TRUNCATION_LENGTH).join(\"/\")\n\t\t\t: safeContracted;\n\tconst native = sep === \"/\" ? displayed : displayed.replaceAll(\"/\", sep);\n\treturn sanitizeTerminalText(native || basename(cwd) || cwd);\n}\n\nfunction toSlashPath(value: string): string {\n\treturn sep === \"\\\\\" ? value.replaceAll(\"\\\\\", \"/\") : value;\n}\n\nfunction contractPath(path: string, root: string | undefined, replacement: string): string {\n\tif (!root) return toSlashPath(path);\n\tconst child = relativeWithin(path, root);\n\tif (child === undefined) return toSlashPath(path);\n\treturn child ? `${replacement}/${child}` : replacement;\n}\n\nfunction contractRepositoryPath(path: string, root: string): string | undefined {\n\tconst child = relativeWithin(path, root);\n\tif (child === undefined) return undefined;\n\tconst name = basename(root) || toSlashPath(root);\n\treturn child ? `${name}/${child}` : name;\n}\n\nfunction relativeWithin(path: string, root: string): string | undefined {\n\tconst child = relative(root, path);\n\tif (child === \"\") return \"\";\n\tif (child === \"..\" || child.startsWith(`..${sep}`) || isAbsolute(child)) return undefined;\n\treturn toSlashPath(child);\n}\n\nfunction samePath(left: string, right: string): boolean {\n\treturn relative(left, right) === \"\";\n}\n", "import type { SessionEntry } from \"@earendil-works/pi-coding-agent\";\n\ninterface UsageLike {\n\tinput?: number;\n\toutput?: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost?: { total?: number };\n}\n\nexport interface FooterUsageSummary {\n\tinput: number;\n\toutput: number;\n\tcacheRead: number;\n\tcacheWrite: number;\n\tcost: number;\n\tlatestCacheHitRate?: number;\n}\n\nexport function summarizeFooterUsage(entries: readonly SessionEntry[]): FooterUsageSummary {\n\tconst totals: FooterUsageSummary = {\n\t\tinput: 0,\n\t\toutput: 0,\n\t\tcacheRead: 0,\n\t\tcacheWrite: 0,\n\t\tcost: 0,\n\t};\n\n\tfor (const entry of entries) {\n\t\tlet usage: UsageLike | undefined;\n\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tusage = entry.message.usage;\n\t\t\tconst input = usage.input ?? 0;\n\t\t\tconst cacheRead = usage.cacheRead ?? 0;\n\t\t\tconst cacheWrite = usage.cacheWrite ?? 0;\n\t\t\tconst promptTokens = input + cacheRead + cacheWrite;\n\t\t\ttotals.latestCacheHitRate = promptTokens > 0 ? (cacheRead / promptTokens) * 100 : undefined;\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"toolResult\") {\n\t\t\tusage = entry.message.usage;\n\t\t} else if (entry.type === \"compaction\" || entry.type === \"branch_summary\") {\n\t\t\tusage = entry.usage;\n\t\t}\n\t\tif (!usage) continue;\n\n\t\ttotals.input += usage.input ?? 0;\n\t\ttotals.output += usage.output ?? 0;\n\t\ttotals.cacheRead += usage.cacheRead ?? 0;\n\t\ttotals.cacheWrite += usage.cacheWrite ?? 0;\n\t\ttotals.cost += usage.cost?.total ?? 0;\n\t}\n\n\treturn totals;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;AAAA,SAAS,eAAe;AACxB;AAAA,EAGC,eAAAA;AAAA,OACM;AACP,SAAS,uBAAuB;;;ACNhC,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY,MAAM,eAAe;AACnD,SAAS,mBAAgD;AACzD,SAAS,wBAAwB;;;ACFjC,SAAS,oBAAoB;;;ACDtB,SAAS,UACf,MACA,QACA,YAAY,MACH;AACT,QAAM,QAAQ;AAAA,IACb,OAAO,KAAK,UAAU,MAAM,OAAO,IAAI,SAAS,IAAI;AAAA,IACpD,OAAO,KAAK,UAAU,MAAM,OAAO,IAAI,SAAS,IAAI;AAAA,EACrD,EAAE,OAAO,CAAC,SAAyB,SAAS,MAAS;AACrD,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,QAAU,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI;AACzC;AAMA,SAAS,UAAU,QAAqB,KAAa,WAA4B;AAChF,QAAM,EAAE,KAAK,OAAO,KAAK,IAAI,SAAS,GAAG;AACzC,SAAO,YACJ,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,IAAI,IAAI,KACnC,GAAG,MAAM,MAAM,aAAa,KAAK,OAAO,IAAI,CAAC;AACjD;AAEA,SAAS,aAAa,KAAa,OAAe,MAAsB;AACvE,QAAM,WAAW,CAAC,KAAK,OAAO,IAAI,EAAE,IAAI,CAAC,UAAU,KAAK,MAAO,QAAQ,MAAO,CAAC,CAAC;AAChF,SAAO,KAAK,MAAM,SAAS,CAAC,KAAK,KAAK,KAAK,SAAS,CAAC,KAAK,MAAM,SAAS,CAAC,KAAK;AAChF;AAEA,SAAS,SAAS,KAA2D;AAC5E,QAAM,aAAa,IAAI,QAAQ,MAAM,EAAE;AACvC,SAAO;AAAA,IACN,KAAK,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IAC/C,OAAO,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,IACjD,MAAM,OAAO,SAAS,WAAW,MAAM,GAAG,CAAC,GAAG,EAAE;AAAA,EACjD;AACD;;;ADdO,SAAS,0BACf,OACA,OACA,QACA,YAAY,MACH;AACT,MAAI,MAAM,WAAW,KAAK,SAAS,EAAG,QAAO;AAC7C,SAAO,WAAW,KAAK,EACrB,IAAI,CAAC,aAAa,qBAAqB,UAAU,OAAO,QAAQ,SAAS,CAAC,EAC1E,KAAK,IAAI;AACZ;AAEA,SAAS,WAAW,OAAwC;AAC3D,QAAM,QAA2B,CAAC,CAAC,CAAC;AACpC,aAAW,QAAQ,OAAO;AACzB,QAAI,KAAK,SAAS,wBAAyB,OAAM,KAAK,CAAC,CAAC;AAAA,QACnD,OAAM,GAAG,EAAE,GAAG,KAAK,IAAI;AAAA,EAC7B;AACA,SAAO;AACR;AAEA,IAAM,6BAA8E;AAAA,EACnF,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,KAAK;AAAA,EACL,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACR;AAEA,SAAS,qBACR,UACA,OACA,QACA,WACS;AACT,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,QAAM,SAAS,CAAC,GAAG,QAAQ;AAC3B,SAAO,OAAO,SAAS,GAAG;AACzB,UAAMC,YAAW,sBAAsB,QAAQ,QAAQ,SAAS;AAChE,QAAI,aAAaA,SAAQ,KAAK,MAAO,QAAOA;AAC5C,QAAI,eAAe;AACnB,aAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACtD,YAAM,YAAY,OAAO,KAAK;AAC9B,YAAM,UAAU,OAAO,YAAY;AACnC,UACC,aACA,WACA,2BAA2B,UAAU,IAAI,IAAI,2BAA2B,QAAQ,IAAI,GACnF;AACD,uBAAe;AAAA,MAChB;AAAA,IACD;AACA,WAAO,OAAO,cAAc,CAAC;AAAA,EAC9B;AACA,QAAM,WAAW,sBAAsB,QAAQ,QAAQ,SAAS;AAChE,SAAO,aAAa,QAAQ,KAAK,QAAQ,WAAW;AACrD;AAEO,SAAS,4BACf,QACA,gBAA+B,eAC/B,YAAY,MACH;AACT,SAAO,UAAU,YAAO,EAAE,IAAI,cAAc,aAAa,EAAE,mBAAmB,GAAG,SAAS;AAC3F;AAEA,SAAS,sBACR,UACA,QACA,WACS;AACT,QAAM,SAAS,cAAc,OAAO,aAAa;AACjD,QAAM,SAAS,iBAAiB,UAAU,QAAQ,OAAO,eAAe,OAAO,OAAO;AACtF,MAAI,OAAO,UAAU,sBAAO,EAAE,IAAI,OAAO,KAAK,GAAG,SAAS;AAE1D,aAAW,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,GAAG;AAC9C,UAAM,WAAW,UAAU,IAAI,SAAY,OAAO,QAAQ,CAAC,GAAG;AAC9D,QAAI,UAAU;AACb,cAAQ,UAAU,UAAK,EAAE,IAAI,SAAS,IAAI,IAAI,MAAM,OAAO,GAAG,GAAG,SAAS;AAAA,IAC3E;AACA,YAAQ,UAAU,gBAAgB,OAAO,MAAM,GAAG,MAAM,QAAQ,SAAS;AAAA,EAC1E;AAEA,QAAM,YAAY,OAAO,GAAG,EAAE;AAC9B,MAAI,UAAW,SAAQ,UAAU,UAAK,EAAE,IAAI,UAAU,OAAO,GAAG,GAAG,SAAS;AAC5E,SAAO;AACR;AAEA,SAAS,iBACR,UACA,QACA,eACA,mBACmB;AACnB,QAAM,SAA2B,CAAC;AAClC,QAAM,uBAAuB,kBAAkB;AAC/C,aAAWC,YAAW,UAAU;AAC/B,UAAM,SAAS,uBACX,kBAAkBA,SAAQ,IAAI,KAAK,CAAC,IACrC,OAAO,OAAOA,SAAQ,KAAK;AAC9B,UAAM,WAAW,OAAO,GAAG,EAAE;AAC7B,UAAM,kBACL,aAAa,WACZ,uBACE,YAAY,SAAS,QAAQ,MAAM,IACnC,SAAS,cAAcA,SAAQ;AACnC,QAAI,gBAAiB,UAAS,SAAS,KAAKA,QAAO;AAAA,QAC9C,QAAO,KAAK,EAAE,WAAWA,SAAQ,OAAO,QAAQ,UAAU,CAACA,QAAO,EAAE,CAAC;AAAA,EAC3E;AACA,SAAO;AACR;AAEA,SAAS,YAAY,MAAmB,OAA6B;AACpE,SAAO,KAAK,OAAO,MAAM,MAAM,KAAK,OAAO,MAAM;AAClD;AAEA,SAAS,gBACR,OACA,QACS;AACT,QAAM,QAAQ,MAAM,SAAS,IAAI,iBAAiB;AAClD,QAAM,YAAY,cAAc,OAAO,WAAW,OAAO,YAAY,MAAM;AAC3E,QAAM,UAAU,OAAO,YAAY,SAAS,OAAO;AACnD,QAAM,WAAW,OAAO,YAAY,SAAS,MAAM;AACnD,SAAO,GAAG,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,QAAQ;AACrD;AAEA,SAAS,kBAAkBA,UAAgC;AAC1D,SAAOA,SAAQ,WAAW,UAAYA,SAAQ,IAAI,aAAeA,SAAQ;AAC1E;AAEA,SAAS,cAAc,WAA0B,MAAuB;AACvE,QAAM,UAAU,OAAO,OAAO;AAC9B,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO,GAAG,OAAO,SAAI,OAAO;AAAA,IAC7B,KAAK;AACJ,aAAO,GAAG,OAAO,SAAI,OAAO;AAAA,IAC7B,KAAK;AACJ,aAAO,GAAG,OAAO,SAAI,OAAO;AAAA,IAC7B,KAAK;AACJ,aAAO,GAAG,OAAO,SAAI,OAAO;AAAA,IAC7B,KAAK;AACJ,aAAO;AAAA,EACT;AACD;;;ADjKA,IAAM,iBAAiB;AACvB,IAAM,8BAAgE;AAAA,EACrE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,uBAAuB;AAAA,EACvB,QAAQ;AACT;AACA,IAAM,sCAAmE,oBAAI,IAAI;AACjF,SAAS,yBACR,QACA,OACA,WACS;AACT,SAAO,4BAA4B,OAAO,OAAO,eAAe,SAAS;AAC1E;AAEO,SAAS,wBACf,UACA,OACA,QACA,SACA,aAAkC,oBAAI,IAAI,GAC1C,YAAY,MACH;AACT,QAAM,YAAY,yBAAyB,QAAQ,OAAO,SAAS;AACnE,QAAM,kBAAkB;AAAA,IACvB,GAAG,+BAA+B,SAAS,KAAK;AAAA,IAChD,GAAG,CAAC,GAAG,SAAS,QAAQ,CAAC,EACvB;AAAA,MACA,CAAC,CAAC,KAAK,KAAK,MAAM,QAAQ,kBAAkB,CAAC,WAAW,IAAI,GAAG,KAAK,MAAM,KAAK,EAAE,SAAS;AAAA,IAC3F,EACC;AAAA,MAAI,CAAC,CAAC,KAAK,KAAK,MAChB,sBAAsB,KAAK,OAAO,OAAO,QAAQ,QAAQ,0BAA0B;AAAA,IACpF;AAAA,EACF,EAAE,MAAM,GAAG,CAAC;AAEZ,SAAO,gBAAgB,KAAK,SAAS;AACtC;AAEO,SAAS,sBACf,KACA,OACA,OACA,QACA,6BAA0D,qCACjD;AACT,QAAM,SAAS,yBAAyB,2BAA2B,KAAK,KAAK,CAAC;AAC9E,QAAM,OAAO,4BAA4B,OAAO,IAAI;AACpD,QAAM,QAAQ,eAAe,KAAK,KAAK;AACvC,QAAM,YAAY,UAAU,YAAY,YAAY;AACpD,QAAM,OAAO;AAAA,IACZ;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,EACD;AACA,QAAM,eAAe,MAAM,GAAG,WAAW,IAAI;AAC7C,SAAO,OAAO,GAAG,MAAM,GAAG,OAAO,IAAI,CAAC,IAAI,YAAY,KAAK;AAC5D;AAEA,SAAS,oBACR,KACA,aACA,iBACA,4BACC;AACD,MAAI,OAAO,OAAO,iBAAiB,GAAG,EAAG,QAAO,gBAAgB,GAAG;AACnE,QAAM,gBAAgB,wBAAwB,KAAK,eAAe;AAClE,MAAI,kBAAkB,OAAW,QAAO;AACxC,QAAM,gBAAgB,4BAA4B,GAAG;AACrD,MAAI,iBAAiB,OAAO,OAAO,iBAAiB,aAAa,GAAG;AACnE,WAAO,gBAAgB,aAAa;AAAA,EACrC;AACA,aAAW,SAAS,6BAA6B,KAAK,0BAA0B,GAAG;AAClF,QAAI,OAAO,OAAO,iBAAiB,KAAK,EAAG,QAAO,gBAAgB,KAAK;AAAA,EACxE;AACA,SAAO,eAAe,+BAA+B,GAAG,KAAK;AAC9D;AAEA,SAAS,wBACR,KACA,iBACqB;AACrB,MAAI;AACJ,aAAW,CAAC,UAAU,IAAI,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC/D,QAAI,CAAC,SAAS,SAAS,IAAI,EAAG;AAC9B,UAAM,OAAO,SAAS,MAAM,GAAG,EAAE;AACjC,QAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,GAAG,IAAI,GAAG,EAAG;AAC1C,QAAI,CAAC,SAAS,KAAK,SAAS,MAAM,WAAY,SAAQ,EAAE,YAAY,KAAK,QAAQ,KAAK;AAAA,EACvF;AACA,SAAO,OAAO;AACf;AAEA,SAAS,6BACR,KACA,4BACoB;AACpB,aAAW,CAAC,YAAY,OAAO,KAAK,4BAA4B;AAC/D,QAAI,2BAA2B,KAAK,UAAU,EAAG,QAAO;AAAA,EACzD;AACA,SAAO,CAAC;AACT;AAEA,SAAS,2BAA2B,KAAa,YAA6B;AAC7E,SAAO,QAAQ,cAAc,IAAI,WAAW,GAAG,UAAU,GAAG,KAAK,IAAI,WAAW,GAAG,UAAU,GAAG;AACjG;AAEO,SAAS,wBAAwB,QAAgB,OAAyB;AAChF,MAAI,CAAC,UAAU,SAAS,EAAG,QAAO,CAAC;AACnC,SAAO,iBAAiB,QAAQ,KAAK;AACtC;AAEA,SAAS,+BAA+B,SAAiC,OAAwB;AAChG,MAAI,QAAQ,oBAAoB,WAAW,EAAG,QAAO,CAAC;AACtD,QAAM,QAAQ,QAAQ,oBAAoB,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AAC/D,QAAM,SACL,QAAQ,oBAAoB,SAAS,IAAI,KAAK,QAAQ,oBAAoB,SAAS,CAAC,KAAK;AAC1F,SAAO,CAAC,GAAG,MAAM,GAAG,WAAW,cAAI,CAAC,IAAI,MAAM,GAAG,WAAW,OAAO,KAAK,GAAG,MAAM,EAAE,CAAC,EAAE;AACvF;AAEO,SAAS,yBAAyB,OAAgD;AACxF,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,CAAC,YAAY,GAAG,UAAU,IAAI,QAAQ,MAAM,KAAK;AACvD,MAAI,cAAc,iBAAiB,UAAU,GAAG;AAC/C,WAAO,EAAE,MAAM,YAAY,MAAM,WAAW,KAAK,GAAG,EAAE;AAAA,EACvD;AACA,SAAO,EAAE,MAAM,QAAQ;AACxB;AAEA,SAAS,iBAAiB,OAAwB;AACjD,SAAO,gMAAgM;AAAA,IACtM;AAAA,EACD;AACD;AAEO,SAAS,eAAe,KAAa,OAA2B;AACtE,QAAM,aAAa,GAAG,GAAG,IAAI,KAAK,GAAG,YAAY;AACjD,MAAI,oDAAoD,KAAK,UAAU,EAAG,QAAO;AACjF,MAAI,WAAW,SAAS,OAAO,EAAG,QAAO;AACzC,MAAI,wCAAwC,KAAK,UAAU,EAAG,QAAO;AACrE,SAAO;AACR;AAEO,SAAS,2BAA2B,KAAa,OAAuB;AAC9E,SAAO,MAAM,KAAK,EAAE,QAAQ,IAAI,OAAO,IAAI,aAAa,GAAG,CAAC,aAAa,IAAI,GAAG,EAAE;AACnF;AAEO,SAAS,4BAA4B,OAAuB;AAClE,SAAO,MACL,KAAK,EACL,QAAQ,gBAAgB,QAAG,EAC3B,QAAQ,kBAAkB,QAAG,EAC7B,QAAQ,SAAS,GAAG,EACpB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,QAAQ,GAAG;AACtB;AAEA,SAAS,aAAa,OAAuB;AAC5C,SAAO,MAAM,QAAQ,uBAAuB,MAAM;AACnD;AAQO,SAAS,+BAA+B,KAA0C;AACxF,QAAM,WAAwC,CAAC;AAC/C,QAAM,gBAAgB,uBAAuB,GAAG;AAEhD,aAAW,gBAAgB,eAAe;AACzC,UAAM,gBAAgB,QAAQ,YAAY;AAC1C,eAAW,aAAa,mBAAmB,YAAY,GAAG;AACzD,YAAM,SAAS,UAAU,KAAK;AAC9B,UAAI,CAAC,OAAQ;AACb,YAAM,cAAc,qBAAqB,QAAQ,aAAa;AAC9D,UAAI,CAAC,YAAa;AAClB,eAAS,KAAK,EAAE,aAAa,QAAQ,UAAU,eAAe,QAAQ,aAAa,EAAE,CAAC;AAAA,IACvF;AAAA,EACD;AAEA,SAAO;AACR;AAEA,SAAS,uBAAuB,KAAuB;AACtD,SAAO,CAAC,KAAK,YAAY,GAAG,eAAe,GAAG,KAAK,KAAK,OAAO,eAAe,CAAC,EAAE;AAAA,IAAO,CAAC,SACxF,WAAW,IAAI;AAAA,EAChB;AACD;AAEO,SAAS,wBACf,mBACW;AACX,QAAM,mBAAmB,oBAAI,IAAyB;AAEtD,aAAW,oBAAoB,mBAAmB;AACjD,UAAM,UAAU,iBAAiB,IAAI,iBAAiB,WAAW,KAAK,oBAAI,IAAY;AACtF,YAAQ,IAAI,iBAAiB,QAAQ;AACrC,qBAAiB,IAAI,iBAAiB,aAAa,OAAO;AAAA,EAC3D;AAEA,SAAO,CAAC,GAAG,iBAAiB,QAAQ,CAAC,EACnC,OAAO,CAAC,CAAC,EAAE,OAAO,MAAM,QAAQ,OAAO,CAAC,EACxC,IAAI,CAAC,CAAC,WAAW,MAAM,YAAY,QAAQ,aAAa,EAAE,EAAE,QAAQ,QAAQ,EAAE,CAAC;AAClF;AAEO,SAAS,gCACf,mBACwB;AACxB,QAAM,6BAA6B,oBAAI,IAAmC;AAE1E,aAAW,oBAAoB,mBAAmB;AACjD,UAAM,YAAY;AAAA,MACjB,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,IAClB;AACA,QAAI,CAAC,UAAW;AAChB,UAAM,mBACL,2BAA2B,IAAI,UAAU,UAAU,KAAK,oBAAI,IAAsB;AACnF,UAAM,kBAAkB,iBAAiB,IAAI,iBAAiB,WAAW,KAAK,CAAC;AAC/E,qBAAiB;AAAA,MAChB,iBAAiB;AAAA,MACjB,cAAc,CAAC,GAAG,iBAAiB,GAAG,UAAU,OAAO,CAAC;AAAA,IACzD;AACA,+BAA2B,IAAI,UAAU,YAAY,gBAAgB;AAAA,EACtE;AAEA,QAAM,UAAU,oBAAI,IAAsB;AAC1C,aAAW,CAAC,YAAY,gBAAgB,KAAK,4BAA4B;AACxE,QAAI,iBAAiB,SAAS;AAC7B,cAAQ,IAAI,YAAY,CAAC,GAAG,iBAAiB,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAAA,EACjE;AACA,SAAO;AACR;AAEA,SAAS,kCACR,aACA,QACwD;AACxD,QAAM,cAAc,gBAAgB,WAAW;AAC/C,QAAM,aAAa,0BAA0B,WAAW;AACxD,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,gBAAgB,QAAQ,WAAW,MAAM,IAAI,CAAC,QAAQ,OAAO,eAAe,MAAM,CAAC,EAAE,IAAI,CAAC;AAChG,SAAO;AAAA,IACN;AAAA,IACA,SAAS,cAAc,CAAC,GAAG,eAAe,aAAa,aAAa,UAAU,CAAC;AAAA,EAChF;AACD;AAEA,SAAS,gBAAgB,aAA6B;AACrD,QAAM,aAAa,YAAY,YAAY,GAAG;AAC9C,SAAO,eAAe,KAAK,cAAc,YAAY,MAAM,aAAa,CAAC;AAC1E;AAEA,SAAS,0BAA0B,aAA6B;AAC/D,SAAO,YAAY,WAAW,KAAK,KAAK,YAAY,SAAS,MAAM,SAChE,YAAY,MAAM,MAAM,MAAM,IAC9B;AACJ;AAEA,SAAS,cAAc,QAAqC;AAC3D,SAAO,CAAC,GAAG,IAAI,IAAI,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC,CAAC,CAAC;AAC/D;AAEA,SAAS,mBAAmB,cAAgC;AAC3D,MAAI;AACH,UAAM,WAAW,KAAK,MAAM,aAAa,cAAc,MAAM,CAAC;AAC9D,YAAQ,SAAS,YAAY,CAAC,GAC5B,IAAI,CAAC,UAAU;AACf,UAAI,OAAO,UAAU,SAAU,QAAO;AACtC,UACC,SACA,OAAO,UAAU,YACjB,OAAQ,MAA+B,WAAW,UACjD;AACD,eAAQ,MAA6B;AAAA,MACtC;AACA,aAAO;AAAA,IACR,CAAC,EACA,OAAO,CAAC,WAA6B,WAAW,MAAS;AAAA,EAC5D,QAAQ;AACP,WAAO,CAAC;AAAA,EACT;AACD;AAEA,SAAS,qBAAqB,QAAgB,eAA2C;AACxF,MAAI,OAAO,WAAW,MAAM,EAAG,QAAO,eAAe,MAAM;AAC3D,QAAM,cAAc,KAAK,kBAAkB,QAAQ,aAAa,GAAG,cAAc;AACjF,MAAI;AACH,UAAM,cAAc,KAAK,MAAM,aAAa,aAAa,MAAM,CAAC;AAChE,WAAO,OAAO,YAAY,SAAS,WAAW,YAAY,OAAO;AAAA,EAClE,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEO,SAAS,eAAe,QAAwB;AACtD,QAAM,OAAO,OAAO,MAAM,OAAO,MAAM;AACvC,MAAI,KAAK,WAAW,GAAG,EAAG,QAAO,KAAK,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AACrE,SAAO,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK;AAC9B;AAEA,SAAS,eAAe,QAAgB,eAA+B;AACtE,MAAI,OAAO,WAAW,MAAM,EAAG,QAAO,OAAO,eAAe,MAAM,CAAC;AACnE,SAAO,kBAAkB,QAAQ,aAAa;AAC/C;AAEA,SAAS,kBAAkB,QAAgB,eAA+B;AACzE,SAAO,WAAW,MAAM,IAAI,SAAS,QAAQ,eAAe,MAAM;AACnE;;;AGrUA,SAAS,cAAAC,mBAAkB;AAG3B,IAAM,wBAAwB;AAY9B,eAAsB,cACrB,IACA,KACA,QACwC;AACxC,QAAM,CAAC,cAAc,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpD,GAAG;AAAA,MACF;AAAA,MACA,CAAC,uBAAuB,UAAU,kBAAkB,YAAY,0BAA0B;AAAA,MAC1F,EAAE,KAAK,SAAS,uBAAuB,OAAO;AAAA,IAC/C;AAAA,IACA,GACE,KAAK,OAAO,CAAC,aAAa,0BAA0B,iBAAiB,GAAG;AAAA,MACxE;AAAA,MACA,SAAS;AAAA,MACT;AAAA,IACD,CAAC,EACA,MAAM,MAAM,MAAS;AAAA,EACxB,CAAC;AACD,MAAI,aAAa,SAAS,KAAK,aAAa,OAAQ,QAAO;AAC3D,QAAM,UAAU,wBAAwB,aAAa,MAAM;AAC3D,MAAI,cAAc,WAAW,SAAS,KAAK,CAAC,WAAW,QAAQ;AAC9D,UAAM,OAAO,aAAa,WAAW,MAAM;AAC3C,QAAI,KAAM,SAAQ,OAAO;AAAA,EAC1B;AACA,SAAO;AACR;AAEO,SAAS,wBAAwB,QAAkC;AACzE,QAAM,UAA4B;AAAA,IACjC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,EACZ;AACA,aAAW,QAAQ,OAAO,MAAM,OAAO,GAAG;AACzC,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,WAAW,KAAK,GAAG;AAC3B,YAAM,QAAQ,KAAK,MAAM,gBAAgB;AACzC,YAAM,SAAS,KAAK,MAAM,iBAAiB;AAC3C,cAAQ,QAAQ,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI;AAC3C,cAAQ,SAAS,SAAS,OAAO,OAAO,CAAC,CAAC,IAAI;AAC9C;AAAA,IACD;AACA,UAAM,cAAc,KAAK,CAAC,KAAK;AAC/B,UAAM,iBAAiB,KAAK,CAAC,KAAK;AAClC,QAAI,gBAAgB,OAAO,mBAAmB,KAAK;AAClD,cAAQ,aAAa;AACrB;AAAA,IACD;AACA,QAAI,iBAAiB,aAAa,cAAc,GAAG;AAClD,cAAQ,aAAa;AACrB;AAAA,IACD;AACA,QAAI,gBAAgB,WAAW,EAAG,SAAQ,UAAU;AACpD,QAAI,gBAAgB,cAAc,EAAG,SAAQ,YAAY;AAAA,EAC1D;AACA,SAAO;AACR;AAEA,SAAS,iBAAiB,aAAqB,gBAAiC;AAC/E,SACE,gBAAgB,OAAO,mBAAmB,OAC1C,gBAAgB,OAAO,mBAAmB,OAC3C,gBAAgB,OAChB,mBAAmB;AAErB;AAEA,SAAS,gBAAgB,QAAyB;AACjD,SAAO,WAAW,OAAO,WAAW,OAAO,WAAW;AACvD;AAEO,SAAS,aAAa,QAAoC;AAChE,QAAM,OAAO,OAAO,MAAM,QAAQ,EAAE,CAAC,GAAG,KAAK;AAC7C,SAAO,QAAQA,YAAW,IAAI,IAAI,OAAO;AAC1C;AAEO,SAAS,uBAAuB,SAA+C;AACrF,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,SAAS;AAAA,IACd,CAAC,UAAK,QAAQ,KAAK;AAAA,IACnB,CAAC,UAAK,QAAQ,MAAM;AAAA,IACpB,CAAC,KAAK,QAAQ,MAAM;AAAA,IACpB,CAAC,KAAK,QAAQ,QAAQ;AAAA,IACtB,CAAC,KAAK,QAAQ,SAAS;AAAA,IACvB,CAAC,KAAK,QAAQ,SAAS;AAAA,EACxB;AACA,SAAO,OACL,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,QAAQ,CAAC,EAC/B,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,GAAG,MAAM,GAAG,YAAY,KAAK,CAAC,EAAE,EACzD,KAAK,GAAG;AACX;AAEO,SAAS,qBACf,QACA,QACA,IACS;AACT,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,CAAC,uBAAuB,MAAM,GAAG,KAAK,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,OAAO;AACrF,SAAO,SAAS,SAAS,IAAI,GAAG,MAAM,IAAI,SAAS,KAAK,GAAG,CAAC,KAAK;AAClE;AAUO,SAAS,sBACf,MACA,OACU;AACV,MAAI,CAAC,QAAQ,CAAC,MAAO,QAAO,SAAS;AACrC,SACC,KAAK,SAAS,MAAM,QACpB,KAAK,UAAU,MAAM,SACrB,KAAK,WAAW,MAAM,UACtB,KAAK,WAAW,MAAM,UACtB,KAAK,aAAa,MAAM,YACxB,KAAK,cAAc,MAAM,aACzB,KAAK,cAAc,MAAM;AAE3B;AAEA,SAAS,YAAY,OAAuB;AAC3C,SAAO,KAAK,aAAa,MAAM,EAAE,UAAU,WAAW,uBAAuB,EAAE,CAAC,EAAE,OAAO,KAAK;AAC/F;;;AC3IA,SAAS,eAAe,gBAAAC,qBAAoB;AAC5C,SAAS,wBAAAC,6BAA4B;;;ACTrC,SAAS,UAAU,cAAAC,aAAY,UAAU,WAAW;AACpD,SAAS,4BAA4B;AAErC,IAAM,4BAA4B;AAClC,IAAM,sBAAsB;AAGrB,SAAS,oBACf,KACA,SACA,SACS;AACT,QAAM,aACL,YAAY,CAAC,WAAW,CAAC,SAAS,SAAS,OAAO,KAC9C,uBAAuB,KAAK,OAAO,KAAK,aAAa,KAAK,SAAS,mBAAmB,IACvF,aAAa,KAAK,SAAS,mBAAmB;AAClD,QAAM,iBAAiB,qBAAqB,UAAU;AACtD,QAAM,aAAa,eAAe,MAAM,GAAG,EAAE,OAAO,CAAC,cAAc,UAAU,SAAS,CAAC;AACvF,QAAM,YACL,WAAW,SAAS,4BACjB,WAAW,MAAM,CAAC,yBAAyB,EAAE,KAAK,GAAG,IACrD;AACJ,QAAM,SAAS,QAAQ,MAAM,YAAY,UAAU,WAAW,KAAK,GAAG;AACtE,SAAO,qBAAqB,UAAU,SAAS,GAAG,KAAK,GAAG;AAC3D;AAEA,SAAS,YAAY,OAAuB;AAC3C,SAAO,QAAQ,OAAO,MAAM,WAAW,MAAM,GAAG,IAAI;AACrD;AAEA,SAAS,aAAa,MAAc,MAA0B,aAA6B;AAC1F,MAAI,CAAC,KAAM,QAAO,YAAY,IAAI;AAClC,QAAM,QAAQ,eAAe,MAAM,IAAI;AACvC,MAAI,UAAU,OAAW,QAAO,YAAY,IAAI;AAChD,SAAO,QAAQ,GAAG,WAAW,IAAI,KAAK,KAAK;AAC5C;AAEA,SAAS,uBAAuB,MAAc,MAAkC;AAC/E,QAAM,QAAQ,eAAe,MAAM,IAAI;AACvC,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,SAAS,IAAI,KAAK,YAAY,IAAI;AAC/C,SAAO,QAAQ,GAAG,IAAI,IAAI,KAAK,KAAK;AACrC;AAEA,SAAS,eAAe,MAAc,MAAkC;AACvE,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,MAAI,UAAU,GAAI,QAAO;AACzB,MAAI,UAAU,QAAQ,MAAM,WAAW,KAAK,GAAG,EAAE,KAAKA,YAAW,KAAK,EAAG,QAAO;AAChF,SAAO,YAAY,KAAK;AACzB;AAEA,SAAS,SAAS,MAAc,OAAwB;AACvD,SAAO,SAAS,MAAM,KAAK,MAAM;AAClC;;;AClCO,SAAS,qBAAqB,SAAsD;AAC1F,QAAM,SAA6B;AAAA,IAClC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,MAAM;AAAA,EACP;AAEA,aAAW,SAAS,SAAS;AAC5B,QAAI;AACJ,QAAI,MAAM,SAAS,aAAa,MAAM,QAAQ,SAAS,aAAa;AACnE,cAAQ,MAAM,QAAQ;AACtB,YAAM,QAAQ,MAAM,SAAS;AAC7B,YAAM,YAAY,MAAM,aAAa;AACrC,YAAM,aAAa,MAAM,cAAc;AACvC,YAAM,eAAe,QAAQ,YAAY;AACzC,aAAO,qBAAqB,eAAe,IAAK,YAAY,eAAgB,MAAM;AAAA,IACnF,WAAW,MAAM,SAAS,aAAa,MAAM,QAAQ,SAAS,cAAc;AAC3E,cAAQ,MAAM,QAAQ;AAAA,IACvB,WAAW,MAAM,SAAS,gBAAgB,MAAM,SAAS,kBAAkB;AAC1E,cAAQ,MAAM;AAAA,IACf;AACA,QAAI,CAAC,MAAO;AAEZ,WAAO,SAAS,MAAM,SAAS;AAC/B,WAAO,UAAU,MAAM,UAAU;AACjC,WAAO,aAAa,MAAM,aAAa;AACvC,WAAO,cAAc,MAAM,cAAc;AACzC,WAAO,QAAQ,MAAM,MAAM,SAAS;AAAA,EACrC;AAEA,SAAO;AACR;;;AFZA,IAAM,gBAAgB;AACtB,IAAM,wBAAwB,oBAAI,IAAI,CAAC,aAAa,CAAC;AAC9C,SAAS,iBACf,OACA,KACA,YACA,QACA,QACA,SACA,YAAY,MACH;AACT,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,eAAe,qBAAqB,IAAI,eAAe,WAAW,CAAC;AACzE,QAAM,OAAyE;AAAA,IAC9E,EAAE,oBAAoB,GAAG,UAAU,CAAC,EAAE;AAAA,EACvC;AACA,aAAW,QAAQ,OAAO,UAAU;AACnC,QAAI,SAAS,yBAAyB;AACrC,WAAK,KAAK,EAAE,oBAAoB,GAAG,UAAU,CAAC,EAAE,CAAC;AACjD;AAAA,IACD;AAEA,UAAM,MAAM,KAAK,GAAG,EAAE;AACtB,QAAI,CAAC,IAAK;AACV,QAAI,sBAAsB;AAC1B,UAAM,WAAW,aAAa,MAAM,KAAK,YAAY,QAAQ,SAAS,YAAY;AAClF,QAAI,YAAY,SAAS,KAAK,SAAS,EAAG,KAAI,SAAS,KAAK,QAAQ;AAAA,EACrE;AAEA,QAAM,WAAyB,CAAC;AAChC,QAAM,eAAe,KAAK;AAAA,IACzB,CAAC,QAAQ,IAAI,uBAAuB,KAAK,IAAI,SAAS,SAAS;AAAA,EAChE;AACA,aAAW,CAAC,OAAO,GAAG,KAAK,aAAa,QAAQ,GAAG;AAClD,QAAI,QAAQ,EAAG,UAAS,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC9D,aAAS,KAAK,GAAG,IAAI,QAAQ;AAAA,EAC9B;AAEA,SAAO,0BAA0B,OAAO,UAAU,QAAQ,SAAS;AACpE;AAEO,SAAS,0BACf,OACA,YACA,OACA,QACA,SACA,UACA,YAAY,MACD;AACX,QAAM,WAAW,WAAW,qBAAqB;AACjD,QAAM,YAAY,sBAAsB,QAAQ;AAChD,QAAM,kBAAkB,cAAc,UAAa,SAAS,SAAS,SAAS;AAC9E,QAAM,SAAS;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB,wBAAwB;AAAA,IAC1C;AAAA,EACD;AACA,SAAO,wBAAwB,QAAQ,KAAK;AAC7C;AAEA,SAAS,aACR,MACA,KACA,YACA,QACA,SACA,cAC4B;AAC5B,UAAQ,MAAM;AAAA,IACb,KAAK;AACJ,aAAO,QAAQ,MAAM,UAAK,QAAQ,UAAU,UAAU,IAAI;AAAA,IAC3D,KAAK;AACJ,aAAO,QAAQ,MAAM,IAAI,OAAO,YAAY,eAAe,QAAQ,UAAU,QAAQ;AAAA,IACtF,KAAK,SAAS;AACb,YAAM,eAAe,OAAO,YAAY;AACxC,YAAM,QAAQ;AAAA,QACb,aAAa,IAAI,OAAO,MAAM,UAAU;AAAA,QACxC,aAAa;AAAA,QACb,aAAa;AAAA,QACb,aAAa;AAAA,MACd;AACA,aAAO,QAAQ,MAAM,OAAO,QAAQ,UAAU,QAAQ;AAAA,IACvD;AAAA,IACA,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,cAAc,QAAQ,aAAa;AAAA,QACnC;AAAA,MACD;AAAA,IACD,KAAK,UAAU;AACd,YAAM,SAAS,WAAW,aAAa;AACvC,YAAM,KAAK,SAAS,sBAAsB,WAAW,qBAAqB,CAAC,IAAI;AAC/E,aAAO;AAAA,QACN;AAAA,QACA,qBAAqB,QAAQ,QAAQ,WAAW,EAAE;AAAA,QAClD;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,IACA,KAAK;AACJ,aAAO;AAAA,QACN;AAAA,QACA,oBAAoB,IAAI,KAAK,QAAQ,SAAS,QAAQ,WAAW,IAAI;AAAA,QACrE;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD,KAAK,SAAS;AACb,YAAM,WAAW,mBAAmB,OAAO;AAC3C,aAAO,WAAW,QAAQ,MAAM,UAAU,QAAQ,UAAU,SAAS,IAAI;AAAA,IAC1E;AAAA,IACA,KAAK,WAAW;AACf,YAAM,QAAQ,IAAI,gBAAgB;AAClC,YAAM,aACL,OAAO,YAAY,QAAQ,OAAO,YAAY,SAC3C,MACA,GAAG,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAC/B,YAAM,gBAAgB,OAAO,iBAAiB,IAAI,OAAO,iBAAiB;AAC1E,aAAO;AAAA,QACN;AAAA,QACA,GAAG,UAAU,IAAIC,aAAY,aAAa,CAAC;AAAA,QAC3C;AAAA,QACA,aAAa,OAAO,OAAO;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAAA,IACA,KAAK,UAAU;AACd,YAAM,QACL,aAAa,UAAU,KAAK,aAAa,WAAW,IACjD,UACA,SAAIA,aAAY,aAAa,KAAK,CAAC,UAAKA,aAAY,aAAa,MAAM,CAAC;AAC5E,aAAO,QAAQ,MAAM,OAAO,QAAQ,UAAU,SAAS;AAAA,IACxD;AAAA,IACA,KAAK,SAAS;AACb,UAAI,aAAa,cAAc,KAAK,aAAa,eAAe,EAAG,QAAO;AAC1E,YAAM,SAAmB,CAAC;AAC1B,UAAI,aAAa,YAAY,EAAG,QAAO,KAAK,IAAIA,aAAY,aAAa,SAAS,CAAC,EAAE;AACrF,UAAI,aAAa,aAAa,EAAG,QAAO,KAAK,IAAIA,aAAY,aAAa,UAAU,CAAC,EAAE;AACvF,UAAI,aAAa,uBAAuB,QAAW;AAClD,eAAO,KAAK,KAAK,aAAa,mBAAmB,QAAQ,CAAC,CAAC,GAAG;AAAA,MAC/D;AACA,aAAO,QAAQ,MAAM,OAAO,KAAK,GAAG,GAAG,QAAQ,UAAU,SAAS;AAAA,IACnE;AAAA,IACA,KAAK,QAAQ;AACZ,YAAM,eAAe,qBAAqB,GAAG,IAAI,WAAW;AAC5D,aAAO;AAAA,QACN;AAAA,QACA,GAAG,aAAa,KAAK,QAAQ,aAAa,QAAQ,IAAI,IAAI,CAAC,CAAC,GAAG,YAAY;AAAA,QAC3E;AAAA,QACA;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,IACA,KAAK;AACJ,aAAO,QAAQ,MAAM,WAAW,GAAG,QAAQ,UAAU,OAAO;AAAA,IAC7D,KAAK;AACJ,aAAO,QAAQ,MAAM,GAAG,QAAQ,SAAS,IAAI,QAAQ,UAAU,OAAO;AAAA,EACxE;AACD;AAEA,SAAS,QACR,MACA,OACA,QACA,OACA,OACA,WAAW,OACK;AAChB,SAAO,EAAE,MAAM,MAAM,wBAAwB,MAAM,OAAO,MAAM,GAAG,OAAO,OAAO,SAAS;AAC3F;AAEO,SAAS,wBACf,MACA,OACA,QACS;AACT,QAAM,eAAe,OAAO,YAAY,IAAI;AAC5C,SAAO,GAAG,aAAa,MAAM,GAAG,KAAK,GAAG,aAAa,MAAM;AAC5D;AAEA,SAAS,cAAc,OAAkC;AACxD,UAAQ,OAAiB;AAAA,IACxB,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,IACR;AACC,aAAO;AAAA,EACT;AACD;AAEO,SAAS,aAAa,SAAgD;AAC5E,MAAI,YAAY,QAAQ,YAAY,OAAW,QAAO;AACtD,MAAI,WAAW,GAAI,QAAO;AAC1B,MAAI,WAAW,GAAI,QAAO;AAC1B,SAAO;AACR;AAEA,IAAM,kCAAkC;AACxC,IAAM,4BAA4B;AAElC,SAAS,yBAAyB,OAAuB;AACxD,MAAI,MAAM;AACV,MAAI,cAAc;AAClB,MAAI,aAAa;AACjB,SAAO,MAAM,MAAM,UAAU,aAAa,iCAAiC;AAC1E,UAAM,YAAY,MAAM,YAAY,GAAG,KAAK;AAC5C,WAAO,YAAY,QAAS,IAAI;AAChC,kBAAc;AACd,QAAI,aAAa,gCAAiC,eAAc;AAAA,EACjE;AACA,SAAO,MAAM,MAAM,SAAS,GAAG,MAAM,MAAM,GAAG,WAAW,CAAC,WAAM;AACjE;AAEA,SAAS,oBAAoB,OAAmC;AAC/D,QAAM,YAAY,QAAQC,sBAAqB,KAAK,EAAE,KAAK,IAAI;AAC/D,QAAM,eAAe,yBAAyB,SAAS;AACvD,MAAIC,cAAa,YAAY,KAAK,0BAA2B,QAAO;AACpE,SAAO,GAAG,cAAc,cAAc,GAAG,4BAA4B,GAAG,IAAI,CAAC;AAC9E;AAEO,SAAS,mBAAmB,SAA2C;AAC7E,MAAI,QAAQ,UAAU;AACrB,UAAM,QAAQ,oBAAoB,QAAQ,SAAS,KAAK;AACxD,WAAO,sBAAiB,QAAQ,SAAS,IAAI,GAAG,QAAQ,SAAM,KAAK,KAAK,EAAE;AAAA,EAC3E;AAEA,QAAM,SAAS,CAAC,GAAG,QAAQ,YAAY,QAAQ,CAAC;AAChD,MAAI,OAAO,SAAS,GAAG;AACtB,UAAM,CAAC,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC7C,UAAM,SAAS,QAAQ,IAAI,OAAI,KAAK,KAAK,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK;AACvF,WAAO,gBAAM,IAAI,GAAG,MAAM;AAAA,EAC3B;AAEA,SAAO,QAAQ,cAAc,uBAAgB;AAC9C;AAEO,SAAS,mBAAmB,UAA2D;AAC7F,QAAM,QAAQ,SAAS,IAAI,aAAa;AACxC,MAAI,CAAC,MAAO,QAAO;AAInB,QAAM,OAAO,MAAM,QAAQ,UAAU;AACrC,MAAI,SAAS,GAAI,QAAO;AACxB,QAAM,cAAc;AACpB,QAAM,QAAQ,MAAM,QAAQ,aAAa,OAAO,CAAC;AACjD,SAAO,UAAU,KAAK,SAAY,MAAM,MAAM,MAAM,QAAQ,YAAY,MAAM;AAC/E;AAEO,SAAS,sBAAsB,UAA2D;AAChG,QAAM,QAAQ,SAAS,IAAI,aAAa;AACxC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,mBAAmB,QAAQ;AACxC,QAAM,YAAY,QAAQ,iBAAiB,KAAK;AAChD,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,QAAQ,eAAe,OAAO,MAAM,QAAQ,MAAM,EAAE,IAAI,KAAK;AACnE,SAAO,QAAQ,GAAG,SAAS,SAAM,KAAK,KAAK;AAC5C;AAEA,SAAS,iBAAiB,OAAmC;AAC5D,SAAO,iBAAiB,KAAK,KAAK,IAAI,CAAC;AACxC;AAEA,SAAS,eAAe,OAAmC;AAC1D,MAAI,iBAAiB,KAAK,KAAK,EAAG,QAAO;AACzC,MAAI,iBAAiB,KAAK,KAAK,EAAG,QAAO;AACzC,MAAI,YAAY,KAAK,KAAK,EAAG,QAAO;AAEpC,QAAM,UAAU,6BAA6B,KAAK,KAAK;AACvD,MAAI,QAAS,QAAO,GAAG,QAAQ,CAAC,CAAC;AACjC,MAAI,wBAAwB,KAAK,KAAK,EAAG,QAAO;AAEhD,QAAM,UAAU,6BAA6B,KAAK,KAAK;AACvD,MAAI,QAAS,QAAO,GAAG,QAAQ,CAAC,CAAC;AACjC,MAAI,eAAe,KAAK,KAAK,EAAG,QAAO;AACvC,MAAI,sBAAsB,KAAK,KAAK,EAAG,QAAO;AAC9C,MAAI,qBAAqB,KAAK,KAAK,EAAG,QAAO;AAC7C,MAAI,gBAAgB,KAAK,KAAK,EAAG,QAAO;AACxC,SAAO;AACR;AAEA,SAAS,qBAAqB,KAAgC;AAC7D,QAAM,QAAQ,IAAI;AAClB,SACC,UAAU,WACT,MAAM,aAAa,iBAAiB,IAAI,cAAc,aAAa,KAAK;AAE3E;AAEO,SAASF,aAAY,OAAuB;AAClD,MAAI,QAAQ,IAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,IAAW,QAAO,IAAI,QAAQ,KAAM,QAAQ,QAAQ,MAAS,IAAI,CAAC,CAAC;AAC/E,SAAO,IAAI,QAAQ,KAAW,QAAQ,CAAC,CAAC;AACzC;AAEA,SAAS,aAAqB;AAC7B,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,IAAI,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACvD,QAAM,UAAU,IAAI,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AAC3D,SAAO,GAAG,KAAK,IAAI,OAAO;AAC3B;AAEA,IAAM,oBAAoB,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAE5E,SAAS,cACf,OACA,QACA,QACA,WACS;AACT,QAAM,YAAYC,sBAAqB,KAAK;AAC5C,MAAI,WAAW,EAAG,QAAO;AACzB,QAAM,YAAY,CAAC,GAAG,kBAAkB,QAAQ,SAAS,CAAC,EAAE,IAAI,CAAC,EAAE,SAAAE,SAAQ,MAAMA,QAAO;AACxF,MAAI,UAAU,UAAU,OAAQ,QAAO;AACvC,QAAM,aAAaF,sBAAqB,MAAM;AAE9C,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO,GAAG,UAAU,GAAG,UAAU,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;AAAA,IACzD,KAAK,UAAU;AACd,YAAM,aAAa,KAAK,KAAK,SAAS,CAAC;AACvC,YAAM,aAAa,KAAK,MAAM,SAAS,CAAC;AACxC,YAAM,OAAO,aAAa,IAAI,UAAU,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI;AACtE,aAAO,GAAG,UAAU,MAAM,GAAG,UAAU,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,GAAG,IAAI;AAAA,IACtE;AAAA,IACA,KAAK;AACJ,aAAO,GAAG,UAAU,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU;AAAA,EAC5D;AACD;AAEO,SAAS,aAAa,OAAuB;AACnD,SAAO,MACL,QAAQ,YAAY,EAAE,EACtB,QAAQ,SAAS,MAAM,EACvB,QAAQ,aAAa,EAAE,EACvB,QAAQ,YAAY,EAAE;AACzB;;;ALlXA,IAAMG,kBAAiB;AACvB,IAAM,iCAAiC;AACvC,IAAM,+BAA+B;AACrC,IAAMC,uCAAmE,oBAAI,IAAI;AAGjF,IAAI;AAEJ,SAAS,yBAAsD;AAC9D,MAAI,CAAC,2BAA2B;AAC/B,gCAA4B,OAAO,+BAAe,EAAE,MAAM,CAAC,UAAU;AACpE,kCAA4B;AAC5B,YAAM;AAAA,IACP,CAAC;AAAA,EACF;AACA,SAAO;AACR;AAEe,SAAR,WAA4B,IAAkB;AACpD,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,QAAM,UAAwB;AAAA,IAC7B,WAAW;AAAA,IACX,aAAa,oBAAI,IAAI;AAAA,IACrB,aAAa;AAAA,IACb,eAAe;AAAA,IACf,qBAAqB,CAAC;AAAA,IACtB,4BAA4BA;AAAA,EAC7B;AAEA,MAAI,oBAAoB;AACxB,MAAI,iBAAiB,IAAI,gBAAgB;AACzC,MAAI,qBAAqB;AACzB,MAAI;AACJ,MAAI,2BAA2B;AAC/B,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,QAAM,UAAU,MAAM,QAAQ,gBAAgB;AAC9C,QAAM,cAAc,CAAC,QAA0B,IAAI,mBAAmB;AAEtE,QAAM,eAAe,CAAC,YAA0C;AAC/D,QAAI,sBAAsB,QAAQ,WAAW,OAAO,EAAG;AACvD,YAAQ,YAAY;AACpB,YAAQ;AAAA,EACT;AAEA,QAAM,yBAAyB,MAAM;AACpC,QAAI,CAAC,uBAAwB;AAC7B,iBAAa,sBAAsB;AACnC,6BAAyB;AAAA,EAC1B;AAEA,QAAM,wBAAwB,CAAC,WAAmB;AACjD,8BAA0B,MAAM,IAAI,aAAa,QAAQ,YAAY,CAAC;AAAA,EACvE;AAEA,QAAM,0BAA0B,CAAC,KAAa,eAC7C,uBAAuB,QAAQ,OAC/B,sBAAsB,eAAe,cACrC,eAAe;AAEhB,QAAM,4BAA4B,CAAC,KAAa,YAAoB,cACnE,wBAAwB,KAAK,UAAU,KAAK,cAAc;AAE3D,QAAM,sBAAsB,CAAC,KAAa,YAAoB,cAAsB;AACnF,QAAI,CAAC,0BAA0B,KAAK,YAAY,SAAS,EAAG;AAC5D,QAAI,0BAA0B;AAC7B,gCAA0B,EAAE,KAAK,YAAY,UAAU;AACvD;AAAA,IACD;AAEA,+BAA2B;AAC3B,UAAM,kBAAkB,IAAI,gBAAgB;AAC5C,+BAA2B;AAC3B,UAAM,YAAY;AACjB,UAAI;AACH,cAAM,UAAU,MAAM,cAAc,IAAI,KAAK,gBAAgB,MAAM;AACnE,YAAI,0BAA0B,KAAK,YAAY,SAAS,EAAG,cAAa,OAAO;AAAA,MAChF,QAAQ;AACP,YAAI,0BAA0B,KAAK,YAAY,SAAS,EAAG,cAAa,MAAS;AAAA,MAClF,UAAE;AACD,mCAA2B;AAC3B,YAAI,6BAA6B,gBAAiB,4BAA2B;AAC7E,cAAM,UAAU;AAChB,kCAA0B;AAC1B,YAAI,QAAS,qBAAoB,QAAQ,KAAK,QAAQ,YAAY,QAAQ,SAAS;AAAA,MACpF;AAAA,IACD,GAAG;AAAA,EACJ;AAEA,QAAM,mBAAmB,CAAC,KAAa,aAAa,sBAAsB;AACzE,QAAI,CAAC,wBAAwB,KAAK,UAAU,EAAG;AAC/C,wBAAoB,KAAK,YAAY,EAAE,kBAAkB;AAAA,EAC1D;AAEA,QAAM,2BAA2B,CAAC,KAAa,aAAa,sBAAsB;AACjF,QAAI,CAAC,wBAAwB,KAAK,UAAU,EAAG;AAC/C,UAAM,YAAY,EAAE;AACpB,2BAAuB;AACvB,6BAAyB,WAAW,MAAM;AACzC,+BAAyB;AACzB,0BAAoB,KAAK,YAAY,SAAS;AAAA,IAC/C,GAAG,4BAA4B;AAAA,EAChC;AAEA,QAAM,qCAAqC,CAAC,QAA0B;AACrE,QAAI,CAAC,yBAAyB,sBAAsB,QAAQ,IAAI,IAAK;AACrE,6BAAyB,sBAAsB,KAAK,sBAAsB,UAAU;AAAA,EACrF;AAEA,QAAM,gBAAgB,CAAC,QAA0B;AAChD,UAAM,aAAa,EAAE;AACrB,mBAAe,MAAM,IAAI,aAAa,uCAAuC,YAAY,CAAC;AAC1F,qBAAiB,IAAI,gBAAgB;AACrC,UAAM,MAAM,IAAI;AAChB,2BAAuB,IAAI;AAC3B,YAAQ,UAAU,QAAQ;AAC1B,2BAAuB;AACvB,0BAAsB,qCAAqC;AAC3D,2BAAuB;AACvB,4BAAwB,IAAI,SAAS,QAAQ,EAAE,KAAK,WAAW,IAAI;AACnE,YAAQ,YAAY;AACpB,YAAQ,sBAAsB,CAAC;AAC/B,YAAQ,6BAA6BA;AACrC,QAAI,GAAG,UAAUD,iBAAgB,MAAS;AAC1C,QAAI,CAAC,yBAAyB,CAAC,OAAQ;AACvC,UAAM,oBAAoB,+BAA+B,GAAG;AAC5D,YAAQ,sBAAsB,wBAAwB,iBAAiB;AACvE,YAAQ,6BAA6B,gCAAgC,iBAAiB;AACtF,QAAI,GAAG,UAAU,CAAC,KAAK,OAAO,eAAe;AAC5C,cAAQ,gBAAgB,MAAM,IAAI,cAAc;AAEhD,YAAM,yBAAyB,MAAM,iBAAiB,KAAK,UAAU;AACrE,YAAM,oBAAoB,WAAW,eAAe,MAAM;AACzD,gBAAQ,YAAY;AACpB,8BAAsB,+BAA+B;AACrD,+BAAuB;AACvB,+BAAuB;AACvB,YAAI,cAAc;AAAA,MACnB,CAAC;AACD,YAAM,QAAQ,YAAY,MAAM;AAC/B,+BAAuB;AACvB,+BAAuB;AACvB,YAAI,cAAc;AAAA,MACnB,GAAG,8BAA8B;AAEjC,aAAO;AAAA,QACN,UAAU;AACT,4BAAkB;AAClB,wBAAc,KAAK;AACnB,cAAI,wBAAwB,KAAK,UAAU,GAAG;AAC7C,oCAAwB;AACxB,kCAAsB,4BAA4B;AAClD,mCAAuB;AACvB,sCAA0B;AAC1B,oBAAQ,YAAY;AACpB,oBAAQ,sBAAsB,CAAC;AAC/B,oBAAQ,6BAA6BC;AACrC,oBAAQ,gBAAgB;AAAA,UACzB;AAAA,QACD;AAAA,QACA,aAAa;AAAA,QAAC;AAAA,QACd,OAAO,OAAyB;AAC/B,cAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,gBAAM,SAAS,uBACZ,EAAE,GAAG,OAAO,QAAQ,eAAe,qBAAqB,IACxD,OAAO;AACV,gBAAM,YAAY,gBAAgB,EAAE;AACpC,gBAAM,WAAW;AAAA,YAChB;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACD;AACA,gBAAM,QAAQ,WAAW,SAAS,MAAM,IAAI,IAAI,CAAC;AACjD,gBAAM;AAAA,YACL,GAAG;AAAA,cACF;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACD;AAAA,UACD;AACA,iBAAO;AAAA,QACR;AAAA,MACD;AAAA,IACD,CAAC;AACD,qBAAiB,KAAK,UAAU;AAAA,EACjC;AAEA,QAAM,WAAWC,aAAY;AAC7B,QAAM,aAAa,iBAAiB,QAAQ;AAC5C,QAAM,iBAA2C;AAAA,IAChD,cAAc;AAAA,IACd,WAAW,MAAM,UAAU,uBAAuB,UAAU;AAAA,IAC5D,cAAc,MAAM;AACnB,YAAM,aAAa;AACnB,aAAO;AAAA,QACN,QAAQ,eAAe;AAAA,QACvB,WAAW,MAAM,eAAe,qBAAqB,CAAC,eAAe,OAAO;AAAA,MAC7E;AAAA,IACD;AAAA,IACA,MAAM,MAAM,KAAK;AAChB,UAAI,IAAI,mBAAmB,qBAAsB;AACjD,6BAAuB;AACvB,eAAS;AACT,cAAQ;AAAA,IACT;AAAA,IACA,QAAQ,eAAe,KAAK;AAC3B,UAAI,IAAI,mBAAmB,qBAAsB;AACjD,6BAAuB;AACvB,cAAQ;AAAA,IACT;AAAA,EACD;AACA,KAAG,gBAAgB,cAAc;AAAA,IAChC,aAAa;AAAA,IACb,wBAAwB;AAAA,IACxB,SAAS,OAAO,MAAM,QAAQ;AAC7B,YAAM,WAAW,MAAM,uBAAuB;AAC9C,UAAI,IAAI,mBAAmB,qBAAsB;AACjD,YAAM,SAAS,wBAAwB,MAAM,KAAK,cAAc;AAAA,IACjE;AAAA,EACD,CAAC;AAED,KAAG,GAAG,iBAAiB,CAAC,QAAQ,QAAQ;AACvC,YAAQ,YAAY;AACpB,YAAQ,YAAY,MAAM;AAC1B,YAAQ,cAAc;AACtB,YAAQ,WAAW;AACnB,aAAS,+BAA+B,QAAQ;AAChD,UAAM,iBAAiB,gCAAgC;AACvD,QAAI,eAAgB,KAAI,GAAG,OAAO,gBAAgB,SAAS;AAC3D,QAAI,OAAO,YAAY,SAAS,GAAG;AAClC,UAAI,GAAG,OAAO,0BAA0B,MAAM,GAAG,SAAS;AAAA,IAC3D;AACA,YAAQ,gBAAgB,GAAG,iBAAiB;AAC5C,kBAAc,GAAG;AAAA,EAClB,CAAC;AAED,KAAG,GAAG,gBAAgB,CAAC,QAAQ,QAAQ;AACtC,kBAAc,GAAG;AACjB,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,oBAAoB,CAAC,QAAQ,QAAQ;AAC1C,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,yBAAqB;AACrB,mBAAe,MAAM,IAAI,aAAa,gCAAgC,YAAY,CAAC;AACnF,2BAAuB;AACvB,2BAAuB;AACvB,4BAAwB;AACxB,0BAAsB,8BAA8B;AACpD,2BAAuB;AACvB,8BAA0B;AAC1B,YAAQ,YAAY;AACpB,YAAQ,YAAY,MAAM;AAC1B,YAAQ,cAAc;AACtB,YAAQ,WAAW;AACnB,YAAQ,sBAAsB,CAAC;AAC/B,YAAQ,6BAA6BD;AACrC,QAAI,GAAG,UAAU,MAAS;AAC1B,QAAI,GAAG,UAAUD,iBAAgB,MAAS;AAC1C,YAAQ,gBAAgB;AAAA,EACzB,CAAC;AAED,KAAG,GAAG,gBAAgB,MAAM,QAAQ,CAAC;AAErC,KAAG,GAAG,yBAAyB,CAAC,UAAU;AACzC,YAAQ,gBAAgB,MAAM;AAC9B,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,eAAe,CAAC,QAAQ,QAAQ;AACrC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,cAAc;AACtB,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,aAAa,CAAC,QAAQ,QAAQ;AACnC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,YAAY,MAAM;AAC1B,uCAAmC,GAAG;AACtC,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,iBAAiB,CAAC,QAAQ,QAAQ;AACvC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,cAAc;AACtB,YAAQ,YAAY,MAAM;AAC1B,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,mBAAmB,CAAC,OAAO,QAAQ;AACxC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,WAAW,EAAE,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM;AAC1D,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,iBAAiB,CAAC,QAAQ,QAAQ;AACvC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,WAAW;AACnB,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,cAAc,CAAC,QAAQ,QAAQ;AACpC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,YAAQ,aAAa;AACrB,YAAQ,cAAc;AACtB,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,YAAY,CAAC,QAAQ,QAAQ;AAClC,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,uCAAmC,GAAG;AACtC,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,wBAAwB,CAAC,OAAO,QAAQ;AAC7C,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,UAAM,eAAe,QAAQ,YAAY,IAAI,MAAM,QAAQ,KAAK;AAChE,YAAQ,YAAY,IAAI,MAAM,UAAU,eAAe,CAAC;AACxD,YAAQ;AAAA,EACT,CAAC;AAED,KAAG,GAAG,sBAAsB,CAAC,OAAO,QAAQ;AAC3C,QAAI,CAAC,YAAY,GAAG,EAAG;AACvB,UAAM,eAAe,QAAQ,YAAY,IAAI,MAAM,QAAQ,KAAK;AAChE,QAAI,gBAAgB,EAAG,SAAQ,YAAY,OAAO,MAAM,QAAQ;AAAA,QAC3D,SAAQ,YAAY,IAAI,MAAM,UAAU,eAAe,CAAC;AAE7D,uCAAmC,GAAG;AACtC,YAAQ;AAAA,EACT,CAAC;AACF;AAEA,SAAS,0BAA0B,QAA0C;AAC5E,QAAM,UAAU,OAAO,YAAY,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,SAAS,KAAK,OAAO;AACzE,QAAM,YAAY,OAAO,YAAY,SAAS,QAAQ;AACtD,SAAO;AAAA,IACN,2BAA2B,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC7C,GAAI,YAAY,IAAI,CAAC,IAAI,SAAS,OAAO,IAAI,CAAC;AAAA,EAC/C,EAAE,KAAK,GAAG;AACX;",
|
|
6
|
+
"names": ["getAgentDir", "rendered", "segment", "isAbsolute", "visibleWidth", "sanitizeTerminalText", "isAbsolute", "formatCount", "sanitizeTerminalText", "visibleWidth", "segment", "STATUSLINE_KEY", "EMPTY_EXTENSION_STATUS_ICON_ALIASES", "getAgentDir"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-statusline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Pi extension that replaces the footer with an information-rich statusline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,9 +23,6 @@
|
|
|
23
23
|
"./dist/index.ts"
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
|
-
"piExtension": {
|
|
27
|
-
"lifecycle": "stable"
|
|
28
|
-
},
|
|
29
26
|
"scripts": {
|
|
30
27
|
"build": "node scripts/build-runtime.mjs",
|
|
31
28
|
"check": "npm run build && biome check --vcs-use-ignore-file=false src test scripts package.json tsconfig.json README.md && npm run typecheck",
|
|
@@ -38,10 +35,10 @@
|
|
|
38
35
|
"@earendil-works/pi-tui": "*"
|
|
39
36
|
},
|
|
40
37
|
"devDependencies": {
|
|
41
|
-
"@biomejs/biome": "2.5.
|
|
42
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
43
|
-
"@earendil-works/pi-tui": "0.84.
|
|
44
|
-
"@types/node": "26.
|
|
38
|
+
"@biomejs/biome": "2.5.11",
|
|
39
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
40
|
+
"@earendil-works/pi-tui": "0.84.4",
|
|
41
|
+
"@types/node": "26.4.0",
|
|
45
42
|
"esbuild": "0.28.2",
|
|
46
43
|
"typescript": "7.0.2"
|
|
47
44
|
},
|
package/src/ansi.ts
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
|
-
export function ansiStyle(
|
|
1
|
+
export function ansiStyle(
|
|
2
|
+
text: string,
|
|
3
|
+
colors: { fg?: string; bg?: string },
|
|
4
|
+
trueColor = true,
|
|
5
|
+
): string {
|
|
2
6
|
const codes = [
|
|
3
|
-
colors.fg ?
|
|
4
|
-
colors.bg ?
|
|
7
|
+
colors.fg ? colorCode("38", colors.fg, trueColor) : undefined,
|
|
8
|
+
colors.bg ? colorCode("48", colors.bg, trueColor) : undefined,
|
|
5
9
|
].filter((code): code is string => code !== undefined);
|
|
6
10
|
if (codes.length === 0) return text;
|
|
7
11
|
return `\u001b[${codes.join(";")}m${text}\u001b[0m`;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
export function ansiFg(hex: string, text: string): string {
|
|
11
|
-
return ansiStyle(text, { fg: hex });
|
|
14
|
+
export function ansiFg(hex: string, text: string, trueColor = true): string {
|
|
15
|
+
return ansiStyle(text, { fg: hex }, trueColor);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
|
-
function
|
|
18
|
+
function colorCode(prefix: "38" | "48", hex: string, trueColor: boolean): string {
|
|
15
19
|
const { red, green, blue } = hexToRgb(hex);
|
|
16
|
-
return
|
|
20
|
+
return trueColor
|
|
21
|
+
? `${prefix};2;${red};${green};${blue}`
|
|
22
|
+
: `${prefix};5;${rgbToAnsi256(red, green, blue)}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function rgbToAnsi256(red: number, green: number, blue: number): number {
|
|
26
|
+
const channels = [red, green, blue].map((value) => Math.round((value / 255) * 5));
|
|
27
|
+
return 16 + 36 * (channels[0] ?? 0) + 6 * (channels[1] ?? 0) + (channels[2] ?? 0);
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
function hexToRgb(hex: string): { red: number; green: number; blue: number } {
|
package/src/extension-status.ts
CHANGED
|
@@ -20,8 +20,12 @@ const COMPATIBLE_STATUS_ICON_KEYS: Readonly<Record<string, string>> = {
|
|
|
20
20
|
pisync: "sync",
|
|
21
21
|
};
|
|
22
22
|
const EMPTY_EXTENSION_STATUS_ICON_ALIASES: ExtensionStatusIconAliasMap = new Map();
|
|
23
|
-
function extensionStatusSeparator(
|
|
24
|
-
|
|
23
|
+
function extensionStatusSeparator(
|
|
24
|
+
config: StatuslineConfig,
|
|
25
|
+
theme: Theme,
|
|
26
|
+
trueColor: boolean,
|
|
27
|
+
): string {
|
|
28
|
+
return powerlineExtensionSeparator(theme, config.palettePreset, trueColor);
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export function formatExtensionStatuses(
|
|
@@ -30,8 +34,9 @@ export function formatExtensionStatuses(
|
|
|
30
34
|
config: StatuslineConfig,
|
|
31
35
|
runtime: ExtensionStatusRuntime,
|
|
32
36
|
hiddenKeys: ReadonlySet<string> = new Set(),
|
|
37
|
+
trueColor = true,
|
|
33
38
|
): string {
|
|
34
|
-
const separator = extensionStatusSeparator(config, theme);
|
|
39
|
+
const separator = extensionStatusSeparator(config, theme, trueColor);
|
|
35
40
|
const visibleStatuses = [
|
|
36
41
|
...formatDuplicateExtensionStatus(runtime, theme),
|
|
37
42
|
...[...statuses.entries()]
|
package/src/powerline.ts
CHANGED
|
@@ -24,10 +24,11 @@ export function renderPowerlineStatusline(
|
|
|
24
24
|
width: number,
|
|
25
25
|
items: RenderItem[],
|
|
26
26
|
config: Pick<StatuslineConfig, "palettePreset" | "palette" | "density" | "separator">,
|
|
27
|
+
trueColor = true,
|
|
27
28
|
): string {
|
|
28
29
|
if (items.length === 0 || width <= 0) return "";
|
|
29
30
|
return splitLines(items)
|
|
30
|
-
.map((segments) => fitPowerlineSegments(segments, width, config))
|
|
31
|
+
.map((segments) => fitPowerlineSegments(segments, width, config, trueColor))
|
|
31
32
|
.join("\n");
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -60,11 +61,12 @@ function fitPowerlineSegments(
|
|
|
60
61
|
segments: readonly RenderSegment[],
|
|
61
62
|
width: number,
|
|
62
63
|
config: Pick<StatuslineConfig, "palettePreset" | "palette" | "density" | "separator">,
|
|
64
|
+
trueColor: boolean,
|
|
63
65
|
): string {
|
|
64
66
|
if (segments.length === 0) return "";
|
|
65
67
|
const fitted = [...segments];
|
|
66
68
|
while (fitted.length > 1) {
|
|
67
|
-
const rendered = joinPowerlineSegments(fitted, config);
|
|
69
|
+
const rendered = joinPowerlineSegments(fitted, config, trueColor);
|
|
68
70
|
if (visibleWidth(rendered) <= width) return rendered;
|
|
69
71
|
let removalIndex = 0;
|
|
70
72
|
for (let index = 1; index < fitted.length; index += 1) {
|
|
@@ -80,33 +82,37 @@ function fitPowerlineSegments(
|
|
|
80
82
|
}
|
|
81
83
|
fitted.splice(removalIndex, 1);
|
|
82
84
|
}
|
|
83
|
-
const rendered = joinPowerlineSegments(fitted, config);
|
|
85
|
+
const rendered = joinPowerlineSegments(fitted, config, trueColor);
|
|
84
86
|
return visibleWidth(rendered) <= width ? rendered : "";
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
export function powerlineExtensionSeparator(
|
|
88
90
|
_theme: Theme,
|
|
89
91
|
palettePreset: PalettePreset = "tokyo-night",
|
|
92
|
+
trueColor = true,
|
|
90
93
|
): string {
|
|
91
|
-
return ansiStyle(" โข ", { fg: resolvePreset(palettePreset).extensionSeparator });
|
|
94
|
+
return ansiStyle(" โข ", { fg: resolvePreset(palettePreset).extensionSeparator }, trueColor);
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
function joinPowerlineSegments(
|
|
95
98
|
segments: RenderSegment[],
|
|
96
99
|
config: Pick<StatuslineConfig, "palettePreset" | "palette" | "density" | "separator">,
|
|
100
|
+
trueColor: boolean,
|
|
97
101
|
): string {
|
|
98
102
|
const preset = resolvePreset(config.palettePreset);
|
|
99
103
|
const blocks = contiguousBlocks(segments, preset, config.palettePreset, config.palette);
|
|
100
|
-
let line = ansiStyle("โโโ", { fg: preset.lead });
|
|
104
|
+
let line = ansiStyle("โโโ", { fg: preset.lead }, trueColor);
|
|
101
105
|
|
|
102
106
|
for (const [index, block] of blocks.entries()) {
|
|
103
107
|
const previous = index === 0 ? undefined : blocks[index - 1]?.colors;
|
|
104
|
-
if (previous)
|
|
105
|
-
|
|
108
|
+
if (previous) {
|
|
109
|
+
line += ansiStyle("๎ด", { fg: previous.bg, bg: block.colors.bg }, trueColor);
|
|
110
|
+
}
|
|
111
|
+
line += ansiStyle(formatBlockText(block, config), block.colors, trueColor);
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
const lastBlock = blocks.at(-1);
|
|
109
|
-
if (lastBlock) line += ansiStyle("๎ด", { fg: lastBlock.colors.bg });
|
|
115
|
+
if (lastBlock) line += ansiStyle("๎ด", { fg: lastBlock.colors.bg }, trueColor);
|
|
110
116
|
return line;
|
|
111
117
|
}
|
|
112
118
|
|
package/src/render.ts
CHANGED
|
@@ -4,7 +4,9 @@ import type {
|
|
|
4
4
|
ReadonlyFooterDataProvider,
|
|
5
5
|
Theme,
|
|
6
6
|
ThemeColor,
|
|
7
|
+
UIPromptKind,
|
|
7
8
|
} from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { sliceByColumn, visibleWidth } from "@earendil-works/pi-tui";
|
|
8
10
|
import { sanitizeTerminalText } from "@narumitw/pi-tui-kit/terminal-text";
|
|
9
11
|
import { formatDirectoryPath } from "./directory.js";
|
|
10
12
|
import {
|
|
@@ -31,6 +33,7 @@ export interface RuntimeState extends ExtensionStatusRuntime {
|
|
|
31
33
|
turnCount: number;
|
|
32
34
|
activeTools: Map<string, number>;
|
|
33
35
|
isStreaming: boolean;
|
|
36
|
+
uiPrompt?: { kind: UIPromptKind; title?: string };
|
|
34
37
|
thinkingLevel: ThinkingLevel;
|
|
35
38
|
gitStatus?: GitStatusSummary;
|
|
36
39
|
requestRender?: () => void;
|
|
@@ -44,6 +47,7 @@ export function renderStatusline(
|
|
|
44
47
|
_theme: Theme,
|
|
45
48
|
config: StatuslineConfig,
|
|
46
49
|
runtime: RuntimeState,
|
|
50
|
+
trueColor = true,
|
|
47
51
|
): string {
|
|
48
52
|
if (width <= 0) return "";
|
|
49
53
|
|
|
@@ -73,7 +77,7 @@ export function renderStatusline(
|
|
|
73
77
|
segments.push(...row.segments);
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
return renderPowerlineStatusline(width, segments, config);
|
|
80
|
+
return renderPowerlineStatusline(width, segments, config, trueColor);
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
export function renderExtensionStatusline(
|
|
@@ -83,6 +87,7 @@ export function renderExtensionStatusline(
|
|
|
83
87
|
config: StatuslineConfig,
|
|
84
88
|
runtime: RuntimeState,
|
|
85
89
|
mainLine: string,
|
|
90
|
+
trueColor = true,
|
|
86
91
|
): string[] {
|
|
87
92
|
const statuses = footerData.getExtensionStatuses();
|
|
88
93
|
const prContext = prContextFromStatuses(statuses);
|
|
@@ -93,6 +98,7 @@ export function renderExtensionStatusline(
|
|
|
93
98
|
config,
|
|
94
99
|
runtime,
|
|
95
100
|
rendersPrInline ? GITHUB_PR_STATUS_KEYS : undefined,
|
|
101
|
+
trueColor,
|
|
96
102
|
);
|
|
97
103
|
return wrapExtensionStatusline(status, width);
|
|
98
104
|
}
|
|
@@ -248,12 +254,40 @@ export function contextColor(percent: number | null | undefined): ThemeColor {
|
|
|
248
254
|
return "success";
|
|
249
255
|
}
|
|
250
256
|
|
|
257
|
+
const MAX_UI_PROMPT_TITLE_CODE_POINTS = 256;
|
|
258
|
+
const MAX_UI_PROMPT_TITLE_WIDTH = 40;
|
|
259
|
+
|
|
260
|
+
function boundUIPromptTitleLength(title: string): string {
|
|
261
|
+
let end = 0;
|
|
262
|
+
let ellipsisEnd = 0;
|
|
263
|
+
let codePoints = 0;
|
|
264
|
+
while (end < title.length && codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) {
|
|
265
|
+
const codePoint = title.codePointAt(end) ?? 0;
|
|
266
|
+
end += codePoint > 0xffff ? 2 : 1;
|
|
267
|
+
codePoints += 1;
|
|
268
|
+
if (codePoints < MAX_UI_PROMPT_TITLE_CODE_POINTS) ellipsisEnd = end;
|
|
269
|
+
}
|
|
270
|
+
return end < title.length ? `${title.slice(0, ellipsisEnd)}โฆ` : title;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function formatUIPromptTitle(title: string | undefined): string {
|
|
274
|
+
const safeTitle = title ? sanitizeTerminalText(title).trim() : "";
|
|
275
|
+
const boundedTitle = boundUIPromptTitleLength(safeTitle);
|
|
276
|
+
if (visibleWidth(boundedTitle) <= MAX_UI_PROMPT_TITLE_WIDTH) return boundedTitle;
|
|
277
|
+
return `${sliceByColumn(boundedTitle, 0, MAX_UI_PROMPT_TITLE_WIDTH - 1, true)}โฆ`;
|
|
278
|
+
}
|
|
279
|
+
|
|
251
280
|
export function formatToolActivity(runtime: RuntimeState): string | undefined {
|
|
281
|
+
if (runtime.uiPrompt) {
|
|
282
|
+
const title = formatUIPromptTitle(runtime.uiPrompt.title);
|
|
283
|
+
return `โจ waiting for ${runtime.uiPrompt.kind}${title ? ` ยท ${title}` : ""}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
252
286
|
const active = [...runtime.activeTools.entries()];
|
|
253
287
|
if (active.length > 0) {
|
|
254
288
|
const [name, count] = active[0] ?? ["tool", 1];
|
|
255
289
|
const suffix = count > 1 ? `ร${count}` : active.length > 1 ? `+${active.length - 1}` : "";
|
|
256
|
-
return
|
|
290
|
+
return `โ๏ธ ${name}${suffix}`;
|
|
257
291
|
}
|
|
258
292
|
|
|
259
293
|
return runtime.isStreaming ? "๐ญ thinking" : undefined;
|
|
@@ -274,11 +308,17 @@ export function prLinkFromStatuses(statuses: ReadonlyMap<string, string>): strin
|
|
|
274
308
|
|
|
275
309
|
export function prContextFromStatuses(statuses: ReadonlyMap<string, string>): string | undefined {
|
|
276
310
|
const value = statuses.get(GITHUB_PR_KEY);
|
|
311
|
+
if (!value) return undefined;
|
|
277
312
|
const link = prLinkFromStatuses(statuses);
|
|
278
|
-
|
|
313
|
+
const reference = link ?? plainPrReference(value);
|
|
314
|
+
if (!reference) return undefined;
|
|
315
|
+
|
|
316
|
+
const state = compactPrState(link ? value.replace(link, "") : value);
|
|
317
|
+
return state ? `${reference} ยท ${state}` : undefined;
|
|
318
|
+
}
|
|
279
319
|
|
|
280
|
-
|
|
281
|
-
return
|
|
320
|
+
function plainPrReference(value: string): string | undefined {
|
|
321
|
+
return /^PR\s+(#\d+):/u.exec(value)?.[1];
|
|
282
322
|
}
|
|
283
323
|
|
|
284
324
|
function compactPrState(value: string): string | undefined {
|
package/src/statusline.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type ExtensionContext,
|
|
5
5
|
getAgentDir,
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
|
+
import { getCapabilities } from "@earendil-works/pi-tui";
|
|
7
8
|
import { completeStatuslineArguments } from "./command-contract.js";
|
|
8
9
|
import type { StatuslineCommandOptions } from "./commands.js";
|
|
9
10
|
import {
|
|
@@ -193,10 +194,27 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
193
194
|
const config = previewPalettePreset
|
|
194
195
|
? { ...loaded.config, palettePreset: previewPalettePreset }
|
|
195
196
|
: loaded.config;
|
|
196
|
-
const
|
|
197
|
+
const trueColor = getCapabilities().trueColor;
|
|
198
|
+
const mainLine = renderStatusline(
|
|
199
|
+
width,
|
|
200
|
+
ctx,
|
|
201
|
+
footerData,
|
|
202
|
+
theme,
|
|
203
|
+
config,
|
|
204
|
+
runtime,
|
|
205
|
+
trueColor,
|
|
206
|
+
);
|
|
197
207
|
const lines = mainLine ? mainLine.split("\n") : [];
|
|
198
208
|
lines.push(
|
|
199
|
-
...renderExtensionStatusline(
|
|
209
|
+
...renderExtensionStatusline(
|
|
210
|
+
width,
|
|
211
|
+
footerData,
|
|
212
|
+
theme,
|
|
213
|
+
config,
|
|
214
|
+
runtime,
|
|
215
|
+
mainLine,
|
|
216
|
+
trueColor,
|
|
217
|
+
),
|
|
200
218
|
);
|
|
201
219
|
return lines;
|
|
202
220
|
},
|
|
@@ -243,6 +261,7 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
243
261
|
runtime.turnCount = 0;
|
|
244
262
|
runtime.activeTools.clear();
|
|
245
263
|
runtime.isStreaming = false;
|
|
264
|
+
runtime.uiPrompt = undefined;
|
|
246
265
|
loaded = loadStatuslineSettingsForAgent(agentDir);
|
|
247
266
|
const settingsNotice = consumeStatuslineSettingsNotice();
|
|
248
267
|
if (settingsNotice) ctx.ui.notify(settingsNotice, "warning");
|
|
@@ -271,6 +290,7 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
271
290
|
runtime.gitStatus = undefined;
|
|
272
291
|
runtime.activeTools.clear();
|
|
273
292
|
runtime.isStreaming = false;
|
|
293
|
+
runtime.uiPrompt = undefined;
|
|
274
294
|
runtime.duplicateExtensions = [];
|
|
275
295
|
runtime.extensionStatusIconAliases = EMPTY_EXTENSION_STATUS_ICON_ALIASES;
|
|
276
296
|
ctx.ui.setFooter(undefined);
|
|
@@ -305,6 +325,18 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
305
325
|
refresh();
|
|
306
326
|
});
|
|
307
327
|
|
|
328
|
+
pi.on("ui_prompt_start", (event, ctx) => {
|
|
329
|
+
if (!ownsRuntime(ctx)) return;
|
|
330
|
+
runtime.uiPrompt = { kind: event.kind, title: event.title };
|
|
331
|
+
refresh();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
pi.on("ui_prompt_end", (_event, ctx) => {
|
|
335
|
+
if (!ownsRuntime(ctx)) return;
|
|
336
|
+
runtime.uiPrompt = undefined;
|
|
337
|
+
refresh();
|
|
338
|
+
});
|
|
339
|
+
|
|
308
340
|
pi.on("turn_start", (_event, ctx) => {
|
|
309
341
|
if (!ownsRuntime(ctx)) return;
|
|
310
342
|
runtime.turnCount += 1;
|