pi-ark-usage 0.1.4 → 0.1.5
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 +4 -3
- package/extensions/index.ts +3 -1
- package/extensions/lib/widget.ts +27 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
在 pi TUI 中显示**火山引擎方舟 Coding Plan / Agent Plan** 的套餐用量,数据直接来自火山方舟 OpenAPI `GetCodingPlanUsage`(AK/SK 签名,官方 [`@volcengine/openapi`](https://github.com/volcengine/volc-sdk-nodejs) SDK 的 Signer)。
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
|
|
6
|
+
1% 4h38m | 15% 5d4h | 54% 23d4h | 3m ago
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
## 特性
|
|
10
10
|
|
|
11
11
|
- **AK/SK 直连 OpenAPI**:不走子进程、不依赖 SSO 登录态;凭据只从环境变量或配置文件读取,本扩展不保存、不上传任何 Key
|
|
12
12
|
- **三个周期同屏**:session(会话)/ weekly(周)/ monthly(月),并显示各周期重置倒计时
|
|
13
|
-
- **Powerline 状态段(唯一展示位)**:通过 `ctx.ui.setStatus("ark-usage", …)` 发布单行摘要(`1% 4h38m | 15% 5d4h | 54% 23d4h`,固定按 session/weekly/monthly 顺序),显示在 [pi-powerline-footer](https://www.npmjs.com/package/pi-powerline-footer) 上;百分比按阈值绿/黄/红着色,时间部分紫色,分隔符跟随主题 `thinkingHigh
|
|
13
|
+
- **Powerline 状态段(唯一展示位)**:通过 `ctx.ui.setStatus("ark-usage", …)` 发布单行摘要(`1% 4h38m | 15% 5d4h | 54% 23d4h | 3m ago`,固定按 session/weekly/monthly 顺序),显示在 [pi-powerline-footer](https://www.npmjs.com/package/pi-powerline-footer) 上;百分比按阈值绿/黄/红着色,时间部分紫色,分隔符跟随主题 `thinkingHigh`(编辑器边框色),末尾的「上次刷新」用 `dim` 渲染以示区隔。不安装 powerline 时也可通过内置 footer 的 extension statuses 区域或 `/arkusage` 查看
|
|
14
|
+
- **上次刷新时间**:状态段末尾显示距今多久前**成功**刷新过(分钟精度:`just now` / `3m ago` / `4h38m ago` / `5d4h ago`)。抓取失败时沿用上一次成功的时间,因此该值持续变大即表示刷新已经失败或长时间未刷新
|
|
14
15
|
- **阈值着色**:低用量绿色(<50%)、接近上限黄色(50–79%)、超过红线红色(≥80%,默认值,可用 `/arkset` 调整)
|
|
15
16
|
- **持久化缓存**:重启 pi 后立即显示上次快照(`~/.pi/agent/pi-ark-usage/cache.json`,0600 权限,临时文件原子写入)
|
|
16
17
|
- 可选空闲自动刷新(默认关闭)
|
|
@@ -97,7 +98,7 @@ pi install npm:pi-ark-usage
|
|
|
97
98
|
1. 用官方 `@volcengine/openapi` 的 `Signer` 对 `POST open.volcengineapi.com?Action=GetCodingPlanUsage&Version=2024-01-01`(service `ark`,region `cn-beijing`)做 V4 签名后 fetch。
|
|
98
99
|
2. 解析 `Result.QuotaUsage[]`(`Level/Percent/ResetTimestamp`,秒级时间戳转 `+08:00` ISO 字符串),做结构与取值校验。
|
|
99
100
|
3. 快照存入内存 Map,并以原子写(tmp 文件 + rename)持久化到 `~/.pi/agent/pi-ark-usage/`。
|
|
100
|
-
4. 摘要通过 `ctx.ui.setStatus("ark-usage", …)` 发布到 extension status,由 pi-powerline-footer 渲染到 powerline 行;每分钟 ticker
|
|
101
|
+
4. 摘要通过 `ctx.ui.setStatus("ark-usage", …)` 发布到 extension status,由 pi-powerline-footer 渲染到 powerline 行;每分钟 ticker 在空闲时重发,保持重置倒计时与「上次刷新」时长显示为最新。
|
|
101
102
|
|
|
102
103
|
## 开发
|
|
103
104
|
|
package/extensions/index.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* the official `@volcengine/openapi` Signer. This extension never stores keys:
|
|
7
7
|
* credentials come from VOLC_ACCESSKEY/VOLC_SECRETKEY or ~/.volc/config.
|
|
8
8
|
*
|
|
9
|
-
* Powerline status (via `ctx.ui.setStatus`):
|
|
9
|
+
* Powerline status (via `ctx.ui.setStatus`):
|
|
10
|
+
* 1% 4h38m | 15% 5d4h | 54% 23d4h | 3m ago
|
|
11
|
+
* The trailing segment is how long ago the data was last refreshed.
|
|
10
12
|
* Commands:
|
|
11
13
|
* /arkcheck force refresh
|
|
12
14
|
* /arkusage show snapshot in a notification
|
package/extensions/lib/widget.ts
CHANGED
|
@@ -202,9 +202,25 @@ export function formatCompactRemaining(ms: number): string {
|
|
|
202
202
|
return `${m}m`;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Age of the last successful refresh, for the trailing status segment:
|
|
207
|
+
* `just now`, `3m ago`, `4h38m ago`, `5d4h ago`. Minute is the finest unit —
|
|
208
|
+
* seconds would only make the line jitter — and a stale cached snapshot thus
|
|
209
|
+
* reads as old at a glance.
|
|
210
|
+
*/
|
|
211
|
+
export function formatRefreshAgo(ts: number, now: number = Date.now()): string {
|
|
212
|
+
if (!Number.isFinite(ts) || ts <= 0) return "";
|
|
213
|
+
const ms = now - ts;
|
|
214
|
+
// Clock skew can make a fresh fetch look negative; treat it as "now".
|
|
215
|
+
if (ms < 60_000) return "just now";
|
|
216
|
+
// Drop a zero lower unit (`1h0m` -> `1h`, `5d0h` -> `5d`).
|
|
217
|
+
const age = formatCompactRemaining(ms).replace(/([dh])0[mh]$/, "$1");
|
|
218
|
+
return `${age} ago`;
|
|
219
|
+
}
|
|
220
|
+
|
|
205
221
|
/**
|
|
206
222
|
* One-line colored summary for the powerline extension-status slot:
|
|
207
|
-
* `1% 4h38m | 15% 5d4h | 54% 23d4h`
|
|
223
|
+
* `1% 4h38m | 15% 5d4h | 54% 23d4h | 3m ago`
|
|
208
224
|
*
|
|
209
225
|
* Periods are shown in API order (session / weekly / monthly) without
|
|
210
226
|
* labels — the order itself is the convention. Percent follows the
|
|
@@ -212,24 +228,32 @@ export function formatCompactRemaining(ms: number): string {
|
|
|
212
228
|
* red); the time part is always purple; the ` | ` separator uses the
|
|
213
229
|
* editor border color (`thinkingHigh`, pink in the dark theme).
|
|
214
230
|
*
|
|
231
|
+
* The last segment is how long ago the data was fetched, in `dim` — it is
|
|
232
|
+
* meta information, not usage, so it stays visually secondary.
|
|
233
|
+
*
|
|
215
234
|
* Returns null when nothing should be shown (the powerline item hides).
|
|
216
235
|
*/
|
|
217
236
|
export function buildCompactStatus(
|
|
218
237
|
snapshot: PlanSnapshot | null,
|
|
219
238
|
status: WidgetStatus,
|
|
220
239
|
theme: Theme,
|
|
240
|
+
now: number = Date.now(),
|
|
221
241
|
): string | null {
|
|
222
242
|
if (snapshot && snapshot.periods.length > 0) {
|
|
223
243
|
const sep = theme.fg("thinkingHigh", " | ");
|
|
224
|
-
|
|
244
|
+
const periods = snapshot.periods
|
|
225
245
|
.map((p) => {
|
|
226
246
|
const pct = coloredPct(clampPct(p.percent));
|
|
227
247
|
const reset = p.reset_at
|
|
228
|
-
? formatCompactRemaining(new Date(p.reset_at).getTime() -
|
|
248
|
+
? formatCompactRemaining(new Date(p.reset_at).getTime() - now)
|
|
229
249
|
: "";
|
|
230
250
|
return reset ? `${pct} ${hexFg(HEX_COLORS.purple, reset)}` : pct;
|
|
231
251
|
})
|
|
232
252
|
.join(sep);
|
|
253
|
+
const refreshed = formatRefreshAgo(snapshot.fetchedAt, now);
|
|
254
|
+
return refreshed
|
|
255
|
+
? `${periods}${sep}${theme.fg("dim", refreshed)}`
|
|
256
|
+
: periods;
|
|
233
257
|
}
|
|
234
258
|
if (status === "fetching") return hexFg(HEX_COLORS.purple, "…");
|
|
235
259
|
if (status === "failed") return hexFg(HEX_COLORS.red, "failed");
|