@lokiyou/pi-nano-footer 0.15.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +25 -31
  2. package/index.ts +53 -36
  3. package/package.json +37 -37
package/README.md CHANGED
@@ -1,45 +1,39 @@
1
1
  # @lokiyou/pi-nano-footer
2
2
 
3
- 超轻量 powerline 风格 footer for **Pi Coding Agent**,霓虹配色方案。
3
+ Lightweight powerline-style footer for Pi Coding Agent.
4
4
 
5
- 精确复刻 pi-powerline-footer default 预设的样式 + 自定义霓虹色配色。
5
+ This extension replaces the default footer with a compact single-line status bar while keeping Pi's built-in `Working...` indicator. It is designed to stay small and focused.
6
6
 
7
- ## 安装
7
+ ## Installation
8
8
 
9
9
  ```bash
10
10
  pi install npm:@lokiyou/pi-nano-footer
11
+ /reload
11
12
  ```
12
13
 
13
- 或手动放入 `~/.pi/agent/extensions/` `/reload`。
14
+ ## What it shows
14
15
 
15
- ## 效果
16
+ From left to right, the footer shows:
16
17
 
17
- ```
18
-  deepseek-v4-flash think:high   project   45.2%/128K    1.2k   0.03
19
- ```
18
+ - current model
19
+ - thinking level
20
+ - current directory name
21
+ - MCP status summary when MCP status is available
22
+ - context usage
23
+ - token totals
24
+ - estimated cost
25
+
26
+ ## Behavior
27
+
28
+ - Uses a compact powerline-style separator layout.
29
+ - Keeps Pi's built-in `Working...` indicator instead of replacing it.
30
+ - Reads MCP status from extension status data when an MCP adapter exposes it.
31
+ - Focuses only on the footer and does not replace the editor component.
32
+
33
+ ## Notes
34
+
35
+ No additional configuration is required.
20
36
 
21
- 从左到右依次展示:
22
- - 🤖 **模型名**(热粉色)
23
- - 💭 **思考等级**(按等级变色,high/xhigh 彩虹)
24
- - 📁 **目录名**(青蓝色)
25
- - 📊 **上下文用量**(紫 → 黄 >70% → 红 >90%)
26
- - 💾 **Token 用量**(荧光绿)
27
- - 💰 **费用**(明黄色)
28
-
29
- ## 配色
30
-
31
- | 令牌 | 色值 | 用途 |
32
- |------|------|------|
33
- | 模型 | `#ff3cac` | 热粉 |
34
- | 路径 | `#00d4ff` | 青蓝 |
35
- | thinking | `#ff6b6b` | 珊瑚红 |
36
- | thinking high/xhigh | rainbow | 彩虹渐变 |
37
- | 上下文正常 | `#6c5ce7` | 紫色 |
38
- | 上下文 >70% | `#fdcb6e` | 黄色警告 |
39
- | 上下文 >90% | `#ff3366` | 红色错误 |
40
- | 费用 | `#fdcb6e` | 明黄 |
41
- | tokens | `#00ff87` | 荧光绿 |
42
-
43
- ## 许可
37
+ ## License
44
38
 
45
39
  MIT
package/index.ts CHANGED
@@ -11,13 +11,14 @@ import { truncateToWidth } from "@earendil-works/pi-tui";
11
11
 
12
12
  // ── Nerd Font 图标(与 pi-powerline-footer 完全一致) ──
13
13
  const icons = {
14
- model: "\uec19", // nf-md-chip
15
- folder: "\uf115", // nf-fa-folder_open
16
- context: "\ue70f", // nf-dev-database
17
- cache: "\uf1c0", // nf-fa-database
18
- input: "\uf090", // nf-fa-sign_in
19
- cost: "\uf155", // nf-fa-dollar
20
- sep: "\ue0b1", // powerline-thin
14
+ model: "\uec19", // nf-md-chip
15
+ mcp: "\u{f048d}", // nf-md-server-network
16
+ folder: "\uf115", // nf-fa-folder_open
17
+ context: "\ue70f", // nf-dev-database
18
+ cache: "\uf1c0", // nf-fa-database
19
+ input: "\uf090", // nf-fa-sign_in
20
+ cost: "\uf155", // nf-fa-dollar
21
+ sep: "\ue0b1", // powerline-thin
21
22
  };
