diff --git a/README.md b/README.md
index fa38f06..6127cbf 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
[](./package.json)
[](./LICENSE)
-
+
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/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",
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>",
);
});