Skip to content

Commit 237ba7a

Browse files
committed
merge origin/main into zhipu provider
2 parents e0add23 + 2293f2f commit 237ba7a

27 files changed

Lines changed: 3645 additions & 493 deletions

.github/workflows/publish-npm.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ jobs:
2222
- name: Setup Node.js
2323
uses: actions/setup-node@v6
2424
with:
25-
node-version: 20
25+
node-version: 24
2626
registry-url: https://registry.npmjs.org/
27-
cache: npm
2827

2928
- name: Sync package.json version from release tag
3029
if: github.event_name == 'release'
@@ -60,13 +59,7 @@ jobs:
6059
run: npm test
6160

6261
- name: Publish
63-
env:
64-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
65-
NPM_CONFIG_PROVENANCE_SOURCE_REPOSITORY: https://github.com/${{ github.repository }}
66-
NPM_CONFIG_PROVENANCE_SOURCE_REPOSITORY_REF: ${{ github.ref }}
67-
NPM_CONFIG_PROVENANCE_SOURCE_REPOSITORY_COMMIT: ${{ github.sha }}
68-
NPM_CONFIG_PROVENANCE_SOURCE_REPOSITORY_URL: https://github.com/${{ github.repository }}
69-
run: npm publish --access public --provenance
62+
run: npm publish --access public
7063

7164
- name: Commit synced version back to repository
7265
if: github.event_name == 'release'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ AGENTS.md
3131
/images
3232
/.agents
3333
/prompt-exports
34+
/opencode-quota

README.md

Lines changed: 371 additions & 294 deletions
Large diffs are not rendered by default.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@slkiser/opencode-quota",
3-
"version": "3.6.2",
3+
"version": "3.7.1",
44
"description": "OpenCode quota & tokens usage with zero context window pollution. Supports GitHub Copilot, OpenAI (Plus/Pro), Qwen Code, Chutes AI, Synthetic, Google Antigravity, Z.ai coding plan and more.",
55
"type": "module",
66
"main": "./dist/index.js",

src/lib/config.ts

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ export const QUOTA_TOAST_SETTING_SOURCE_KEYS = [
5353
"toastDurationMs",
5454
"onlyCurrentModel",
5555
"showSessionTokens",
56+
"tuiSidebarPanel.enabled",
57+
"tuiCompactStatus.enabled",
58+
"tuiCompactStatus.homeBottom",
59+
"tuiCompactStatus.sessionPrompt",
60+
"tuiCompactStatus.suppressWhenNativeProviderQuota",
61+
"tuiCompactStatus.maxWidth",
5662
"layout.maxWidth",
5763
"layout.narrowAt",
5864
"layout.tinyAt",
@@ -110,6 +116,8 @@ const NETWORK_SETTING_SOURCE_KEYS = [
110116
] as const satisfies readonly QuotaToastSettingSourceKey[];
111117

112118
type PricingSnapshotPatch = Partial<QuotaToastConfig["pricingSnapshot"]>;
119+
type TuiSidebarPanelPatch = Partial<QuotaToastConfig["tuiSidebarPanel"]>;
120+
type TuiCompactStatusPatch = Partial<QuotaToastConfig["tuiCompactStatus"]>;
113121
type LayoutPatch = Partial<QuotaToastConfig["layout"]>;
114122

115123
type ValidatedQuotaToastPatch = {
@@ -137,6 +145,8 @@ type ValidatedQuotaToastPatch = {
137145
toastDurationMs?: number;
138146
onlyCurrentModel?: boolean;
139147
showSessionTokens?: boolean;
148+
tuiSidebarPanel?: TuiSidebarPanelPatch;
149+
tuiCompactStatus?: TuiCompactStatusPatch;
140150
layout?: LayoutPatch;
141151
};
142152

@@ -257,6 +267,8 @@ function cloneConfig(config: QuotaToastConfig): QuotaToastConfig {
257267
googleModels: [...config.googleModels],
258268
opencodeGoWindows: [...config.opencodeGoWindows],
259269
pricingSnapshot: { ...config.pricingSnapshot },
270+
tuiSidebarPanel: { ...config.tuiSidebarPanel },
271+
tuiCompactStatus: { ...config.tuiCompactStatus },
260272
layout: { ...config.layout },
261273
};
262274
}
@@ -344,6 +356,53 @@ function extractPricingSnapshotPatch(value: unknown): PricingSnapshotPatch | und
344356
return Object.keys(patch).length > 0 ? patch : undefined;
345357
}
346358

359+
function extractTuiSidebarPanelPatch(value: unknown): TuiSidebarPanelPatch | undefined {
360+
if (!isPlainObject(value)) {
361+
return undefined;
362+
}
363+
364+
const patch: TuiSidebarPanelPatch = {};
365+
366+
if (hasOwnKey(value, "enabled") && typeof value.enabled === "boolean") {
367+
patch.enabled = value.enabled;
368+
}
369+
370+
return Object.keys(patch).length > 0 ? patch : undefined;
371+
}
372+
373+
function extractTuiCompactStatusPatch(value: unknown): TuiCompactStatusPatch | undefined {
374+
if (!isPlainObject(value)) {
375+
return undefined;
376+
}
377+
378+
const patch: TuiCompactStatusPatch = {};
379+
380+
if (hasOwnKey(value, "enabled") && typeof value.enabled === "boolean") {
381+
patch.enabled = value.enabled;
382+
}
383+
384+
if (hasOwnKey(value, "homeBottom") && typeof value.homeBottom === "boolean") {
385+
patch.homeBottom = value.homeBottom;
386+
}
387+
388+
if (hasOwnKey(value, "sessionPrompt") && typeof value.sessionPrompt === "boolean") {
389+
patch.sessionPrompt = value.sessionPrompt;
390+
}
391+
392+
if (
393+
hasOwnKey(value, "suppressWhenNativeProviderQuota") &&
394+
typeof value.suppressWhenNativeProviderQuota === "boolean"
395+
) {
396+
patch.suppressWhenNativeProviderQuota = value.suppressWhenNativeProviderQuota;
397+
}
398+
399+
if (hasOwnKey(value, "maxWidth") && isPositiveNumber(value.maxWidth)) {
400+
patch.maxWidth = value.maxWidth;
401+
}
402+
403+
return Object.keys(patch).length > 0 ? patch : undefined;
404+
}
405+
347406
function extractLayoutPatch(value: unknown): LayoutPatch | undefined {
348407
if (!isPlainObject(value)) {
349408
return undefined;
@@ -522,6 +581,20 @@ function extractValidatedQuotaToastPatch(
522581
patch.showSessionTokens = quotaToastConfig.showSessionTokens;
523582
}
524583

584+
if (hasOwnKey(quotaToastConfig, "tuiSidebarPanel")) {
585+
const tuiSidebarPanel = extractTuiSidebarPanelPatch(quotaToastConfig.tuiSidebarPanel);
586+
if (tuiSidebarPanel) {
587+
patch.tuiSidebarPanel = tuiSidebarPanel;
588+
}
589+
}
590+
591+
if (hasOwnKey(quotaToastConfig, "tuiCompactStatus")) {
592+
const tuiCompactStatus = extractTuiCompactStatusPatch(quotaToastConfig.tuiCompactStatus);
593+
if (tuiCompactStatus) {
594+
patch.tuiCompactStatus = tuiCompactStatus;
595+
}
596+
}
597+
525598
if (hasOwnKey(quotaToastConfig, "layout")) {
526599
const layout = extractLayoutPatch(quotaToastConfig.layout);
527600
if (layout) {
@@ -671,6 +744,45 @@ function applyValidatedQuotaToastPatch(
671744
applySettingSource(settingSources, "showSessionTokens", sourcePath);
672745
}
673746

747+
if (patch.tuiSidebarPanel) {
748+
if (hasOwnKey(patch.tuiSidebarPanel, "enabled")) {
749+
config.tuiSidebarPanel.enabled = patch.tuiSidebarPanel.enabled!;
750+
applySettingSource(settingSources, "tuiSidebarPanel.enabled", sourcePath);
751+
}
752+
}
753+
754+
if (patch.tuiCompactStatus) {
755+
if (hasOwnKey(patch.tuiCompactStatus, "enabled")) {
756+
config.tuiCompactStatus.enabled = patch.tuiCompactStatus.enabled!;
757+
applySettingSource(settingSources, "tuiCompactStatus.enabled", sourcePath);
758+
}
759+
760+
if (hasOwnKey(patch.tuiCompactStatus, "homeBottom")) {
761+
config.tuiCompactStatus.homeBottom = patch.tuiCompactStatus.homeBottom!;
762+
applySettingSource(settingSources, "tuiCompactStatus.homeBottom", sourcePath);
763+
}
764+
765+
if (hasOwnKey(patch.tuiCompactStatus, "sessionPrompt")) {
766+
config.tuiCompactStatus.sessionPrompt = patch.tuiCompactStatus.sessionPrompt!;
767+
applySettingSource(settingSources, "tuiCompactStatus.sessionPrompt", sourcePath);
768+
}
769+
770+
if (hasOwnKey(patch.tuiCompactStatus, "suppressWhenNativeProviderQuota")) {
771+
config.tuiCompactStatus.suppressWhenNativeProviderQuota =
772+
patch.tuiCompactStatus.suppressWhenNativeProviderQuota!;
773+
applySettingSource(
774+
settingSources,
775+
"tuiCompactStatus.suppressWhenNativeProviderQuota",
776+
sourcePath,
777+
);
778+
}
779+
780+
if (hasOwnKey(patch.tuiCompactStatus, "maxWidth")) {
781+
config.tuiCompactStatus.maxWidth = patch.tuiCompactStatus.maxWidth!;
782+
applySettingSource(settingSources, "tuiCompactStatus.maxWidth", sourcePath);
783+
}
784+
}
785+
674786
if (patch.layout) {
675787
if (hasOwnKey(patch.layout, "maxWidth")) {
676788
config.layout.maxWidth = patch.layout.maxWidth!;
@@ -933,5 +1045,5 @@ export async function loadConfig(
9331045
meta.networkSettingSources = {};
9341046
meta.configIssues = [];
9351047
}
936-
return DEFAULT_CONFIG;
1048+
return cloneDefaultConfig();
9371049
}

src/lib/format.ts

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,48 +21,7 @@ import {
2121
renderSidebarSessionTokenSummaryLines,
2222
} from "./session-tokens-format.js";
2323
import { getQuotaFormatStyleDefinition } from "./quota-format-style.js";
24-
import { formatGroupedHeader } from "./grouped-header-format.js";
25-
26-
function normalizeSingleWindowLabelText(value?: string): string {
27-
return value?.trim().replace(/:+$/u, "").trim() ?? "";
28-
}
29-
30-
function extractSingleWindowWindowLabel(text: string): string | null {
31-
const lower = normalizeSingleWindowLabelText(text).toLowerCase();
32-
if (!lower) return null;
33-
34-
if (/\b(?:rpm|per minute|minute|minutes)\b/u.test(lower)) return "RPM";
35-
if (/\b(?:rolling|5h|5 h|5-hour|5 hour|five-hour|five hour)\b/u.test(lower)) return "5h";
36-
if (/\b(?:hourly|1h|1 h|1-hour|1 hour|hour)\b/u.test(lower)) return "Hourly";
37-
if (/\b(?:7d|7 d|7-day|7 day|weekly|week)\b/u.test(lower)) return "Weekly";
38-
if (/\b(?:daily|1d|1 d|1-day|1 day|day)\b/u.test(lower)) return "Daily";
39-
if (/\b(?:monthly|month)\b/u.test(lower)) return "Monthly";
40-
if (/\b(?:yearly|annual|annually|year)\b/u.test(lower)) return "Yearly";
41-
if (/\bmcp\b/u.test(lower)) return "MCP";
42-
if (/\bcode review\b/u.test(lower)) return "Code Review";
43-
44-
return null;
45-
}
46-
47-
function buildSingleWindowPercentName(entry: QuotaToastEntry): string {
48-
const name = entry.name.trim();
49-
const group = entry.group?.trim();
50-
const windowLabel =
51-
extractSingleWindowWindowLabel(entry.label ?? "") ??
52-
extractSingleWindowWindowLabel(entry.name);
53-
54-
if (name.startsWith("[")) {
55-
if (!windowLabel) return name;
56-
return name.toLowerCase().includes(windowLabel.toLowerCase()) ? name : `${name} ${windowLabel}`;
57-
}
58-
59-
if (group) {
60-
const provider = formatGroupedHeader(group);
61-
return windowLabel ? `${provider} ${windowLabel}` : provider;
62-
}
63-
64-
return name;
65-
}
24+
import { buildSingleWindowPercentEntryDisplayName } from "./quota-entry-display.js";
6625

6726
export function formatQuotaRows(params: {
6827
version: string;
@@ -204,7 +163,7 @@ export function formatQuotaRows(params: {
204163
addValueEntry(entry.name, entry.resetTimeIso, entry.value);
205164
} else {
206165
addPercentEntry(
207-
buildSingleWindowPercentName(entry),
166+
buildSingleWindowPercentEntryDisplayName(entry),
208167
entry.resetTimeIso,
209168
entry.percentRemaining,
210169
entry.right,

0 commit comments

Comments
 (0)