@d3ara1n/pi-editor-shell 0.5.0 → 0.7.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 +25 -12
- package/package.json +1 -1
- package/src/config.ts +17 -0
- package/src/index.ts +20 -5
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@ Replaces pi's default editor and status bar with a unified rounded-corner shell
|
|
|
4
4
|
|
|
5
5
|
## What shows up where
|
|
6
6
|
|
|
7
|
-
- **Top border** — `
|
|
8
|
-
- **Bottom border** — ` ctx NN%/
|
|
7
|
+
- **Top border** — ` model · thinking-level ` (left) + pinned extension statuses (right, via `pinnedStatus` config)
|
|
8
|
+
- **Bottom border** — ` ctx NN%/NNk|N.NM · ⚡ cacheRead (total) hitRate% ` (left) + ` ~/Projects (main +2 ~1) ` (right, shows git branch + dirty state when in a repo)
|
|
9
9
|
- **Below shell** — Auto-wrapping extension status line (all `setStatus` entries not pinned to the top)
|
|
10
10
|
- **Border color** follows pi's thinking-level / bash-mode indicator automatically.
|
|
11
11
|
|
|
@@ -15,19 +15,13 @@ All segments are re-read from live session state on every paint, so switching th
|
|
|
15
15
|
|
|
16
16
|
In `~/.pi/agent/settings.json` under the `editorShell` key:
|
|
17
17
|
|
|
18
|
-
```
|
|
18
|
+
```json
|
|
19
19
|
{
|
|
20
20
|
"editorShell": {
|
|
21
|
-
// Status keys to pin to the top-right corner of the shell.
|
|
22
|
-
// Only keys set via ctx.ui.setStatus() are eligible.
|
|
23
21
|
"pinnedStatus": ["subagent", "access-denied"],
|
|
24
|
-
|
|
25
|
-
// Per-slot border-icon overrides. Any subset; missing keys fall back
|
|
26
|
-
// to the built-in Nerd Font set (see table below). Values are raw
|
|
27
|
-
// characters — "\uf0e7" for a Nerd Font glyph, "🤖" for an emoji.
|
|
28
22
|
"icons": {
|
|
29
|
-
"model": "
|
|
30
|
-
"cache": "
|
|
23
|
+
"model": "robot",
|
|
24
|
+
"cache": "\\uf0e7"
|
|
31
25
|
}
|
|
32
26
|
}
|
|
33
27
|
}
|
|
@@ -44,6 +38,25 @@ In `~/.pi/agent/settings.json` under the `editorShell` key:
|
|
|
44
38
|
| `hitRate` | `` | fa-bullseye |
|
|
45
39
|
| `folder` | `` | fa-folder_open |
|
|
46
40
|
|
|
41
|
+
### Model display
|
|
42
|
+
|
|
43
|
+
How the model is labeled in the top-left border (`"name"` by default):
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"editorShell": {
|
|
48
|
+
"modelDisplay": "name"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Value | Example |
|
|
54
|
+
|-------|---------|
|
|
55
|
+
| `"name"` (default) | `Claude Opus 4.8 (Yanproxy)` |
|
|
56
|
+
| `"provider-id"` | `yanproxy/anthropic/claude-opus-4-8` |
|
|
57
|
+
|
|
58
|
+
`"name"` uses `model.name`; a model with no name falls back to its id, so the slot never goes blank.
|
|
59
|
+
|
|
47
60
|
## Commands
|
|
48
61
|
|
|
49
62
|
| Command | Description |
|
|
@@ -64,7 +77,7 @@ pi install npm:@d3ara1n/pi-editor-shell
|
|
|
64
77
|
|
|
65
78
|
Or add to `~/.pi/agent/settings.json`:
|
|
66
79
|
|
|
67
|
-
```
|
|
80
|
+
```json
|
|
68
81
|
{
|
|
69
82
|
"extensions": [
|
|
70
83
|
"/absolute/path/to/pi-extensions/packages/pi-editor-shell"
|
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -22,6 +22,9 @@ export interface EditorShellIcons {
|
|
|
22
22
|
folder: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** How the model is shown in the top-left border slot. */
|
|
26
|
+
export type ModelDisplay = "name" | "provider-id";
|
|
27
|
+
|
|
25
28
|
export interface EditorShellConfig {
|
|
26
29
|
/**
|
|
27
30
|
* Status keys to pin to the shell's top-right corner.
|
|
@@ -34,6 +37,13 @@ export interface EditorShellConfig {
|
|
|
34
37
|
* for a Nerd Font glyph, or `"🤖"` for an emoji, etc.
|
|
35
38
|
*/
|
|
36
39
|
icons: Partial<EditorShellIcons>;
|
|
40
|
+
/**
|
|
41
|
+
* What to show as the model label in the top-left border.
|
|
42
|
+
* - `"name"` — `model.name` (friendlier; falls back to the id when a model
|
|
43
|
+
* has no name, so it never goes blank).
|
|
44
|
+
* - `"provider-id"` — `provider/id`.
|
|
45
|
+
*/
|
|
46
|
+
modelDisplay: ModelDisplay;
|
|
37
47
|
}
|
|
38
48
|
|
|
39
49
|
const ICON_KEYS: ReadonlyArray<keyof EditorShellIcons> = [
|
|
@@ -59,6 +69,7 @@ function filterIcons(obj: Record<string, unknown>): Partial<EditorShellIcons> {
|
|
|
59
69
|
export const DEFAULT_CONFIG: EditorShellConfig = {
|
|
60
70
|
pinnedStatus: [],
|
|
61
71
|
icons: {},
|
|
72
|
+
modelDisplay: "name",
|
|
62
73
|
};
|
|
63
74
|
|
|
64
75
|
function getAgentDir(): string {
|
|
@@ -91,6 +102,11 @@ export function loadEditorShellConfig(cwd?: string): EditorShellConfig {
|
|
|
91
102
|
|
|
92
103
|
const pinned = raw.pinnedStatus;
|
|
93
104
|
const iconsRaw = raw.icons;
|
|
105
|
+
const modelDisplayRaw = raw.modelDisplay;
|
|
106
|
+
const modelDisplay =
|
|
107
|
+
modelDisplayRaw === "name" || modelDisplayRaw === "provider-id"
|
|
108
|
+
? modelDisplayRaw
|
|
109
|
+
: DEFAULT_CONFIG.modelDisplay;
|
|
94
110
|
return {
|
|
95
111
|
pinnedStatus: Array.isArray(pinned)
|
|
96
112
|
? pinned.filter((k): k is string => typeof k === "string")
|
|
@@ -99,5 +115,6 @@ export function loadEditorShellConfig(cwd?: string): EditorShellConfig {
|
|
|
99
115
|
iconsRaw && typeof iconsRaw === "object"
|
|
100
116
|
? filterIcons(iconsRaw as Record<string, unknown>)
|
|
101
117
|
: {},
|
|
118
|
+
modelDisplay,
|
|
102
119
|
};
|
|
103
120
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn } from "node:child_process";
|
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
6
|
import { CardEditor, type FrameProvider, type SpinnerPhase } from "./card-editor";
|
|
7
|
-
import { loadEditorShellConfig, type EditorShellConfig, type EditorShellIcons } from "./config";
|
|
7
|
+
import { DEFAULT_CONFIG, loadEditorShellConfig, type EditorShellConfig, type EditorShellIcons } from "./config";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* pi-editor-shell — Replaces pi's default editor and status bar with a
|
|
@@ -47,6 +47,16 @@ function contextToken(pct: number | null | undefined): ThemeColor {
|
|
|
47
47
|
return "success";
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function trimFixed1(n: number): string {
|
|
51
|
+
const text = n.toFixed(1);
|
|
52
|
+
return text.endsWith(".0") ? text.slice(0, -2) : text;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function formatContextWindow(tokens: number): string {
|
|
56
|
+
if (tokens >= 1_000_000) return `${trimFixed1(tokens / 1_000_000)}M`;
|
|
57
|
+
return `${(tokens / 1_000).toFixed(0)}k`;
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
// ── Built-in icon set (Nerd Font). Users can override any subset via the
|
|
51
61
|
// `editorShell.icons` config — see config.ts. `cache` uses U+26A1, which
|
|
52
62
|
// Nerd Fonts maps `oct-zap` to directly (no dedicated glyph), so it is
|
|
@@ -195,7 +205,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
195
205
|
// The factory may run again when pi rebuilds the editor (model switch,
|
|
196
206
|
// reload, …), so always drive whichever instance is current.
|
|
197
207
|
let editor: CardEditor | undefined;
|
|
198
|
-
let config: EditorShellConfig = {
|
|
208
|
+
let config: EditorShellConfig = { ...DEFAULT_CONFIG };
|
|
199
209
|
// Resolved icons for the current session: built-in defaults merged with
|
|
200
210
|
// the user's overrides. Re-computed at session_start.
|
|
201
211
|
let icons: EditorShellIcons = { ...DEFAULT_ICONS };
|
|
@@ -271,7 +281,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
271
281
|
return ` ${texts.map((s) => theme.fg("muted", s)).join(theme.fg("dim", " · "))} `;
|
|
272
282
|
};
|
|
273
283
|
|
|
274
|
-
const model = ctx.model
|
|
284
|
+
const model = ctx.model
|
|
285
|
+
? config.modelDisplay === "name"
|
|
286
|
+
? ctx.model.name
|
|
287
|
+
: `${ctx.model.provider}/${ctx.model.id}`
|
|
288
|
+
: "no model";
|
|
275
289
|
const thinking = pi.getThinkingLevel();
|
|
276
290
|
const thinkingColor = THINKING_TOKEN[thinking] ?? "muted";
|
|
277
291
|
|
|
@@ -280,8 +294,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
280
294
|
const ctxWindow = usage?.contextWindow ?? ctx.model?.contextWindow;
|
|
281
295
|
const ctxText =
|
|
282
296
|
pct != null && ctxWindow
|
|
283
|
-
? `${pct.toFixed(1)}%/${(ctxWindow
|
|
284
|
-
: "?/??
|
|
297
|
+
? `${pct.toFixed(1)}%/${formatContextWindow(ctxWindow)}`
|
|
298
|
+
: "?/??";
|
|
285
299
|
|
|
286
300
|
// Cache-read tokens — per-turn figure first, session total in parens,
|
|
287
301
|
// then hit rate (pi's "CHxx%" formula). All refreshed at agent_end and
|
|
@@ -368,6 +382,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
368
382
|
|
|
369
383
|
lines.push("[editor-shell config]");
|
|
370
384
|
lines.push(` pinnedStatus: [${config.pinnedStatus.join(", ")}]`);
|
|
385
|
+
lines.push(` modelDisplay: ${config.modelDisplay}`);
|
|
371
386
|
|
|
372
387
|
lines.push("");
|
|
373
388
|
lines.push("[extension statuses]");
|