@jeffreyjyz/opencode-command-code 0.1.3 → 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/dist/index.js +63 -7
- package/dist/usage.d.ts +24 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -452,6 +452,8 @@ var plans_default = {
|
|
|
452
452
|
|
|
453
453
|
// src/usage.ts
|
|
454
454
|
var BAR_WIDTH = 12;
|
|
455
|
+
var FIVE_HOUR_SECS = 5 * 3600;
|
|
456
|
+
var WEEKLY_SECS = 7 * 86400;
|
|
455
457
|
function money(v) {
|
|
456
458
|
return `$${v.toFixed(2)}`;
|
|
457
459
|
}
|
|
@@ -488,6 +490,50 @@ function relTime(resetAtMs, nowSecs) {
|
|
|
488
490
|
return `${m}m`;
|
|
489
491
|
return "<1m";
|
|
490
492
|
}
|
|
493
|
+
function duration(secs) {
|
|
494
|
+
const d = Math.floor(secs / 86400);
|
|
495
|
+
const h = Math.floor(secs % 86400 / 3600);
|
|
496
|
+
const m = Math.floor(secs % 3600 / 60);
|
|
497
|
+
if (d > 0)
|
|
498
|
+
return `${d}d ${h}h`;
|
|
499
|
+
if (h > 0)
|
|
500
|
+
return `${h}h ${m}m`;
|
|
501
|
+
if (m > 0)
|
|
502
|
+
return `${m}m`;
|
|
503
|
+
return "<1m";
|
|
504
|
+
}
|
|
505
|
+
function elapsedPct(resetAtMs, durSecs, nowSecs) {
|
|
506
|
+
if (resetAtMs === undefined)
|
|
507
|
+
return;
|
|
508
|
+
const resetSecs = Math.floor(resetAtMs / 1000);
|
|
509
|
+
if (resetSecs < durSecs)
|
|
510
|
+
return;
|
|
511
|
+
const start = resetSecs - durSecs;
|
|
512
|
+
if (nowSecs < start)
|
|
513
|
+
return;
|
|
514
|
+
const pct = Math.min(Math.max((nowSecs - start) / durSecs * 100, 0), 100);
|
|
515
|
+
return Math.round(pct);
|
|
516
|
+
}
|
|
517
|
+
function paceEta(resetAtMs, durSecs, used, cap, nowSecs) {
|
|
518
|
+
if (resetAtMs === undefined)
|
|
519
|
+
return;
|
|
520
|
+
const resetSecs = Math.floor(resetAtMs / 1000);
|
|
521
|
+
if (resetSecs < durSecs)
|
|
522
|
+
return;
|
|
523
|
+
const start = resetSecs - durSecs;
|
|
524
|
+
if (nowSecs <= start || nowSecs >= resetSecs)
|
|
525
|
+
return;
|
|
526
|
+
const elapsed = nowSecs - start;
|
|
527
|
+
if (elapsed / durSecs < 0.1)
|
|
528
|
+
return;
|
|
529
|
+
const rate = used / elapsed;
|
|
530
|
+
if (rate <= 0 || used >= cap)
|
|
531
|
+
return;
|
|
532
|
+
const secsToCap = (cap - used) / rate;
|
|
533
|
+
if (secsToCap >= resetSecs - nowSecs)
|
|
534
|
+
return;
|
|
535
|
+
return secsToCap;
|
|
536
|
+
}
|
|
491
537
|
function parseIsoUtc(s) {
|
|
492
538
|
const m = s.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|[+-]\d{2}:?\d{2})?$/);
|
|
493
539
|
if (!m)
|
|
@@ -503,6 +549,13 @@ function parseIsoUtc(s) {
|
|
|
503
549
|
}
|
|
504
550
|
return Date.UTC(+y, +mo - 1, +d, +h, +mi, Math.floor(+sec)) - offsetMs;
|
|
505
551
|
}
|
|
552
|
+
function monthlyWindow(cap, remaining, periodStart, periodEnd) {
|
|
553
|
+
const used = Math.min(Math.max(cap - remaining, 0), cap);
|
|
554
|
+
const resetAt = periodEnd ? parseIsoUtc(periodEnd) : undefined;
|
|
555
|
+
const start = periodStart ? parseIsoUtc(periodStart) : undefined;
|
|
556
|
+
const durSecs = start !== undefined && resetAt !== undefined ? Math.max(Math.floor((resetAt - start) / 1000), 1) : undefined;
|
|
557
|
+
return { window: { used, cap, resetAt }, durSecs };
|
|
558
|
+
}
|
|
506
559
|
var NAME_RULES = plans_default.nameRules;
|
|
507
560
|
var DEFAULT_NAME = plans_default.defaultName;
|
|
508
561
|
var CAPS = plans_default.caps;
|
|
@@ -518,9 +571,13 @@ function planName(planId) {
|
|
|
518
571
|
}
|
|
519
572
|
return DEFAULT_NAME;
|
|
520
573
|
}
|
|
521
|
-
function windowLine(label, w, nowSecs) {
|
|
574
|
+
function windowLine(label, w, nowSecs, durSecs) {
|
|
522
575
|
const status = w.exceeded ? " \xB7 **LIMIT EXCEEDED**" : "";
|
|
523
|
-
|
|
576
|
+
const elapsed = durSecs !== undefined ? elapsedPct(w.resetAt, durSecs, nowSecs) : undefined;
|
|
577
|
+
const thru = elapsed !== undefined ? ` \xB7 window ${elapsed}% elapsed` : "";
|
|
578
|
+
const eta = durSecs !== undefined ? paceEta(w.resetAt, durSecs, w.used, w.cap, nowSecs) : undefined;
|
|
579
|
+
const pace = eta !== undefined ? ` \xB7 **on pace to hit cap in ${duration(eta)}**` : "";
|
|
580
|
+
return `**${label}** \`${bar(w.used, w.cap)}\` ${money(w.used)} of ${money(w.cap)} (${pctStr(w.used, w.cap)}) \xB7 resets in ${relTime(w.resetAt, nowSecs)}${thru}${pace}${status}
|
|
524
581
|
`;
|
|
525
582
|
}
|
|
526
583
|
function plansTable(current) {
|
|
@@ -561,16 +618,15 @@ async function renderUsage(key) {
|
|
|
561
618
|
}
|
|
562
619
|
lines.push("### Usage windows");
|
|
563
620
|
if (cap) {
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
lines.push(windowLine("Monthly", { used, cap, resetAt }, nowSecs));
|
|
621
|
+
const { window, durSecs } = monthlyWindow(cap, cr.credits.monthlyCredits, sub.currentPeriodStart, sub.currentPeriodEnd);
|
|
622
|
+
lines.push(windowLine("Monthly", { ...window, exceeded: false }, nowSecs, durSecs));
|
|
567
623
|
}
|
|
568
624
|
const five = cr.windowLimits?.fiveHour;
|
|
569
625
|
const weekly = cr.windowLimits?.weekly;
|
|
570
626
|
if (five)
|
|
571
|
-
lines.push(windowLine("5-hour", five, nowSecs));
|
|
627
|
+
lines.push(windowLine("5-hour", five, nowSecs, FIVE_HOUR_SECS));
|
|
572
628
|
if (weekly)
|
|
573
|
-
lines.push(windowLine("Weekly", weekly, nowSecs));
|
|
629
|
+
lines.push(windowLine("Weekly", weekly, nowSecs, WEEKLY_SECS));
|
|
574
630
|
if (!five && !weekly)
|
|
575
631
|
lines.push(`No rolling windows on this plan (pay-as-you-go credits only).
|
|
576
632
|
`);
|
package/dist/usage.d.ts
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
import { type Window } from "./api";
|
|
2
|
+
export declare const FIVE_HOUR_SECS: number;
|
|
3
|
+
export declare const WEEKLY_SECS: number;
|
|
2
4
|
export declare function money(v: number): string;
|
|
3
5
|
export declare function compact(n: number): string;
|
|
4
6
|
export declare function bar(used: number, cap: number): string;
|
|
5
7
|
export declare function pctStr(used: number, cap: number): string;
|
|
6
8
|
export declare function relTime(resetAtMs: number | undefined, nowSecs: number): string;
|
|
9
|
+
/** Compact "Xh Ym" / "Xd Yh" for a span of seconds. Pure duration — use this
|
|
10
|
+
* (not relTime) for ETAs/countdowns. Mirrors cmduse_core::duration. */
|
|
11
|
+
export declare function duration(secs: number): string;
|
|
12
|
+
/** % of a rolling window elapsed; window length = durSecs, ends at resetAtMs.
|
|
13
|
+
* undefined when the window hasn't started or the reset is unknown. */
|
|
14
|
+
export declare function elapsedPct(resetAtMs: number | undefined, durSecs: number, nowSecs: number): number | undefined;
|
|
15
|
+
/** Seconds until spend hits cap at the current rate, if before the reset.
|
|
16
|
+
* Suppressed before 10% of the window has elapsed (flat-rate projection is
|
|
17
|
+
* unreliable that early). undefined = no warning. */
|
|
18
|
+
export declare function paceEta(resetAtMs: number | undefined, durSecs: number, used: number, cap: number, nowSecs: number): number | undefined;
|
|
7
19
|
/** ISO 8601 → epoch ms. Handles trailing Z or a ±HH:MM / ±HHMM offset. */
|
|
8
20
|
export declare function parseIsoUtc(s: string): number | undefined;
|
|
21
|
+
/** Assemble the monthly window from the plan cap + subscription period:
|
|
22
|
+
* used = cap − remaining (clamped), reset = period end, durSecs = period
|
|
23
|
+
* length. Mirrors cmduse_core::monthly_window (conformance-pinned). */
|
|
24
|
+
export declare function monthlyWindow(cap: number, remaining: number, periodStart?: string, periodEnd?: string): {
|
|
25
|
+
window: {
|
|
26
|
+
used: number;
|
|
27
|
+
cap: number;
|
|
28
|
+
resetAt?: number;
|
|
29
|
+
};
|
|
30
|
+
durSecs?: number;
|
|
31
|
+
};
|
|
9
32
|
export declare function planMonthlyCap(planId: string): number | undefined;
|
|
10
33
|
export declare function planName(planId: string): string;
|
|
11
|
-
export declare function windowLine(label: string, w: Window, nowSecs: number): string;
|
|
34
|
+
export declare function windowLine(label: string, w: Window, nowSecs: number, durSecs?: number): string;
|
|
12
35
|
export declare function plansTable(current: string): string;
|
|
13
36
|
/** Fetch billing data in parallel and render the markdown dashboard. */
|
|
14
37
|
export declare function renderUsage(key: string): Promise<string>;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffreyjyz/opencode-command-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"build": "bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin
|
|
9
|
+
"build": "bun build src/index.ts --outdir dist --target bun --external @opencode-ai/plugin && tsc -p tsconfig.build.json",
|
|
10
10
|
"test": "bun test",
|
|
11
11
|
"extract": "bun run scripts/extract-gating.ts",
|
|
12
12
|
"typecheck": "tsc --noEmit"
|