pi-ark-usage 0.1.2 → 0.1.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/README.md CHANGED
@@ -10,7 +10,8 @@ Volc Usage: sess 30%(reset after 4h18m) / wk 37%(reset after 4d) / mo 19%(reset
10
10
 
11
11
  - **AK/SK 直连 OpenAPI**:不走子进程、不依赖 SSO 登录态;凭据只从环境变量或配置文件读取,本扩展不保存、不上传任何 Key
12
12
  - **三个周期同屏**:session(会话)/ weekly(周)/ monthly(月),并显示各周期重置倒计时
13
- - **阈值着色**:低用量绿色、接近上限黄色、超过红线红色
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) 的 `extension_statuses` / customItems 上;百分比按阈值绿/黄/红着色,时间部分紫色,分隔符跟随主题 `thinkingHigh`(编辑器边框色)
14
+ - **阈值着色**:低用量绿色(<50%)、接近上限黄色(50–79%)、超过红线红色(≥80%,默认值,可用 `/arkset` 调整)
14
15
  - **单轮消耗**:以每轮对话开始前的快照为基线,结算时标注各周期增量(如 `(+2)`)
15
16
  - **产品切换感知**:在个人版/团队版、Coding Plan/Agent Plan 之间切换时标注 `(变更)`;套餐周期重置时标注 `(已重置)`
16
17
  - **持久化缓存**:重启 pi 后立即显示上次快照(`~/.pi/agent/pi-ark-usage/cache.json`,0600 权限,临时文件原子写入)
@@ -26,6 +26,7 @@ import {
26
26
  ArkUsageComponent,
27
27
  AUTO_REFRESH_MAX_MINUTES,
28
28
  LOCALES,
29
+ buildCompactStatus,
29
30
  buildItems,
30
31
  formatRemaining,
31
32
  getSettings,
@@ -48,6 +49,8 @@ import type {
48
49
  } from "./lib/types.js";
49
50
 
50
51
  const WIDGET_KEY = "pi-ark-usage";
52
+ /** Extension-status key consumed by pi-powerline-footer (powerline slot). */
53
+ const STATUS_KEY = "ark-usage";
51
54
  const TICK_MS = 60_000;
52
55
  const AGENT_START_TIMEOUT_MS = 3_000;
53
56
  const BASELINE_FRESH_MS = 60 * 60_000;
@@ -128,14 +131,24 @@ function activeSnapshot(): PlanSnapshot | null {
128
131
  function renderWidget(ctx: ExtensionContext): void {
129
132
  lastCtx = ctx;
130
133
  const snap = activeSnapshot();
134
+ const widgetStatus = status === "ok" && !snap ? "none" : status;
131
135
  const items: RenderItem[] = buildItems(
132
136
  snap,
133
137
  language,
134
- status === "ok" && !snap ? "none" : status,
138
+ widgetStatus,
135
139
  ctx.isIdle(),
136
140
  deltas,
137
141
  note,
138
142
  );
143
+ // Publish the one-line summary to the extension-status slot (powerline).
144
+ // The ticker calls renderWidget every minute while idle, keeping the
145
+ // reset countdown fresh without refetching.
146
+ const compact = buildCompactStatus(snap, widgetStatus, ctx.ui.theme);
147
+ if (compact) {
148
+ ctx.ui.setStatus(STATUS_KEY, compact);
149
+ } else {
150
+ ctx.ui.setStatus(STATUS_KEY, undefined);
151
+ }
139
152
  if (activeWidget) {
140
153
  activeWidget.update(items);
141
154
  return;
@@ -122,7 +122,7 @@ export const LOCALES: Record<Language, Locale> = { zh: ZH, en: EN };
122
122
  export const AUTO_REFRESH_MAX_MINUTES = 30;
123
123
 
124
124
  export const DEFAULT_SETTINGS: ArkSettings = {
125
- pctYellow: 40,
125
+ pctYellow: 50,
126
126
  pctRed: 80,
127
127
  autoRefreshMinutes: 5,
128
128
  product: "auto",
@@ -209,6 +209,57 @@ export function formatAge(fetchedAt: number, lang: Language): string {
209
209
  return LOCALES[lang].ageMinutesAgo(m);
210
210
  }
211
211
 
212
+ /* ---------------------- compact status (powerline slot) -------------------- */
213
+
214
+ /**
215
+ * Compact reset countdown for the powerline status: `38m`, `4h38m`, `5d4h`.
216
+ * Lower-precision units are dropped to keep the line short and stable.
217
+ */
218
+ export function formatCompactRemaining(ms: number): string {
219
+ if (!Number.isFinite(ms) || ms <= 0) return "";
220
+ const totalMin = Math.floor(ms / 60_000);
221
+ const d = Math.floor(totalMin / 1440);
222
+ const h = Math.floor((totalMin % 1440) / 60);
223
+ const m = totalMin % 60;
224
+ if (d > 0) return `${d}d${h}h`;
225
+ if (h > 0) return `${h}h${m}m`;
226
+ return `${m}m`;
227
+ }
228
+
229
+ /**
230
+ * One-line colored summary for the powerline extension-status slot:
231
+ * `1% 4h38m | 15% 5d4h | 54% 23d4h`
232
+ *
233
+ * Periods are shown in API order (session / weekly / monthly) without
234
+ * labels — the order itself is the convention. Percent follows the
235
+ * yellow/red thresholds (green below yellow, yellow below red, red at/above
236
+ * red); the time part is always purple; the ` | ` separator uses the
237
+ * editor border color (`thinkingHigh`, pink in the dark theme).
238
+ *
239
+ * Returns null when nothing should be shown (the powerline item hides).
240
+ */
241
+ export function buildCompactStatus(
242
+ snapshot: PlanSnapshot | null,
243
+ status: WidgetStatus,
244
+ theme: Theme,
245
+ ): string | null {
246
+ if (snapshot && snapshot.periods.length > 0) {
247
+ const sep = theme.fg("thinkingHigh", " | ");
248
+ return snapshot.periods
249
+ .map((p) => {
250
+ const pct = coloredPct(clampPct(p.percent));
251
+ const reset = p.reset_at
252
+ ? formatCompactRemaining(new Date(p.reset_at).getTime() - Date.now())
253
+ : "";
254
+ return reset ? `${pct} ${hexFg(HEX_COLORS.purple, reset)}` : pct;
255
+ })
256
+ .join(sep);
257
+ }
258
+ if (status === "fetching") return hexFg(HEX_COLORS.purple, "…");
259
+ if (status === "failed") return hexFg(HEX_COLORS.red, "failed");
260
+ return null;
261
+ }
262
+
212
263
  /* ----------------------------- snapshot -> items --------------------------- */
213
264
 
214
265
  export type WidgetStatus = "ok" | "fetching" | "failed" | "no-binary" | "none";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ark-usage",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Show Volcengine Ark Coding Plan / Agent Plan usage in the pi TUI (AK/SK OpenAPI)",
5
5
  "keywords": [
6
6
  "pi",