@jeffreyjyz/opencode-command-code 0.5.0 → 0.5.1

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/dist/index.js CHANGED
@@ -2414,7 +2414,7 @@ function superRefine(fn) {
2414
2414
  // package.json
2415
2415
  var package_default = {
2416
2416
  name: "@jeffreyjyz/opencode-command-code",
2417
- version: "0.5.0",
2417
+ version: "0.5.1",
2418
2418
  description: "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
2419
2419
  type: "module",
2420
2420
  main: "dist/index.js",
@@ -130,6 +130,24 @@ export declare function rate(value: number): string;
130
130
  export declare function count(value: number): string;
131
131
  /** "3h 12m" / "1d 20h" / "<1m" for a reset epoch. */
132
132
  export declare function until(epoch: number | undefined, now?: number): string;
133
+ /** A rolling window as two or three rows: the use line, then resets plus whatever
134
+ * needs flagging, then an optional `extra` continuation. The lead segment follows
135
+ * cmduse's importance order — over-cap flag, then the cap ETA, then the
136
+ * informational elapsed share — because the 37-column budget fits exactly one of
137
+ * them beside the reset countdown.
138
+ *
139
+ * Shared by both panels: CommandCode passes four arguments (output unchanged),
140
+ * the OpenCode Go/Zen side adds the window's request count as `extra`, so
141
+ * `LIMIT EXCEEDED`, the tone, `cap in …`, `elapsed` and `resets` all have one
142
+ * implementation. */
143
+ export declare function windowRows(label: string, w: WindowUsage | undefined, now: number, durSecs: number, extra?: string): SidebarRow[];
144
+ /**
145
+ * The two store-backed rows for the active model — its requests under `Usage
146
+ * (this model)`, then this conversation's own totals under `Session`. They need
147
+ * no network, so both panels keep them when the catalog is missing, and both
148
+ * families build them here rather than in two places.
149
+ */
150
+ export declare function localUsageRows(usage?: ModelUsage, session?: ModelUsage): SidebarRow[];
133
151
  /** Plan + rolling windows + period totals, from a cmduse snapshot. */
134
152
  export declare function usageRows(usage: Usage | undefined, now?: number): SidebarRow[];
135
153
  /** Active model's allowance, rates and benchmarks, from mpc's catalog; its
@@ -14,7 +14,15 @@ export interface ZenModel {
14
14
  month: ZenTotals;
15
15
  }
16
16
  export interface ZenUsage {
17
+ /**
18
+ * Billing period start, epoch ms: `periodStart` on current ocuse, or
19
+ * `periodStartAt` once it publishes the bounds (the same instants cmduse
20
+ * 0.7.2+ carries).
21
+ */
17
22
  periodStart?: number;
23
+ /** Billing period end, epoch ms. Optional: older ocuse does not publish it
24
+ * and the Monthly row must then degrade to spend alone. */
25
+ periodEndAt?: number;
18
26
  source?: string;
19
27
  totals: {
20
28
  fiveHour: ZenTotals;
@@ -28,6 +36,7 @@ export interface ZenUsage {
28
36
  export declare function parseZenJson(text: string): ZenUsage;
29
37
  /** The OpenCode Go / Zen panel: period windows, a rule, then the active model.
30
38
  * Like `modelRows`, `fallbackName` (the session's own id) keeps the model block
31
- * — and the local `Session` figure — on screen when mpc's catalog is
32
- * unreachable; only the catalog-derived rows then drop out. */
33
- export declare function zenRows(usage: ZenUsage | undefined, meta: ModelMeta | undefined, session?: ModelUsage, fallbackName?: string): SidebarRow[];
39
+ * — and the local `Usage (this model)` / `Session` figures, which need no network
40
+ * — on screen when mpc's catalog is unreachable; only the catalog-derived rows
41
+ * then drop out. */
42
+ export declare function zenRows(usage: ZenUsage | undefined, meta: ModelMeta | undefined, modelUsage?: ModelUsage, session?: ModelUsage, fallbackName?: string): SidebarRow[];
package/dist/tui.js CHANGED
@@ -621,7 +621,7 @@ function until(epoch, now = Date.now()) {
621
621
  const days = Math.floor(hours / 24);
622
622
  return hours % 24 ? `${days}d ${hours % 24}h` : `${days}d`;
623
623
  }
624
- function windowRows(label, w, now, durSecs) {
624
+ function windowRows(label, w, now, durSecs, extra) {
625
625
  if (!w || typeof w.cap !== "number" || w.cap <= 0)
626
626
  return [];
627
627
  const used = typeof w.used === "number" ? w.used : 0;
@@ -632,7 +632,23 @@ function windowRows(label, w, now, durSecs) {
632
632
  const reset = until(w.resetAt, now);
633
633
  const lead = w.exceeded ? "LIMIT EXCEEDED" : eta === undefined ? elapsed === undefined ? "" : `${elapsed} elapsed` : `cap in ${until(now + eta * 1000, now)}`;
634
634
  const detail = [lead, reset ? `resets ${reset}` : ""].filter(Boolean).join(" \xB7 ");
635
- return [[label, `${money(used)}/${money(w.cap)} (${pct.toFixed(1)}%)`, w.exceeded ? "crit" : pctTone(pct)], ...detail ? [["", detail, "muted"]] : []];
635
+ return [[label, `${money(used)}/${money(w.cap)} (${pct.toFixed(1)}%)`, w.exceeded ? "crit" : pctTone(pct)], ...detail ? [["", detail, "muted"]] : [], ...extra ? [["", extra, "muted"]] : []];
636
+ }
637
+ function localUsageRows(usage, session) {
638
+ const rows = [];
639
+ if (usage) {
640
+ rows.push(["Usage (this model)", `${count(usage.requests)} req`, "base"]);
641
+ const spend = usage.cost > 0 ? money(usage.cost) : "";
642
+ const share = usage.cost > 0 && session && session.cost > 0 ? `${Math.min(100, Math.round(usage.cost / session.cost * 100))}% of session` : "";
643
+ const detail = [spend, share].filter(Boolean).join(" \xB7 ");
644
+ if (detail)
645
+ rows.push(["", detail, "muted"]);
646
+ }
647
+ if (session) {
648
+ const spent = session.cost > 0 ? ` \xB7 ${money(session.cost)}` : "";
649
+ rows.push(["Session", `${count(session.requests)} req${spent}`, "base"]);
650
+ }
651
+ return rows;
636
652
  }
637
653
  function monthlyDetail(usage, now) {
638
654
  const {
@@ -681,19 +697,7 @@ function modelRows(meta, usage, session, fallbackName) {
681
697
  const name = meta?.name ?? fallbackName;
682
698
  if (!name)
683
699
  return [];
684
- const rows = [["Model", clip(name, valueWidth("Model")), "strong", true]];
685
- if (usage) {
686
- rows.push(["Usage (this model)", `${count(usage.requests)} req`, "base"]);
687
- const spend = usage.cost > 0 ? money(usage.cost) : "";
688
- const share = usage.cost > 0 && session && session.cost > 0 ? `${Math.min(100, Math.round(usage.cost / session.cost * 100))}% of session` : "";
689
- const detail = [spend, share].filter(Boolean).join(" \xB7 ");
690
- if (detail)
691
- rows.push(["", detail, "muted"]);
692
- }
693
- if (session) {
694
- const spent = session.cost > 0 ? ` \xB7 ${money(session.cost)}` : "";
695
- rows.push(["Session", `${count(session.requests)} req${spent}`, "base"]);
696
- }
700
+ const rows = [["Model", clip(name, valueWidth("Model")), "strong", true], ...localUsageRows(usage, session)];
697
701
  if (!meta)
698
702
  return rows;
699
703
  if (meta.tier)
@@ -2060,7 +2064,8 @@ function parseZenJson(text) {
2060
2064
  }
2061
2065
  const top = body.totals ?? {};
2062
2066
  return {
2063
- periodStart: typeof body.periodStart === "number" ? body.periodStart : undefined,
2067
+ periodStart: typeof body.periodStartAt === "number" ? body.periodStartAt : typeof body.periodStart === "number" ? body.periodStart : undefined,
2068
+ periodEndAt: typeof body.periodEndAt === "number" ? body.periodEndAt : undefined,
2064
2069
  source: typeof body.source === "string" ? body.source : undefined,
2065
2070
  totals: {
2066
2071
  fiveHour: totals(top.fiveHour),
@@ -2070,38 +2075,53 @@ function parseZenJson(text) {
2070
2075
  models
2071
2076
  };
2072
2077
  }
2073
- function windowRows2(label, spent, limit, share) {
2074
- if (typeof limit !== "number" || limit <= 0) {
2078
+ function monthPeriod(usage) {
2079
+ const {
2080
+ periodStart,
2081
+ periodEndAt
2082
+ } = usage;
2083
+ if (typeof periodStart !== "number" || typeof periodEndAt !== "number")
2084
+ return;
2085
+ const durSecs = Math.round((periodEndAt - periodStart) / 1000);
2086
+ if (durSecs <= 0)
2087
+ return;
2088
+ return {
2089
+ resetAt: periodEndAt,
2090
+ durSecs
2091
+ };
2092
+ }
2093
+ function zenWindow(label, spent, limit, share, now, durSecs, resetAt) {
2094
+ const cap = typeof limit === "number" && limit > 0 ? limit * share : undefined;
2095
+ if (cap === undefined) {
2075
2096
  return [[label, `${money(spent.cost)} \xB7 ${count(spent.requests)} req`, "base"]];
2076
2097
  }
2077
- const cap = limit * share;
2078
- const pct = cap > 0 ? spent.cost / cap * 100 : 0;
2079
- const rows = [[label, `${money(spent.cost)}/${money(cap)} (${pct.toFixed(1)}%)`, pctTone(pct)]];
2080
- if (spent.requests > 0)
2081
- rows.push(["", `${count(spent.requests)} req`, "muted"]);
2082
- return rows;
2083
- }
2084
- function zenRows(usage, meta, session, fallbackName) {
2098
+ return windowRows(label, {
2099
+ cap,
2100
+ used: spent.cost,
2101
+ resetAt,
2102
+ exceeded: spent.cost >= cap
2103
+ }, now, durSecs, spent.requests > 0 ? `${count(spent.requests)} req` : undefined);
2104
+ }
2105
+ function zenRows(usage, meta, modelUsage, session, fallbackName) {
2085
2106
  if (!usage)
2086
2107
  return [];
2108
+ const now = Date.now();
2087
2109
  const oc = meta?.oc;
2088
2110
  const rows = [["Plan", `${oc?.plan ?? "Go"} \xB7 limits per model`, "base"]];
2089
2111
  const mine = meta ? usage.models.get(modelKey(meta.name)) : undefined;
2090
2112
  const limit = oc?.allowance ?? mine?.limit;
2091
2113
  const cap = mine ? limit : undefined;
2092
- rows.push(...windowRows2("5-hour", mine?.fiveHour ?? usage.totals.fiveHour, cap, GO_WINDOW_SHARE.fiveHour));
2093
- rows.push(...windowRows2("Weekly", mine?.weekly ?? usage.totals.weekly, cap, GO_WINDOW_SHARE.weekly));
2094
- rows.push(...windowRows2("Month", mine?.month ?? usage.totals.month, cap, GO_WINDOW_SHARE.month));
2114
+ rows.push(...zenWindow("5-hour", mine?.fiveHour ?? usage.totals.fiveHour, cap, GO_WINDOW_SHARE.fiveHour, now, FIVE_HOUR_SECS));
2115
+ rows.push(...zenWindow("Weekly", mine?.weekly ?? usage.totals.weekly, cap, GO_WINDOW_SHARE.weekly, now, WEEKLY_SECS));
2116
+ const period = monthPeriod(usage);
2117
+ rows.push(...zenWindow("Monthly", mine?.month ?? usage.totals.month, cap, GO_WINDOW_SHARE.month, now, period?.durSecs ?? 0, period?.resetAt));
2095
2118
  rows.push(["Period", `${count(usage.totals.month.requests)} requests \xB7 ${money(usage.totals.month.cost)}`, "base"]);
2096
2119
  rows.push(separator());
2097
2120
  const name = meta?.name ?? fallbackName;
2098
2121
  if (!name)
2099
2122
  return rows;
2100
2123
  rows.push(["Model", clip(name, valueWidth("Model")), "strong", true]);
2101
- if (session) {
2102
- const spent = session.cost > 0 ? ` \xB7 ${money(session.cost)}` : "";
2103
- rows.push(["Session", `${count(session.requests)} req${spent}`, "base"]);
2104
- }
2124
+ rows.push(...localUsageRows(modelUsage, session));
2105
2125
  if (!meta)
2106
2126
  return rows;
2107
2127
  if (typeof limit === "number") {
@@ -2503,6 +2523,7 @@ function useRows(activeModelId, providerID, sessionID) {
2503
2523
  refreshModelUsage(activeModelId());
2504
2524
  } else if (kind === "go" || kind === "zen") {
2505
2525
  setZen(await loadZen(loadPrefs().ocPlan));
2526
+ refreshModelUsage(activeModelId());
2506
2527
  }
2507
2528
  } catch {} finally {
2508
2529
  inFlight = false;
@@ -2520,7 +2541,7 @@ function useRows(activeModelId, providerID, sessionID) {
2520
2541
  createEffect(() => {
2521
2542
  const id = activeModelId();
2522
2543
  const session = sessionID();
2523
- if (sessionKind(providerID()) !== "ours" || !id || !session)
2544
+ if (!shows(sessionKind(providerID())) || !id || !session)
2524
2545
  return;
2525
2546
  refreshModelUsage(id);
2526
2547
  });
@@ -2540,7 +2561,7 @@ function useRows(activeModelId, providerID, sessionID) {
2540
2561
  const found = id ? meta().get(modelKey(id)) ?? meta().get(id) : undefined;
2541
2562
  const fallbackName = id ? id.split("/").pop() ?? id : undefined;
2542
2563
  if (kind === "go" || kind === "zen") {
2543
- return zenRows(zen(), found, sessionUsage(), fallbackName);
2564
+ return zenRows(zen(), found, usageFor(id), sessionUsage(), fallbackName);
2544
2565
  }
2545
2566
  const model = found ? {
2546
2567
  ...found,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jeffreyjyz/opencode-command-code",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Command Code provider + usage dashboard for opencode: two providers (Anthropic wire for Claude, OpenAI wire for everything else) against api.commandcode.ai, live model list, plan gating, /cmd-usage. Requires the cmduse CLI for usage rendering.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",