@narumitw/pi-statusline 0.1.21 โ 0.1.23
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 +3 -4
- package/package.json +1 -1
- package/src/statusline.ts +0 -34
package/README.md
CHANGED
|
@@ -10,9 +10,8 @@ Use it to monitor model selection, thinking level, git branch, working directory
|
|
|
10
10
|
|
|
11
11
|
- Replaces the default Pi footer with a compact rich statusline.
|
|
12
12
|
- Shows model, thinking level, git branch, project directory, active tool, context usage, tokens, cost, and clock.
|
|
13
|
-
- Displays compact statuses
|
|
13
|
+
- Displays compact statuses published through Pi's generic extension status API.
|
|
14
14
|
- Preserves extension-provided status icons when the status text starts with one.
|
|
15
|
-
- Shows active subagent count and execution mode while subagent tools are running.
|
|
16
15
|
- Warns when the same extension package is installed from multiple sources.
|
|
17
16
|
- Uses emoji-labeled segments for readability.
|
|
18
17
|
- Adapts to terminal width and truncates safely.
|
|
@@ -53,14 +52,14 @@ The default statusline includes:
|
|
|
53
52
|
|
|
54
53
|
Statuses from other extensions appear on their own compact line below the main statusline and are separated with `๎ฑ`.
|
|
55
54
|
|
|
56
|
-
`pi-statusline` is extension-agnostic: it does not
|
|
55
|
+
`pi-statusline` is extension-agnostic: it consumes Pi's generic extension status API and does not import or depend on status-producing extensions. If an extension wants a custom icon, it should include that icon at the start of its status text, for example `ctx.ui.setStatus("goal", "๐ฏ active")`. Statuses without a leading icon use the generic `๐` icon.
|
|
57
56
|
|
|
58
57
|
Examples:
|
|
59
58
|
|
|
60
59
|
- `๐ active` for a plain status such as `goal: active`.
|
|
61
60
|
- `๐ฏ active` when the producing extension sets `๐ฏ active`.
|
|
62
61
|
- `๐ ty โ ruff โ` when the producing extension sets a Python status with a leading icon.
|
|
63
|
-
-
|
|
62
|
+
- `๐งช running` when any extension publishes an activity status with its own icon.
|
|
64
63
|
- `โ ๏ธ dup biome-lsp` when local and npm installs register the same extension.
|
|
65
64
|
|
|
66
65
|
## ๐ง Use cases
|
package/package.json
CHANGED
package/src/statusline.ts
CHANGED
|
@@ -40,7 +40,6 @@ interface StatuslineConfig {
|
|
|
40
40
|
interface RuntimeState {
|
|
41
41
|
turnCount: number;
|
|
42
42
|
activeTools: Map<string, number>;
|
|
43
|
-
activeSubagents: Map<string, SubagentActivity>;
|
|
44
43
|
lastTool?: string;
|
|
45
44
|
lastCompletedTool?: string;
|
|
46
45
|
isStreaming: boolean;
|
|
@@ -49,11 +48,6 @@ interface RuntimeState {
|
|
|
49
48
|
requestRender?: () => void;
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
interface SubagentActivity {
|
|
53
|
-
mode: string;
|
|
54
|
-
count: number;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
interface TokenTotals {
|
|
58
52
|
input: number;
|
|
59
53
|
output: number;
|
|
@@ -98,7 +92,6 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
98
92
|
const runtime: RuntimeState = {
|
|
99
93
|
turnCount: 0,
|
|
100
94
|
activeTools: new Map(),
|
|
101
|
-
activeSubagents: new Map(),
|
|
102
95
|
isStreaming: false,
|
|
103
96
|
thinkingLevel: "off",
|
|
104
97
|
duplicateExtensions: [],
|
|
@@ -175,9 +168,6 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
175
168
|
pi.on("tool_execution_start", (event) => {
|
|
176
169
|
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
177
170
|
runtime.activeTools.set(event.toolName, currentCount + 1);
|
|
178
|
-
if (event.toolName === "subagent") {
|
|
179
|
-
runtime.activeSubagents.set(event.toolCallId, parseSubagentActivity(event.args));
|
|
180
|
-
}
|
|
181
171
|
runtime.lastTool = event.toolName;
|
|
182
172
|
refresh();
|
|
183
173
|
});
|
|
@@ -186,7 +176,6 @@ export default function statusline(pi: ExtensionAPI) {
|
|
|
186
176
|
const currentCount = runtime.activeTools.get(event.toolName) ?? 0;
|
|
187
177
|
if (currentCount <= 1) runtime.activeTools.delete(event.toolName);
|
|
188
178
|
else runtime.activeTools.set(event.toolName, currentCount - 1);
|
|
189
|
-
if (event.toolName === "subagent") runtime.activeSubagents.delete(event.toolCallId);
|
|
190
179
|
|
|
191
180
|
runtime.lastCompletedTool = event.toolName;
|
|
192
181
|
refresh();
|
|
@@ -412,7 +401,6 @@ function formatExtensionStatuses(
|
|
|
412
401
|
): string {
|
|
413
402
|
const separator = theme.fg("dim", " ๎ฑ ");
|
|
414
403
|
const visibleStatuses = [
|
|
415
|
-
...formatSubagentStatus(runtime, theme),
|
|
416
404
|
...formatDuplicateExtensionStatus(runtime, theme),
|
|
417
405
|
...[...statuses.entries()]
|
|
418
406
|
.filter(([key, value]) => key !== STATUSLINE_KEY && value.trim().length > 0)
|
|
@@ -430,16 +418,6 @@ function formatExtensionStatus(key: string, value: string, theme: Theme): string
|
|
|
430
418
|
return `${theme.fg(color, status.icon)} ${theme.fg(textColor, text)}`;
|
|
431
419
|
}
|
|
432
420
|
|
|
433
|
-
function formatSubagentStatus(runtime: RuntimeState, theme: Theme): string[] {
|
|
434
|
-
const activities = [...runtime.activeSubagents.values()];
|
|
435
|
-
if (activities.length === 0) return [];
|
|
436
|
-
|
|
437
|
-
const total = activities.reduce((sum, activity) => sum + activity.count, 0);
|
|
438
|
-
const mode = activities[0]?.mode ?? "active";
|
|
439
|
-
const suffix = activities.length > 1 ? ` +${activities.length - 1}` : "";
|
|
440
|
-
return [`${theme.fg("accent", "๐งโ๐คโ๐ง")} ${theme.fg("muted", `${total} ${mode}${suffix}`)}`];
|
|
441
|
-
}
|
|
442
|
-
|
|
443
421
|
function formatDuplicateExtensionStatus(runtime: RuntimeState, theme: Theme): string[] {
|
|
444
422
|
if (runtime.duplicateExtensions.length === 0) return [];
|
|
445
423
|
const names = runtime.duplicateExtensions.slice(0, 2).join(", ");
|
|
@@ -488,18 +466,6 @@ function escapeRegExp(value: string): string {
|
|
|
488
466
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
489
467
|
}
|
|
490
468
|
|
|
491
|
-
function parseSubagentActivity(args: unknown): SubagentActivity {
|
|
492
|
-
const input = args && typeof args === "object" ? (args as Record<string, unknown>) : {};
|
|
493
|
-
const tasks = Array.isArray(input.tasks) ? input.tasks.length : 0;
|
|
494
|
-
const chain = Array.isArray(input.chain) ? input.chain.length : 0;
|
|
495
|
-
const hasAggregator = input.aggregator !== undefined;
|
|
496
|
-
|
|
497
|
-
if (chain > 0) return { mode: "chain", count: chain };
|
|
498
|
-
if (tasks > 0 && hasAggregator) return { mode: "fan-in", count: tasks };
|
|
499
|
-
if (tasks > 0) return { mode: "parallel", count: tasks };
|
|
500
|
-
return { mode: "single", count: 1 };
|
|
501
|
-
}
|
|
502
|
-
|
|
503
469
|
function findDuplicateExtensions(cwd: string): string[] {
|
|
504
470
|
const settingsFiles = [
|
|
505
471
|
join(process.env.HOME ?? "", ".pi", "agent", "settings.json"),
|