@fyeeme/pi-statusline 1.2.1 → 1.2.3
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/CHANGELOG.md +16 -0
- package/README.md +3 -3
- package/index.ts +27 -1
- package/package.json +7 -7
- package/pricing/deepseek.ts +17 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.2.3] - 2026-09-09
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Footer subscribes to `ui_prompt_start`/`ui_prompt_end`: the elapsed timer freezes while a blocking dialog (ask_user, permission gates, ...) is open and the footer shows "waiting for user" instead of running time.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Peer/dev dependencies bumped to pi 0.84.4 (the `ui_prompt` events require >= 0.84.4).
|
|
19
|
+
|
|
20
|
+
## [1.2.2] - 2026-08-23
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Follow DeepSeek's weekend flat-rate adjustment (effective 2026-08-23 00:00 Beijing time): weekends (Saturday/Sunday) no longer distinguish peak/off-peak periods and are billed at the off-peak price all day. `isDeepSeekPeakTime()` now returns false for any Beijing-time Saturday/Sunday from the effective date onward; messages before that instant keep the old per-hour rule, so long sessions spanning 2026-08-23 are still priced correctly per message. Footer indicator and registry patch follow automatically.
|
|
25
|
+
|
|
10
26
|
## [1.2.1] - 2026-08-21
|
|
11
27
|
|
|
12
28
|
### Fixed
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ A rich custom status bar for [pi](https://pi.dev) that replaces the default foot
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
10
|
- **Provider-aware usage** — special support for DeepSeek and GLM/ZAI (see [Provider Support](#provider-support))
|
|
11
|
-
- **DeepSeek peak/off-peak pricing** — session cost follows DeepSeek's 2026-08-17 peak/off-peak billing (peak 9:00-12:00 / 14:00-18:00 Beijing time
|
|
11
|
+
- **DeepSeek peak/off-peak pricing** — session cost follows DeepSeek's 2026-08-17 peak/off-peak billing (peak 9:00-12:00 / 14:00-18:00 Beijing time on weekdays; weekends are off-peak all day since 2026-08-23), priced per-message by timestamp, with a live `peak`/`off-peak` indicator in the footer (see [DeepSeek](#deepseek))
|
|
12
12
|
- **Token usage**: input, output, cache read/write, total per session, with cache hit rate
|
|
13
13
|
- **Cost**: cumulative session cost with currency auto-detection (¥ for DeepSeek/CNY, $ otherwise)
|
|
14
14
|
- **Context window**: usage percentage and size
|
|
@@ -25,7 +25,7 @@ Shows live **account balance**, **weekly token usage**, and **peak/off-peak awar
|
|
|
25
25
|
|
|
26
26
|
#### Peak / Off-peak pricing (since 2026-08-17)
|
|
27
27
|
|
|
28
|
-
DeepSeek now bills in two periods — **peak hours are 9:00-12:00 and 14:00-18:00 Beijing time** (UTC+8), all other hours are off-peak, and **off-peak is half the peak price**. Official CNY prices per million tokens:
|
|
28
|
+
DeepSeek now bills in two periods — **peak hours are 9:00-12:00 and 14:00-18:00 Beijing time** (UTC+8) on weekdays, all other hours are off-peak, and **off-peak is half the peak price**. Since **2026-08-23 00:00 Beijing time**, weekends (Saturday/Sunday) no longer distinguish periods and bill at the off-peak price all day. Official CNY prices per million tokens:
|
|
29
29
|
|
|
30
30
|
| Model | Period | Cache-hit input | Cache-miss input | Output |
|
|
31
31
|
|---|---|---|---|---|
|
|
@@ -33,7 +33,7 @@ DeepSeek now bills in two periods — **peak hours are 9:00-12:00 and 14:00-18:0
|
|
|
33
33
|
| deepseek-v4-pro | off-peak / peak | ¥0.15 / ¥0.30 | ¥4.5 / ¥9.0 | ¥13.5 / ¥27.0 |
|
|
34
34
|
|
|
35
35
|
- **Per-message pricing by timestamp** — each message is priced at the rate of its own time (`AssistantMessage.timestamp`), so a long session spanning a period boundary (9:00/12:00/14:00/18:00) accounts every message correctly instead of using a single fixed rate.
|
|
36
|
-
- **Peak/off-peak indicator** — the footer appends the current period so you always know which rate is in effect: `peak` during 9:00-12:00 / 14:00-18:00 Beijing time, `off-peak` otherwise:
|
|
36
|
+
- **Peak/off-peak indicator** — the footer appends the current period so you always know which rate is in effect: `peak` during weekday 9:00-12:00 / 14:00-18:00 Beijing time, `off-peak` otherwise (including all day on weekends since 2026-08-23):
|
|
37
37
|
|
|
38
38
|
```
|
|
39
39
|
¥0.12/50.00 · 7d:1.2M · off-peak
|
package/index.ts
CHANGED
|
@@ -46,6 +46,11 @@ let lastModel: ExtensionContext["model"] = undefined;
|
|
|
46
46
|
let agentRunning = false;
|
|
47
47
|
let lastElapsedSec = 0;
|
|
48
48
|
let lastTps = 0;
|
|
49
|
+
/** True while a blocking ctx.ui dialog (select/confirm/input/editor/custom)
|
|
50
|
+
* span is open (ui_prompt_start → ui_prompt_end). Elapsed time freezes and
|
|
51
|
+
* the footer says "waiting for user" instead of showing a running timer —
|
|
52
|
+
* the doc-intended status-integration use of the ui_prompt events. */
|
|
53
|
+
let waitingForUser = false;
|
|
49
54
|
|
|
50
55
|
const tokenCalculator = new SessionTokenUsageCalculator(() => deepSeekPricing.getCurrencyOverride());
|
|
51
56
|
|
|
@@ -90,6 +95,25 @@ export default function (pi: ExtensionAPI) {
|
|
|
90
95
|
}
|
|
91
96
|
});
|
|
92
97
|
|
|
98
|
+
// ---- Blocking-dialog spans: freeze the elapsed timer + surface the wait ----
|
|
99
|
+
pi.on("ui_prompt_start", () => {
|
|
100
|
+
// Nested/overlapping prompts coalesce into one span (doc), so these are
|
|
101
|
+
// balanced set/reset pairs. Freeze first so user think-time never counts
|
|
102
|
+
// as agent work; resume on the matching end.
|
|
103
|
+
if (agentRunning && agentStartMs !== null) {
|
|
104
|
+
lastElapsedSec += (Date.now() - agentStartMs) / 1000;
|
|
105
|
+
agentStartMs = null;
|
|
106
|
+
}
|
|
107
|
+
waitingForUser = true;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
pi.on("ui_prompt_end", () => {
|
|
111
|
+
if (agentRunning && agentStartMs === null) {
|
|
112
|
+
agentStartMs = Date.now();
|
|
113
|
+
}
|
|
114
|
+
waitingForUser = false;
|
|
115
|
+
});
|
|
116
|
+
|
|
93
117
|
// ---- /status-debug ----
|
|
94
118
|
pi.registerCommand("status-debug", {
|
|
95
119
|
description: "Dump session stats to /tmp/pi-status-debug.log + console.error",
|
|
@@ -237,8 +261,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
237
261
|
}
|
|
238
262
|
|
|
239
263
|
// Line 1: tokens + cost + provider usage + context + elapsed + tps + mcp
|
|
264
|
+
let statLine = dim(buildStatLine(stats, cu, providerResult, providers, getElapsedSec, lastTps));
|
|
265
|
+
if (waitingForUser) statLine += theme.fg("warning", " · waiting for user");
|
|
240
266
|
lines.push(truncateToWidth(
|
|
241
|
-
|
|
267
|
+
statLine,
|
|
242
268
|
width,
|
|
243
269
|
dim("..."),
|
|
244
270
|
));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fyeeme/pi-statusline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "Rich custom status bar for pi with token usage, cost, DeepSeek balance, context window, and timing.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,14 +48,14 @@
|
|
|
48
48
|
"typecheck": "tsc"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@earendil-works/pi-coding-agent": ">=0.84.
|
|
52
|
-
"@earendil-works/pi-ai": ">=0.84.
|
|
53
|
-
"@earendil-works/pi-tui": ">=0.84.
|
|
51
|
+
"@earendil-works/pi-coding-agent": ">=0.84.4",
|
|
52
|
+
"@earendil-works/pi-ai": ">=0.84.4",
|
|
53
|
+
"@earendil-works/pi-tui": ">=0.84.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@earendil-works/pi-coding-agent": "0.84.
|
|
57
|
-
"@earendil-works/pi-ai": "0.84.
|
|
58
|
-
"@earendil-works/pi-tui": "0.84.
|
|
56
|
+
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
57
|
+
"@earendil-works/pi-ai": "0.84.4",
|
|
58
|
+
"@earendil-works/pi-tui": "0.84.4",
|
|
59
59
|
"@types/node": "22.19.19",
|
|
60
60
|
"typescript": "5.9.3"
|
|
61
61
|
}
|
package/pricing/deepseek.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* 因此所有「修正」都必须跟随结算币种与峰谷时段:
|
|
11
11
|
* 1. `billedInCny()`:判定是否按 CNY 计价 —— 用户显式 `/currency` 优先;否则按 balance API
|
|
12
12
|
* 探测到的账户币种(探测失败/未知时按 CNY,保持原有「deepseek → ¥」默认行为)。
|
|
13
|
-
* 2. `isDeepSeekPeakTime()`:按北京时间(UTC+8
|
|
13
|
+
* 2. `isDeepSeekPeakTime()`:按北京时间(UTC+8,无夏令时)判定指定时刻是否高峰时段
|
|
14
|
+
* (2026-08-23 00:00 起周末周六、周日全天不再区分峰谷,统一按低谷价)。
|
|
14
15
|
* 3. `messageCost()`:按消息时刻对应的峰谷单价重算单条消息成本(仅 CNY 计价时接管;USD 计价
|
|
15
16
|
* 返回 null 回退 pi 记录的 cost —— 会话文件里已记录的 cost 无法追溯修正)。
|
|
16
17
|
* 4. `applyPricingPatch()`:运行时把注册表中 deepseek 模型定价覆盖为当前时段的官方 CNY 价
|
|
@@ -51,12 +52,26 @@ export const DEEPSEEK_CNY_PRICES: Record<string, DeepSeekCnyPrice> = {
|
|
|
51
52
|
|
|
52
53
|
const PER_MILLION = 1_000_000;
|
|
53
54
|
|
|
55
|
+
const BJ_OFFSET_MS = 8 * 60 * 60 * 1000;
|
|
56
|
+
|
|
57
|
+
/** 周末全天低谷价生效起点:2026-08-23 00:00 北京时间 = 2026-08-22T16:00Z。 */
|
|
58
|
+
const WEEKEND_OFFPEAK_SINCE_MS = Date.parse("2026-08-22T16:00:00Z");
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* DeepSeek 高峰时段判定:北京时间(UTC+8,无夏令时)9:00-12:00、14:00-18:00 为高峰,
|
|
56
62
|
* 其余为空闲时段(官方定价页备注)。`at` 可指定时刻,默认当前时间。
|
|
63
|
+
*
|
|
64
|
+
* 2026-08-23(周日)00:00 北京时间起,官方调整:周末(周六、周日)全天不再区分峰谷,
|
|
65
|
+
* 统一按低谷价收取 —— 即生效后的周六/周日任何时刻均判为空闲时段。生效前(如 2026-08-22
|
|
66
|
+
* 周六)的历史消息仍按旧规则计价,保证跨生效日的长会话逐条重算正确。
|
|
57
67
|
*/
|
|
58
68
|
export function isDeepSeekPeakTime(at: Date = new Date()): boolean {
|
|
59
|
-
const
|
|
69
|
+
const beijing = new Date(at.getTime() + BJ_OFFSET_MS);
|
|
70
|
+
if (at.getTime() >= WEEKEND_OFFPEAK_SINCE_MS) {
|
|
71
|
+
const bjDay = beijing.getUTCDay(); // 0=周日 6=周六(按北京日期,非 UTC 日期)
|
|
72
|
+
if (bjDay === 0 || bjDay === 6) return false;
|
|
73
|
+
}
|
|
74
|
+
const beijingHour = beijing.getUTCHours();
|
|
60
75
|
return (beijingHour >= 9 && beijingHour < 12) || (beijingHour >= 14 && beijingHour < 18);
|
|
61
76
|
}
|
|
62
77
|
|