22
23
 
23
24
  // ── 用户自定义霓虹配色 ──
@@ -60,9 +61,7 @@ export default function (pi: ExtensionAPI) {
60
61
 
61
62
  pi.on("session_start", async (_event, ctx) => {
62
63
  thinkingLevel = pi.getThinkingLevel();
63
-
64
- // 隐藏内置的 "Working..." 指示器,用输入框呼吸代替
65
- ctx.ui.setWorkingVisible(false);
64
+ ctx.ui.setWorkingVisible(true);
66
65
 
67
66
  ctx.ui.setFooter((tui, theme, footerData) => {
68
67
  requestRender = () => tui.requestRender();
@@ -89,14 +88,18 @@ export default function (pi: ExtensionAPI) {
89
88
  const dir = ctx.cwd.replace(/\\/g, "/").split("/").filter(Boolean).pop() || ctx.cwd;
90
89
  parts.push(ansi(C.path, `${icons.folder} ${dir}`));
91
90
 
92
- // 4. 上下文用量 —— #6c5ce7 紫 / #fdcb6e 黄 / #ff3366 红
91
+ // 4. MCP 摘要 —— 紧凑图标版
92
+ const mcp = renderMcpN(footerData);
93
+ if (mcp) parts.push(mcp);
94
+
95
+ // 5. 上下文用量 —— #6c5ce7 紫 / #fdcb6e 黄 / #ff3366 红
93
96
  parts.push(renderContextN(ctx));
94
97
 
95
- // 5. Token 用量 —— #00ff87 荧光绿
98
+ // 6. Token 用量 —— #00ff87 荧光绿
96
99
  const { input, cost } = calcTotals(ctx);
97
100
  parts.push(ansi(C.tokens, `${icons.cache} ${icons.input} ${fmt(input)}`));
98
101
 
99
- // 6. 费用 —— #fdcb6e 明黄色
102
+ // 7. 费用 —— #fdcb6e 明黄色
100
103
  parts.push(ansi(C.cost, `${icons.cost} ${cost.toFixed(2)}`));
101
104
 
102
105
  return [truncateToWidth(parts.join(S), width, "")];
@@ -112,35 +115,12 @@ export default function (pi: ExtensionAPI) {
112
115
  refresh();
113
116
  });
114
117
  pi.on("model_select", () => refresh());
115
-
116
- // 工作状态切换 → 控制呼吸发光
117
- pi.on("agent_start", () => {
118
- working = true;
119
- // 50ms 间隔主动刷新,保证呼吸动画 20fps 流畅
120
- if (requestRender) {
121
- animInterval = setInterval(requestRender, 50);
122
- }
123
- refresh();
124
- });
125
- pi.on("agent_end", () => {
126
- working = false;
127
- if (animInterval) {
128
- clearInterval(animInterval);
129
- animInterval = undefined;
130
- }
131
- refresh();
132
- });
133
-
134
118
  pi.on("turn_start", () => refresh());
135
119
  pi.on("turn_end", () => refresh());
136
120
 
137
121
  pi.on("session_shutdown", (_event, ctx) => {
138
122
  ctx.ui.setFooter(undefined);
139
123
  requestRender = undefined;
140
- if (animInterval) {
141
- clearInterval(animInterval);
142
- animInterval = undefined;
143
- }
144
124
  });
145
125
  }
146
126
 
@@ -193,6 +173,43 @@ function renderContextN(ctx: any): string {
193
173
  return ansi(color, `${icons.context} ${pct?.toFixed(1) ?? "?"}%${maxStr}`);
194
174
  }
195
175
 
176
+ /** 渲染 MCP 状态摘要,优先显示已连接/总数 */
177
+ function renderMcpN(footerData: any): string | null {
178
+ const statuses = footerData?.getExtensionStatuses?.();
179
+ if (!statuses || typeof statuses.get !== "function") return null;
180
+
181
+ const raw = typeof statuses.get("mcp") === "string"
182
+ ? statuses.get("mcp")
183
+ : Array.from(statuses.values()).find((value: unknown) => typeof value === "string" && value.includes("MCP:"));
184
+ if (typeof raw !== "string") return null;
185
+
186
+ const status = raw.replace(/\x1b\[[0-9;]*m/g, "").replace(/\s+/g, " ").trim();
187
+
188
+ const ratio = /MCP:\s*(\d+)\s*\/\s*(\d+)\s+servers?/i.exec(status);
189
+ if (ratio) {
190
+ const connected = Number(ratio[1]);
191
+ const total = Number(ratio[2]);
192
+ const color = connected >= total ? C.tokens : C.thinkingMedium;
193
+ return ansi(color, `${icons.mcp} ${connected}/${total}`);
194
+ }
195
+
196
+ const connected = /MCP:\s*(\d+)\s+servers connected(?:\s*\((\d+)\s+tools\))?/i.exec(status);
197
+ if (connected) {
198
+ return ansi(C.tokens, `${icons.mcp} ${connected[1]}`);
199
+ }
200
+
201
+ const connecting = /MCP:\s*connecting to\s+(\d+)\s+servers?/i.exec(status);
202
+ if (connecting) {
203
+ return ansi(C.thinkingMedium, `${icons.mcp} …/${connecting[1]}`);
204
+ }
205
+
206
+ if (/failed|error|needs-auth|oauth/i.test(status)) {
207
+ return ansi(C.contextError, `${icons.mcp} !`);
208
+ }
209
+
210
+ return ansi(C.context, `${icons.mcp} ?`);
211
+ }
212
+
196
213
  /** 遍历会话分支,累计 input token 数和总费用 */
197
214
  function calcTotals(ctx: any): { input: number; cost: number } {
198
215
  let input = 0, cost = 0;
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
- {
2
- "name": "@lokiyou/pi-nano-footer",
3
- "version": "0.15.0",
4
- "description": "超轻量 powerline 风格 footer for Pi Coding Agent,保留内置 Working... 指示器,霓虹配色,实时显示模型、目录、上下文、token 和费用",
5
- "type": "module",
6
- "keywords": [
7
- "pi-package",
8
- "pi-extension",
9
- "footer",
10
- "statusline",
11
- "powerline",
12
- "neon"
13
- ],
14
- "author": "lokiyou",
15
- "license": "MIT",
16
- "files": [
17
- "index.ts",
18
- "README.md"
19
- ],
20
- "pi": {
21
- "extensions": [
22
- "./index.ts"
23
- ]
24
- },
25
- "peerDependencies": {
26
- "@earendil-works/pi-coding-agent": "*",
27
- "@earendil-works/pi-tui": "*",
28
- "@earendil-works/pi-ai": "*"
29
- },
30
- "repository": {
31
- "type": "git",
32
- "url": ""
33
- },
34
- "publishConfig": {
35
- "access": "public"
36
- }
37
- }
1
+ {
2
+ "name": "@lokiyou/pi-nano-footer",
3
+ "version": "0.15.2",
4
+ "description": "Lightweight powerline-style footer for Pi Coding Agent that shows model, thinking level, directory, MCP status, context usage, tokens, and cost while keeping the built-in Working indicator.",
5
+ "type": "module",
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi-extension",
9
+ "footer",
10
+ "statusline",
11
+ "powerline",
12
+ "neon"
13
+ ],
14
+ "author": "lokiyou",
15
+ "license": "MIT",
16
+ "files": [
17
+ "index.ts",
18
+ "README.md"
19
+ ],
20
+ "pi": {
21
+ "extensions": [
22
+ "./index.ts"
23
+ ]
24
+ },
25
+ "peerDependencies": {
26
+ "@earendil-works/pi-coding-agent": "*",
27
+ "@earendil-works/pi-tui": "*",
28
+ "@earendil-works/pi-ai": "*"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": ""
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }