From dc0a5912f20437508ade0821e17c797636845b5f Mon Sep 17 00:00:00 2001 From: RECTOR Date: Wed, 9 Sep 2026 21:00:01 +0700 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20info=20line=20renders=20Gregorian?= =?UTF-8?q?=20date=20beside=20Hijri=20=E2=80=94=2027=20Rab=C4=AB=CA=BF=20a?= =?UTF-8?q?l-awwal=201448=20(09=20Sep=202026)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- assets/hero.svg | 2 +- src/format.ts | 8 ++++++++ src/index.ts | 8 ++++---- test/lines.test.ts | 13 ++++++++++--- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index fa38f06..6127cbf 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![node](https://img.shields.io/badge/node-%E2%89%A5%2020-339933?style=flat-square)](./package.json) [![MIT](https://img.shields.io/badge/license-MIT-007ec6?style=flat-square)](./LICENSE) -omp-statusline rendering four lines beneath the editor in a terminal: clock, Hijri date and city; the five prayer times with a green countdown on the next prayer; API spend and token volume per window; and z.ai quota pace per window with over/under indicators. +omp-statusline rendering four lines beneath the editor in a terminal: clock, Hijri date with Gregorian gloss and city; the five prayer times with a green countdown on the next prayer; API spend and token volume per window; and z.ai quota pace per window with over/under indicators. A statusline widget for [omp](https://github.com/can1357/oh-my-pi) (Oh My Pi) — the omp-native successor to [pi-statusline](https://github.com/getpipher/pi-statusline). It renders below the editor in omp's own visual language (` · ` separators, nerd glyphs, theme tokens), and omp's native statusline closes the block beneath it (extension widgets cannot render under it yet — tracked upstream as [can1357/oh-my-pi#11100](https://github.com/can1357/oh-my-pi/issues/11100)). @@ -18,7 +18,7 @@ Render order (top → bottom): **info · prayers · money · zai**. | Line | Contents | |---|---| -| **info** | Local clock · Hijri date · city — all dim. | +| **info** | Local clock · Hijri date with Gregorian gloss — `27 Rabīʿ al-awwal 1448 (09 Sep 2026)` · city — all dim. | | **prayers** | All five prayers with wall times, from [aladhan](https://api.aladhan.com) (cached per local day, stale-marker on degradation). Past prayers get a dim `✓`; the next prayer is green with a countdown on its segment only — `Dhuhr 11:51 (3h 36m)`. | | **money** | API spend + token volume per window: `REPO $68.36 (1.3B)` (all-time for the current project) · `DAY` (since 00:00 local) · `7DAY` / `30DAY` (rolling, hour-aligned). Token volumes are dim, from the same sessions scan. | | **zai** | Quota pace per window: `LABEL usage%/elapsed% (pace · reset · absolute)` — e.g. `5hrs 16%/26% (30m under · 3h 43m · 11:58)`. **Provider-gated**: renders only while the active model's provider is `zai` (or the provider is unreadable); vanishes entirely on other providers. | @@ -79,7 +79,7 @@ State (deen cache) lives beside the config in `~/.omp/agent/omp-statusline/`. Forces a zai + deen + money refresh and notifies full source state: quota freshness, today's plan credits, 7-day per-model split, usage streaks, cache-hit rate, prayer city/hijri, and the spend breakdown including subagent share and entry count: ``` -zai key omp credentials · 5h 16% · weekly 24% · fetched 0m ago · today 7.7K · models 7d glm-5.3 28K · gpt-5.4 9.2K · streak 46d (best 61d) · cache 71% | deen Jakarta · 25 Rabīʿ al-awwal 1448 · fresh | money REPO $68.36 · DAY $26.50 · 7DAY $315.27 · 30DAY $492.88 · sub $11.02 · 1234 entries +zai key omp credentials · 5h 16% · weekly 24% · fetched 0m ago · today 7.7K · models 7d glm-5.3 28K · gpt-5.4 9.2K · streak 46d (best 61d) · cache 71% | deen Jakarta · 25 Rabīʿ al-awwal 1448 (07 Sep 2026) · fresh | money REPO $68.36 · DAY $26.50 · 7DAY $315.27 · 30DAY $492.88 · sub $11.02 · 1234 entries ``` The z.ai dashboard endpoints (`credit-usage/usage-detail`, `credit-usage/activity`) accept the same API key as the quota API — no browser or cookie session needed. diff --git a/assets/hero.svg b/assets/hero.svg index 976f026..71b687a 100644 --- a/assets/hero.svg +++ b/assets/hero.svg @@ -27,7 +27,7 @@ // v0.3.0 (RECTOR order): info first, prayers, money, zai - 08:15 · 25 Rabīʿ al-awwal 1448 · Jakarta + 08:15 · 25 Rabīʿ al-awwal 1448 (07 Sep 2026) · Jakarta Fajr 04:33 ✓ · Dhuhr 11:51 (3h 36m) · Asr 15:07 · Maghrib 17:52 · Isha 19:01 diff --git a/src/format.ts b/src/format.ts index 236c564..a83e681 100644 --- a/src/format.ts +++ b/src/format.ts @@ -60,3 +60,11 @@ export function formatResetAbs(targetMs: number, now: number): string { t.getDate() === n.getDate(); return sameDay ? formatClock(targetMs) : `${MONTHS[t.getMonth()]} ${String(t.getDate()).padStart(2, "0")} ${formatClock(targetMs)}`; } + +// v0.5.1: Gregorian gloss beside the Hijri date in infoLine — `09 Sep 2026`. +// Machine-local like the clock; reuses MONTHS for deterministic EN rendering +// (no Intl/platform variance). +export function formatGregorian(ts: number): string { + const d = new Date(ts); + return `${String(d.getDate()).padStart(2, "0")} ${MONTHS[d.getMonth()]} ${d.getFullYear()}`; +} diff --git a/src/index.ts b/src/index.ts index 4437a5f..1e4c879 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ // omp-statusline — 4-line belowEditor widget, RECTOR-approved 2026-09-07: // 󰚯 zai 5hrs 16%/26% (30m under · 3h 43m · 11:58) · 7DAY 33%/31% (3h 22m over · 4d 19h · Sep 12 03:30) ← provider-gated (zai only) // 󰣎 Fajr 04:33 ✓ · Dhuhr 11:51 (3h 36m) · Asr 15:07 · Maghrib 17:52 · Isha 19:01 -// 󰥔 08:15 · 25 Rabīʿ al-awwal 1448 · Jakarta +// 󰥔 08:15 · 25 Rabīʿ al-awwal 1448 (07 Sep 2026) · Jakarta // 󰄬 REPO $68.36 · DAY $26.50 · 7DAY $315.27 · 30DAY $492.88 // Data layer vendored from @getpipher/pi-statusline (quota/zai, format, deen, adapters); // money comes from the omp sessions disk-scan (money.ts — subagent-inclusive). State @@ -14,7 +14,7 @@ import { readFileSync, mkdirSync } from "node:fs"; import { fetchQuota, readZaiKey, type QuotaLimit, type QuotaResult } from "./quota/zai.ts"; import { FIVE_HOUR_MS, WEEK_MS, windowElapsedPercent } from "./quota/project.ts"; -import { formatReset, formatResetAbs } from "./format.ts"; +import { formatReset, formatResetAbs, formatGregorian } from "./format.ts"; import { createDeenSource, type DeenSnapshot, type DeenSourceConfig } from "./deen/source.ts"; import { zaiStatusDetail } from "./adapters/zai.ts"; import { scanMoney, type MoneySnapshot } from "./money.ts"; @@ -215,7 +215,7 @@ export function prayerLine(theme: SlTheme, s: DeenSnapshot, sep: string): string export function infoLine(theme: SlTheme, s: DeenSnapshot, now: number, sep: string): string { const d = new Date(now); const clock = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`; - return ` ${theme.fg("dim", "󰥔")} ${[clock, s.hijri, s.city].map((part) => theme.fg("dim", part)).join(sep)}`; + return ` ${theme.fg("dim", "󰥔")} ${[clock, `${s.hijri} (${formatGregorian(now)})`, s.city].map((part) => theme.fg("dim", part)).join(sep)}`; } @@ -365,7 +365,7 @@ export default function ompStatusline(pi: SlApi): void { report && report.cacheHitRate !== null ? `cache ${Math.round(report.cacheHitRate * 100)}%` : "", ].filter(Boolean).join(" · ") : resolved ? "no quota data" : "no key"; - const deenPart = s ? `${s.city} · ${s.hijri}${s.staleMinutes !== null ? ` · stale ${s.staleMinutes}m` : " · fresh"}` : "no data"; + const deenPart = s ? `${s.city} · ${s.hijri} (${formatGregorian(Date.now())})${s.staleMinutes !== null ? ` · stale ${s.staleMinutes}m` : " · fresh"}` : "no data"; const moneyPart = `REPO $${money.repo.toFixed(2)} · DAY $${money.day.toFixed(2)} · 7DAY $${money.week.toFixed(2)} · 30DAY $${money.month.toFixed(2)} · sub $${money.sub.toFixed(2)} · ${money.entries} entries`; cmdCtx.ui.notify(`zai ${zaiPart} | deen ${deenPart} | money ${moneyPart}`, "info"); }, diff --git a/test/lines.test.ts b/test/lines.test.ts index a084207..9d2aedd 100644 --- a/test/lines.test.ts +++ b/test/lines.test.ts @@ -7,7 +7,7 @@ import type { SlTheme } from "../src/index.ts"; import type { DeenSnapshot } from "../src/deen/source.ts"; import type { PrayerScheduleEntry } from "../src/deen/time.ts"; import type { QuotaResult } from "../src/quota/zai.ts"; -import { formatResetAbs } from "../src/format.ts"; +import { formatResetAbs, formatGregorian } from "../src/format.ts"; const theme: SlTheme = { fg: (token, text) => `<${token}>${text}` }; const sep = theme.fg("dim", " · "); @@ -77,6 +77,13 @@ test("formatResetAbs: same-day clock, cross-day month-day, past → now", () => assert.equal(formatResetAbs(lateNight + 2 * HOUR, lateNight), "Sep 05 01:00"); // crosses midnight → padded single-digit day }); +test("formatGregorian: zero-padded day, EN month from local date, year", () => { + assert.equal(formatGregorian(new Date(2026, 8, 7).getTime()), "07 Sep 2026"); // single-digit day padded + assert.equal(formatGregorian(new Date(2026, 8, 20).getTime()), "20 Sep 2026"); // double-digit day verbatim + assert.equal(formatGregorian(new Date(2026, 11, 31).getTime()), "31 Dec 2026"); // last month of year + assert.equal(formatGregorian(new Date(2027, 0, 1).getTime()), "01 Jan 2027"); // year boundary +}); + test("paceText: gap = window × Δ%/100; formats and over/under tokens", () => { const H = 3_600_000; assert.deepEqual(paceText(5 * H, 34, 74), { text: "2h 0m under", token: "success" }); // RECTOR's worked example @@ -93,11 +100,11 @@ test("heat: band boundaries are >= on both thresholds", () => { assert.equal(heat(90), "error"); }); -test("infoLine: clock · hijri · city, all dim", () => { +test("infoLine: clock · hijri (gregorian in parens) · city, all dim", () => { const now = new Date(2026, 8, 7, 8, 15, 3).getTime(); // local-time construction → 08:15 in any tz assert.equal( infoLine(theme, deen(SCHEDULE), now, sep), - " 󰥔 08:15 · 25 Rabīʿ al-awwal 1448 · Jakarta", + " 󰥔 08:15 · 25 Rabīʿ al-awwal 1448 (07 Sep 2026) · Jakarta", ); }); From f1d25673b2718cdd28ae6a0da50076ab084991f0 Mon Sep 17 00:00:00 2001 From: RECTOR Date: Wed, 9 Sep 2026 21:02:36 +0700 Subject: [PATCH 2/2] chore: bump version to 0.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7167586..6509714 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@getpipher/omp-statusline", - "version": "0.5.0", + "version": "0.5.1", "description": "Four-line omp statusline widget: zai coding-plan quota (provider-gated), prayer times, hijri clock, and API-spend ledger (REPO/DAY/7DAY/30DAY, subagent-inclusive).", "keywords": [ "pi-package",