@beyona/pi-zai-usage 0.3.2

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/LICENSE +21 -0
  3. package/README.md +100 -0
  4. package/dist/api.d.ts +34 -0
  5. package/dist/api.d.ts.map +1 -0
  6. package/dist/api.js +39 -0
  7. package/dist/api.js.map +1 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +26 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/usage-lib/api.d.ts +34 -0
  13. package/dist/usage-lib/api.d.ts.map +1 -0
  14. package/dist/usage-lib/api.js +74 -0
  15. package/dist/usage-lib/api.js.map +1 -0
  16. package/dist/usage-lib/cache.d.ts +22 -0
  17. package/dist/usage-lib/cache.d.ts.map +1 -0
  18. package/dist/usage-lib/cache.js +56 -0
  19. package/dist/usage-lib/cache.js.map +1 -0
  20. package/dist/usage-lib/color.d.ts +24 -0
  21. package/dist/usage-lib/color.d.ts.map +1 -0
  22. package/dist/usage-lib/color.js +38 -0
  23. package/dist/usage-lib/color.js.map +1 -0
  24. package/dist/usage-lib/config.d.ts +34 -0
  25. package/dist/usage-lib/config.d.ts.map +1 -0
  26. package/dist/usage-lib/config.js +86 -0
  27. package/dist/usage-lib/config.js.map +1 -0
  28. package/dist/usage-lib/datetime.d.ts +13 -0
  29. package/dist/usage-lib/datetime.d.ts.map +1 -0
  30. package/dist/usage-lib/datetime.js +46 -0
  31. package/dist/usage-lib/datetime.js.map +1 -0
  32. package/dist/usage-lib/extension.d.ts +14 -0
  33. package/dist/usage-lib/extension.d.ts.map +1 -0
  34. package/dist/usage-lib/extension.js +51 -0
  35. package/dist/usage-lib/extension.js.map +1 -0
  36. package/dist/usage-lib/index.d.ts +14 -0
  37. package/dist/usage-lib/index.d.ts.map +1 -0
  38. package/dist/usage-lib/index.js +13 -0
  39. package/dist/usage-lib/index.js.map +1 -0
  40. package/dist/usage-lib/types.d.ts +58 -0
  41. package/dist/usage-lib/types.d.ts.map +1 -0
  42. package/dist/usage-lib/types.js +6 -0
  43. package/dist/usage-lib/types.js.map +1 -0
  44. package/package.json +75 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,177 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.2] - 2026-06-19
11
+
12
+ ### Fixed
13
+
14
+ - upgrade usage lib for custom warning values
15
+
16
+ ## [0.3.1] - 2026-06-17
17
+
18
+ ### Fixed
19
+
20
+ - use correct format for colored values
21
+
22
+ ## [0.3.0] - 2026-06-17
23
+
24
+ ### Added
25
+
26
+ - use warning colors for high quota usage
27
+
28
+ ### Changed
29
+
30
+ - **deps-ci**: bump codecov/codecov-action from 6 to 7 (#42)
31
+ - **deps**: update dependencies
32
+ - **deps**: update dependencies (#39)
33
+ - **deps**: update dependencies (#40)
34
+ - **deps-dev**: update dependencies (#41)
35
+ - **deps**: update dependencies (#43)
36
+ - **deps**: update dependencies (#44)
37
+ - **deps**: update dependencies (#45)
38
+
39
+ ## [0.2.2] - 2026-05-30
40
+
41
+ ### Changed
42
+
43
+ - use @alexanderfortin/pi-usage-lib shared library (#38)
44
+
45
+ ### Fixed
46
+
47
+ - fix ts type issue
48
+
49
+ ## [0.2.1] - 2026-05-29
50
+
51
+ ### Changed
52
+
53
+ - **deps**: update dependencies (#34)
54
+ - **deps**: update dependencies (#35)
55
+
56
+ ### Fixed
57
+
58
+ - add UTC default timezone to support sbx sandboxes
59
+
60
+ ## [0.2.0] - 2026-05-26
61
+
62
+ ### Added
63
+
64
+ - show error codes in footer instead of raw console errors
65
+
66
+ ### Changed
67
+
68
+ - **deps**: update dependencies (#32)
69
+ - **deps**: update dependencies (#33)
70
+
71
+ ## [0.1.14] - 2026-05-18
72
+
73
+ ### Fixed
74
+
75
+ - remove pinned dependency version
76
+
77
+ ## [0.1.13] - 2026-05-18
78
+
79
+ ### Fixed
80
+
81
+ - handle empty/malformed API responses from Pi v0.75.0 fetch changes
82
+
83
+ ## [0.1.12] - 2026-05-08
84
+
85
+ ### Fixed
86
+
87
+ - **deps**: update namespace to @earendil-works
88
+
89
+ ## [0.1.11] - 2026-05-04
90
+
91
+ ### Fixed
92
+
93
+ - **deps**: bump dependencies
94
+
95
+ ## [0.1.10] - 2026-04-26
96
+
97
+ ### Fixed
98
+
99
+ - **deps**: update dependencies to latest versions (#10)
100
+
101
+ ## [0.1.9] - 2026-04-14
102
+
103
+ ### Changed
104
+
105
+ - **deps**: bump @mariozechner/pi-coding-agent (#1)
106
+ - **deps**: update Pi and other deps
107
+
108
+ ### Fixed
109
+
110
+ - bump release
111
+
112
+ ## [0.1.8] - 2026-04-09
113
+
114
+ ### Fixed
115
+
116
+ - correct CHANGELOG format and semantic release configuration
117
+
118
+ ## [0.1.7] - 2026-04-09
119
+
120
+ ### Fixed
121
+
122
+ - add semantic release automated workflow
123
+
124
+ ## [0.1.6] - 2026-04-04
125
+
126
+ ### Changed
127
+
128
+ - Manual version bump for NPM publishing
129
+
130
+ ## [0.1.3] - 2026-04-04
131
+
132
+ ### Changed
133
+
134
+ - remove redundant cleanup for turn_end
135
+ - reduce duplication in set status logic
136
+ - fix readme
137
+
138
+ ## [0.1.2] - 2026-04-03
139
+
140
+ ### Changed
141
+
142
+ - update README with install instructions
143
+ - cleanup release docs
144
+
145
+ ## [0.1.1] - 2026-04-03
146
+
147
+ ### Added
148
+
149
+ - Usage tool for checking Z.ai API token usage quota
150
+ - Auto footer display when using Z.ai models
151
+ - Smart caching (30-second cache to avoid excessive API calls)
152
+ - Temporal-based datetime formatting
153
+ - Time tracking (reset time and remaining time display)
154
+
155
+ ### Changed
156
+
157
+ - Enabled full OIDC publishing (no NPM_TOKEN required)
158
+
159
+ [unreleased]: https://github.com/shaftoe/pi-zai-usage/compare/v0.3.2...HEAD
160
+ [0.3.2]: https://github.com/shaftoe/pi-zai-usage/compare/v0.3.1...v0.3.2
161
+ [0.3.1]: https://github.com/shaftoe/pi-zai-usage/compare/v0.3.0...v0.3.1
162
+ [0.3.0]: https://github.com/shaftoe/pi-zai-usage/compare/v0.2.2...v0.3.0
163
+ [0.2.2]: https://github.com/shaftoe/pi-zai-usage/compare/v0.2.1...v0.2.2
164
+ [0.2.1]: https://github.com/shaftoe/pi-zai-usage/compare/v0.2.0...v0.2.1
165
+ [0.2.0]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.14...v0.2.0
166
+ [0.1.14]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.13...v0.1.14
167
+ [0.1.13]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.12...v0.1.13
168
+ [0.1.12]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.11...v0.1.12
169
+ [0.1.11]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.10...v0.1.11
170
+ [0.1.10]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.9...v0.1.10
171
+ [0.1.9]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.8...v0.1.9
172
+ [0.1.8]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.7...v0.1.8
173
+ [0.1.7]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.6...v0.1.7
174
+ [0.1.6]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.3...v0.1.6
175
+ [0.1.3]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.2...v0.1.3
176
+ [0.1.2]: https://github.com/shaftoe/pi-zai-usage/compare/v0.1.1...v0.1.2
177
+ [0.1.1]: https://github.com/shaftoe/pi-zai-usage/releases/tag/v0.1.1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander Fortin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Pi coding agent Z.ai Usage Extension
2
+
3
+
4
+
5
+ A [Pi coding agent](https://pi.dev/) extension that monitors [Z.ai subscription](https://z.ai/subscribe) API token usage quota and automatically displays usage in the footer when using the Z.ai provider.
6
+
7
+ ![screenshot](./screenshot.png)
8
+
9
+ ## Features
10
+
11
+ - **Auto Footer Display**: Automatically shows usage in the footer when using Z.ai models
12
+ - **Smart Caching**: Caches usage data for 30 seconds to avoid excessive API calls
13
+ - **Time Tracking**: Displays remaining time until quota reset
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pi install npm:@beyona/pi-zai-usage
19
+ ```
20
+
21
+ or if you prefer to build and keep a source checkout locally, clone your fork and run:
22
+
23
+ ```bash
24
+ # Install dependencies
25
+ bun install
26
+
27
+ # Build the extension
28
+ bun run build
29
+
30
+ # Install the extension
31
+ pi install ./
32
+ ```
33
+
34
+ ## Development
35
+
36
+ This project uses modern TypeScript development tooling:
37
+
38
+ - **Bun** - Fast package manager and runtime
39
+ - **TypeScript 6** - Static type checking with strict mode enabled
40
+ - **Biome** - Ultra-fast linter and formatter
41
+
42
+ ```bash
43
+ # Type check
44
+ bun run typecheck
45
+
46
+ # Lint code
47
+ bun run lint
48
+
49
+ # Auto-fix lint issues
50
+ bun run lint:fix
51
+
52
+ # Format code
53
+ bun run format
54
+
55
+ # Run all checks
56
+ bun run check
57
+
58
+ # Watch mode for development
59
+ bun run dev
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ### Automatic Footer Display
65
+
66
+ When using a Z.ai model (e.g., `glm-4.7`, `glm-5`, `glm-5-flash`), the extension automatically displays the usage in the footer (between brackets the time left for the quota to be reset):
67
+
68
+ ```
69
+ Z.ai: 45% (2h 15m 30s)
70
+ ```
71
+
72
+ The footer updates after each AI turn and on model selection changes.
73
+
74
+ ## Configuration
75
+
76
+ No configuration needed. The extension automatically:
77
+ - Uses cached data for 30 seconds to avoid excessive API calls
78
+ - Shows/updates status only when Z.ai models are active
79
+ - Clears status when switching to non-Z.ai models
80
+
81
+ ## API
82
+
83
+ The extension uses the Z.ai API endpoint: `https://api.z.ai/api/monitor/usage/quota/limit`
84
+
85
+ Make sure you're logged in to Z.ai via Pi (`/login for Z.ai`).
86
+
87
+ ## Releasing
88
+
89
+ This project uses automated publishing to NPM via GitHub Actions. The workflow will:
90
+ - Run all CI checks
91
+ - Build the package
92
+ - Publish to NPM with provenance (signed) via [trusted publishing](https://docs.npmjs.com/trusted-publishers)
93
+
94
+ ## Redistribution notes
95
+
96
+ This fork vendors the helper code formerly provided by `@alexanderfortin/pi-usage-lib` so the published `@beyona/pi-zai-usage` package has no runtime dependency on that package. The vendored helper code and original extension are MIT-licensed by Alexander Fortin.
97
+
98
+ ## License
99
+
100
+ MIT
package/dist/api.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Z.ai Usage Checker - Pi Extension
3
+ * Provider-specific API interaction using shared library primitives
4
+ */
5
+ import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
6
+ import { UsageError } from "./usage-lib";
7
+ export interface ZaiUsageResponse {
8
+ data: {
9
+ limits: Array<{
10
+ type: string;
11
+ percentage: number;
12
+ nextResetTime?: number;
13
+ }>;
14
+ };
15
+ }
16
+ export interface ZaiApiError {
17
+ code: number;
18
+ msg: string;
19
+ success: boolean;
20
+ }
21
+ export interface ZaiUsageData {
22
+ percentage: number;
23
+ resetTime?: string;
24
+ timeRemaining?: string;
25
+ }
26
+ /**
27
+ * Fetch Z.ai usage from the API
28
+ *
29
+ * Uses shared library primitives (buildAuthHeaders, safeFetch, safeParseJson)
30
+ * for sandbox-aware auth, error handling, and JSON parsing.
31
+ */
32
+ export declare function getZaiUsage(modelRegistry: Pick<ModelRegistry, "getApiKeyForProvider">): Promise<ZaiUsageData>;
33
+ export { UsageError };
34
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,EAML,UAAU,EACX,MAAM,aAAa,CAAA;AAIpB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE;QACJ,MAAM,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAA;YACZ,UAAU,EAAE,MAAM,CAAA;YAClB,aAAa,CAAC,EAAE,MAAM,CAAA;SACvB,CAAC,CAAA;KACH,CAAA;CACF;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAID;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,GACzD,OAAO,CAAC,YAAY,CAAC,CA+BvB;AAGD,OAAO,EAAE,UAAU,EAAE,CAAA"}
package/dist/api.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Z.ai Usage Checker - Pi Extension
3
+ * Provider-specific API interaction using shared library primitives
4
+ */
5
+ import { buildAuthHeaders, formatInstantFromEpochMs, formatTimeRemainingFromEpochMs, safeFetch, safeParseJson, UsageError, } from "./usage-lib";
6
+ const ZAI_USAGE_API_URL = "https://api.z.ai/api/monitor/usage/quota/limit";
7
+ /**
8
+ * Fetch Z.ai usage from the API
9
+ *
10
+ * Uses shared library primitives (buildAuthHeaders, safeFetch, safeParseJson)
11
+ * for sandbox-aware auth, error handling, and JSON parsing.
12
+ */
13
+ export async function getZaiUsage(modelRegistry) {
14
+ const headers = await buildAuthHeaders(modelRegistry, "zai");
15
+ const response = await safeFetch(ZAI_USAGE_API_URL, { headers });
16
+ const parsed = await safeParseJson(response);
17
+ // Z.ai API can return HTTP 200 with an error body
18
+ // e.g. {"code":401,"msg":"token expired or incorrect","success":false}
19
+ const apiError = parsed;
20
+ if (typeof apiError.success === "boolean" && !apiError.success && apiError.msg) {
21
+ throw new UsageError(`Z.ai API error: ${apiError.msg}`, `api${apiError.code ?? "unknown"}`);
22
+ }
23
+ const data = parsed;
24
+ const tokensLimit = data.data?.limits?.find((limit) => limit.type === "TOKENS_LIMIT");
25
+ if (!tokensLimit) {
26
+ throw new UsageError("TOKENS_LIMIT not found in API response", "nolimit");
27
+ }
28
+ const result = {
29
+ percentage: tokensLimit.percentage,
30
+ };
31
+ if (tokensLimit.nextResetTime) {
32
+ result.resetTime = formatInstantFromEpochMs(tokensLimit.nextResetTime);
33
+ result.timeRemaining = formatTimeRemainingFromEpochMs(tokensLimit.nextResetTime);
34
+ }
35
+ return result;
36
+ }
37
+ // Re-export UsageError for consumers that need it
38
+ export { UsageError };
39
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,8BAA8B,EAC9B,SAAS,EACT,aAAa,EACb,UAAU,GACX,MAAM,aAAa,CAAA;AA0BpB,MAAM,iBAAiB,GAAG,gDAAgD,CAAA;AAE1E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,aAA0D;IAE1D,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;IAE5D,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAEhE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAA;IAE5C,kDAAkD;IAClD,uEAAuE;IACvE,MAAM,QAAQ,GAAG,MAAqB,CAAA;IACtC,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,GAAG,EAAE,CAAC;QAC/E,MAAM,IAAI,UAAU,CAAC,mBAAmB,QAAQ,CAAC,GAAG,EAAE,EAAE,MAAM,QAAQ,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC,CAAA;IAC7F,CAAC;IAED,MAAM,IAAI,GAAG,MAA0B,CAAA;IACvC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC,CAAA;IAErF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,UAAU,CAAC,wCAAwC,EAAE,SAAS,CAAC,CAAA;IAC3E,CAAC;IAED,MAAM,MAAM,GAAiB;QAC3B,UAAU,EAAE,WAAW,CAAC,UAAU;KACnC,CAAA;IAED,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;QAC9B,MAAM,CAAC,SAAS,GAAG,wBAAwB,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;QACtE,MAAM,CAAC,aAAa,GAAG,8BAA8B,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;IAClF,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,kDAAkD;AAClD,OAAO,EAAE,UAAU,EAAE,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Z.ai Usage Checker - Pi Extension
3
+ *
4
+ * Uses createUsageExtension from the shared library to handle all
5
+ * event registration, provider matching, caching, and footer lifecycle.
6
+ */
7
+ import { type ZaiUsageData } from "./api";
8
+ import { createUsageExtension, type Theme } from "./usage-lib";
9
+ /** Render Z.ai usage data into a themed footer string */
10
+ export declare function renderZaiStatus(data: ZaiUsageData, theme: Theme): string;
11
+ declare const extension: ReturnType<typeof createUsageExtension<ZaiUsageData>>;
12
+ export default extension;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAsB,oBAAoB,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAA;AAElF,yDAAyD;AACzD,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAOxE;AAED,QAAA,MAAM,SAAS,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,YAAY,CAAC,CAOjE,CAAA;AAEJ,eAAe,SAAS,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Z.ai Usage Checker - Pi Extension
3
+ *
4
+ * Uses createUsageExtension from the shared library to handle all
5
+ * event registration, provider matching, caching, and footer lifecycle.
6
+ */
7
+ import { getZaiUsage } from "./api";
8
+ import { colorForPercentage, createUsageExtension } from "./usage-lib";
9
+ /** Render Z.ai usage data into a themed footer string */
10
+ export function renderZaiStatus(data, theme) {
11
+ const displayPercentage = Math.round(data.percentage * 10) / 10;
12
+ let status = `${theme.fg("muted", "Z.ai:")}${colorForPercentage(displayPercentage, theme)(`${displayPercentage}%`)}`;
13
+ if (data.resetTime && data.timeRemaining) {
14
+ status += ` ${theme.fg("dim", `(${data.timeRemaining})`)}`;
15
+ }
16
+ return status;
17
+ }
18
+ const extension = createUsageExtension({
19
+ providerPrefix: "zai",
20
+ statusKey: "zai-usage",
21
+ label: "Z.ai",
22
+ fetchUsage: getZaiUsage,
23
+ renderStatus: renderZaiStatus,
24
+ });
25
+ export default extension;
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAqB,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAc,MAAM,aAAa,CAAA;AAElF,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAAC,IAAkB,EAAE,KAAY;IAC9D,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,GAAG,EAAE,CAAA;IAC/D,IAAI,MAAM,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,kBAAkB,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC,GAAG,iBAAiB,GAAG,CAAC,EAAE,CAAA;IACpH,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACzC,MAAM,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC,EAAE,CAAA;IAC5D,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,SAAS,GACb,oBAAoB,CAAe;IACjC,cAAc,EAAE,KAAK;IACrB,SAAS,EAAE,WAAW;IACtB,KAAK,EAAE,MAAM;IACb,UAAU,EAAE,WAAW;IACvB,YAAY,EAAE,eAAe;CAC9B,CAAC,CAAA;AAEJ,eAAe,SAAS,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * API utilities: sandbox-aware auth, safe fetch, structured errors.
4
+ */
5
+ import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
6
+ /** Error thrown by API interactions; carries a short code for footer display */
7
+ export declare class UsageError extends Error {
8
+ readonly code: string;
9
+ readonly name = "UsageError";
10
+ constructor(message: string, code: string);
11
+ }
12
+ /**
13
+ * Build authenticated headers using a 3-way sandbox-aware strategy:
14
+ *
15
+ * 1. Real key present → send "Authorization: Bearer <key>"
16
+ * 2. Key is "proxy-managed" sentinel → don't set auth (sandbox proxy handles it)
17
+ * 3. No key → don't set auth (API returns 401, shown as error)
18
+ *
19
+ * Also sets Accept-Encoding: identity to work around Pi v0.75.0's
20
+ * undici EnvHttpProxyAgent gzip decompression issue.
21
+ */
22
+ export declare function buildAuthHeaders(modelRegistry: Pick<ModelRegistry, "getApiKeyForProvider">, providerName: string, extra?: Record<string, string>): Promise<Record<string, string>>;
23
+ /**
24
+ * Fetch with error wrapping:
25
+ * - Network errors (DNS, timeout, proxy) → UsageError("fetch")
26
+ * - HTTP errors (4xx, 5xx) → UsageError("http{status}")
27
+ */
28
+ export declare function safeFetch(url: string, init?: RequestInit): Promise<Response>;
29
+ /**
30
+ * Parse JSON with error handling:
31
+ * - Empty/malformed body → UsageError("badjson")
32
+ */
33
+ export declare function safeParseJson<T = unknown>(response: Response): Promise<T>;
34
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/usage-lib/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAQpE,gFAAgF;AAChF,qBAAa,UAAW,SAAQ,KAAK;aAIjB,IAAI,EAAE,MAAM;IAH9B,SAAkB,IAAI,gBAAe;gBAEnC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAI/B;AAED;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,EAC1D,YAAY,EAAE,MAAM,EACpB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAajC;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAclF;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAO/E"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * API utilities: sandbox-aware auth, safe fetch, structured errors.
4
+ */
5
+ /** Sentinel value injected by Docker Sandbox proxy when an env var is
6
+ * proxy-managed (listed under environment.proxyManaged in spec.yaml).
7
+ * When the API key reads as this value, the proxy will inject the real
8
+ * Authorization header, so we should not set it ourselves. */
9
+ const PROXY_MANAGED_SENTINEL = "proxy-managed";
10
+ /** Error thrown by API interactions; carries a short code for footer display */
11
+ export class UsageError extends Error {
12
+ code;
13
+ name = "UsageError";
14
+ constructor(message, code) {
15
+ super(message);
16
+ this.code = code;
17
+ }
18
+ }
19
+ /**
20
+ * Build authenticated headers using a 3-way sandbox-aware strategy:
21
+ *
22
+ * 1. Real key present → send "Authorization: Bearer <key>"
23
+ * 2. Key is "proxy-managed" sentinel → don't set auth (sandbox proxy handles it)
24
+ * 3. No key → don't set auth (API returns 401, shown as error)
25
+ *
26
+ * Also sets Accept-Encoding: identity to work around Pi v0.75.0's
27
+ * undici EnvHttpProxyAgent gzip decompression issue.
28
+ */
29
+ export async function buildAuthHeaders(modelRegistry, providerName, extra) {
30
+ const apiKey = await modelRegistry.getApiKeyForProvider(providerName);
31
+ const headers = {
32
+ // Prevent gzip encoding: Pi v0.75.0 routes fetch() through undici's
33
+ // EnvHttpProxyAgent which fails to decompress gzip responses, causing
34
+ // response.json() to see garbled bytes and throw SyntaxError.
35
+ "Accept-Encoding": "identity",
36
+ ...extra,
37
+ };
38
+ if (apiKey && apiKey !== PROXY_MANAGED_SENTINEL) {
39
+ headers.Authorization = `Bearer ${apiKey}`;
40
+ }
41
+ return headers;
42
+ }
43
+ /**
44
+ * Fetch with error wrapping:
45
+ * - Network errors (DNS, timeout, proxy) → UsageError("fetch")
46
+ * - HTTP errors (4xx, 5xx) → UsageError("http{status}")
47
+ */
48
+ export async function safeFetch(url, init) {
49
+ let response;
50
+ try {
51
+ response = await fetch(url, init);
52
+ }
53
+ catch (e) {
54
+ throw new UsageError(`Network error: ${e instanceof Error ? e.message : String(e)}`, "fetch");
55
+ }
56
+ if (!response.ok) {
57
+ throw new UsageError(`API request failed with status ${response.status}`, `http${response.status}`);
58
+ }
59
+ return response;
60
+ }
61
+ /**
62
+ * Parse JSON with error handling:
63
+ * - Empty/malformed body → UsageError("badjson")
64
+ */
65
+ export async function safeParseJson(response) {
66
+ try {
67
+ return (await response.json());
68
+ }
69
+ catch (e) {
70
+ const message = e instanceof SyntaxError ? "empty or malformed response" : String(e);
71
+ throw new UsageError(`API returned invalid JSON (${message})`, "badjson");
72
+ }
73
+ }
74
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/usage-lib/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;8DAG8D;AAC9D,MAAM,sBAAsB,GAAG,eAAe,CAAA;AAE9C,gFAAgF;AAChF,MAAM,OAAO,UAAW,SAAQ,KAAK;IAIjB;IAHA,IAAI,GAAG,YAAY,CAAA;IACrC,YACE,OAAe,EACC,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAA;QAFE,SAAI,GAAJ,IAAI,CAAQ;IAG9B,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,aAA0D,EAC1D,YAAoB,EACpB,KAA8B;IAE9B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAA;IACrE,MAAM,OAAO,GAA2B;QACtC,oEAAoE;QACpE,sEAAsE;QACtE,8DAA8D;QAC9D,iBAAiB,EAAE,UAAU;QAC7B,GAAG,KAAK;KACT,CAAA;IACD,IAAI,MAAM,IAAI,MAAM,KAAK,sBAAsB,EAAE,CAAC;QAChD,OAAO,CAAC,aAAa,GAAG,UAAU,MAAM,EAAE,CAAA;IAC5C,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,IAAkB;IAC7D,IAAI,QAAkB,CAAA;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACnC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,kBAAkB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAC/F,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,UAAU,CAClB,kCAAkC,QAAQ,CAAC,MAAM,EAAE,EACnD,OAAO,QAAQ,CAAC,MAAM,EAAE,CACzB,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAc,QAAkB;IACjE,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAA;IACrC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,CAAC,YAAY,WAAW,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACpF,MAAM,IAAI,UAAU,CAAC,8BAA8B,OAAO,GAAG,EAAE,SAAS,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Generic usage cache with themed footer rendering.
4
+ */
5
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
6
+ import type { FetchUsageFn, RenderErrorFn, RenderStatusFn } from "./types";
7
+ /** Generic cache for usage data with cooldown and themed footer rendering */
8
+ export declare class UsageCache<TData> {
9
+ private readonly statusKey;
10
+ private readonly fetchUsage;
11
+ private readonly renderStatus;
12
+ private readonly cooldownMs;
13
+ private lastData;
14
+ private lastFetchTime;
15
+ private readonly renderError;
16
+ constructor(statusKey: string, label: string, fetchUsage: FetchUsageFn<TData>, renderStatus: RenderStatusFn<TData>, renderError: RenderErrorFn | undefined, cooldownMs?: number);
17
+ /** Update footer status from API or cache */
18
+ updateStatus(ctx: ExtensionContext): Promise<void>;
19
+ /** Clear footer status */
20
+ clear(ctx: ExtensionContext): void;
21
+ }
22
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/usage-lib/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAGvE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAS,MAAM,SAAS,CAAA;AAUjF,6EAA6E;AAC7E,qBAAa,UAAU,CAAC,KAAK;IAMzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAV7B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAe;gBAGxB,SAAS,EAAE,MAAM,EAClC,KAAK,EAAE,MAAM,EACI,UAAU,EAAE,YAAY,CAAC,KAAK,CAAC,EAC/B,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC,EACpD,WAAW,EAAE,aAAa,GAAG,SAAS,EACrB,UAAU,SAAS;IAMtC,6CAA6C;IACvC,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBxD,0BAA0B;IAC1B,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;CAGnC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Generic usage cache with themed footer rendering.
4
+ */
5
+ import { Temporal } from "temporal-polyfill";
6
+ import { UsageError } from "./api";
7
+ /** Build the default error renderer for a given label */
8
+ function defaultRenderError(label) {
9
+ return (error, theme) => {
10
+ const code = error instanceof UsageError ? error.code : "fetch";
11
+ return theme.fg("muted", `${label}:`) + theme.fg("error", `<err:${code}>`);
12
+ };
13
+ }
14
+ /** Generic cache for usage data with cooldown and themed footer rendering */
15
+ export class UsageCache {
16
+ statusKey;
17
+ fetchUsage;
18
+ renderStatus;
19
+ cooldownMs;
20
+ lastData = null;
21
+ lastFetchTime = 0;
22
+ renderError;
23
+ constructor(statusKey, label, fetchUsage, renderStatus, renderError, cooldownMs = 30_000) {
24
+ this.statusKey = statusKey;
25
+ this.fetchUsage = fetchUsage;
26
+ this.renderStatus = renderStatus;
27
+ this.cooldownMs = cooldownMs;
28
+ // Use default error rendering
29
+ this.renderError = renderError ?? defaultRenderError(label);
30
+ }
31
+ /** Update footer status from API or cache */
32
+ async updateStatus(ctx) {
33
+ try {
34
+ const now = Temporal.Now.instant().epochMilliseconds;
35
+ // Use cached data if still fresh
36
+ if (this.lastData && now - this.lastFetchTime < this.cooldownMs) {
37
+ ctx.ui.setStatus(this.statusKey, this.renderStatus(this.lastData, ctx.ui.theme));
38
+ return;
39
+ }
40
+ const data = await this.fetchUsage(ctx.modelRegistry);
41
+ this.lastData = data;
42
+ this.lastFetchTime = now;
43
+ ctx.ui.setStatus(this.statusKey, this.renderStatus(data, ctx.ui.theme));
44
+ }
45
+ catch (error) {
46
+ // Show error code in footer (no console.error)
47
+ const rendered = this.renderError(error, ctx.ui.theme);
48
+ ctx.ui.setStatus(this.statusKey, rendered); // undefined → clears
49
+ }
50
+ }
51
+ /** Clear footer status */
52
+ clear(ctx) {
53
+ ctx.ui.setStatus(this.statusKey, undefined);
54
+ }
55
+ }
56
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/usage-lib/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGlC,yDAAyD;AACzD,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,CAAC,KAAc,EAAE,KAAY,EAAU,EAAE;QAC9C,MAAM,IAAI,GAAG,KAAK,YAAY,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;QAC/D,OAAO,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,IAAI,GAAG,CAAC,CAAA;IAC5E,CAAC,CAAA;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,OAAO,UAAU;IAMF;IAEA;IACA;IAEA;IAVX,QAAQ,GAAiB,IAAI,CAAA;IAC7B,aAAa,GAAG,CAAC,CAAA;IACR,WAAW,CAAe;IAE3C,YACmB,SAAiB,EAClC,KAAa,EACI,UAA+B,EAC/B,YAAmC,EACpD,WAAsC,EACrB,aAAa,MAAM;QALnB,cAAS,GAAT,SAAS,CAAQ;QAEjB,eAAU,GAAV,UAAU,CAAqB;QAC/B,iBAAY,GAAZ,YAAY,CAAuB;QAEnC,eAAU,GAAV,UAAU,CAAS;QAEpC,8BAA8B;QAC9B,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAC7D,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,YAAY,CAAC,GAAqB;QACtC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,iBAAiB,CAAA;YAEpD,iCAAiC;YACjC,IAAI,IAAI,CAAC,QAAQ,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChE,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;gBAChF,OAAM;YACR,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;YACrD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;YACpB,IAAI,CAAC,aAAa,GAAG,GAAG,CAAA;YAExB,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QACzE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,+CAA+C;YAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;YACtD,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA,CAAC,qBAAqB;QAClE,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,KAAK,CAAC,GAAqB;QACzB,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IAC7C,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Color threshold helpers for usage display.
4
+ */
5
+ import type { ColorThresholds, Theme } from "./types";
6
+ /**
7
+ * Get the appropriate TUI color function for a percentage-based usage value.
8
+ *
9
+ * - accent (default) when percentage ≤ warning threshold
10
+ * - warning when percentage > warning threshold
11
+ * - error when percentage ≥ critical threshold
12
+ */
13
+ export declare function colorForPercentage(percentage: number, theme: Theme, thresholds?: ColorThresholds): (text: string) => string;
14
+ /**
15
+ * Get the appropriate TUI color function for a credit / monetary balance value.
16
+ *
17
+ * - accent (default) when credit ≥ warning threshold
18
+ * - warning when credit < warning threshold
19
+ * - error when credit ≤ critical threshold
20
+ */
21
+ export declare function colorForCredit(credit: number, theme: Theme, thresholds?: ColorThresholds): (text: string) => string;
22
+ /** Default color thresholds — re-exported for convenience. */
23
+ export { DEFAULT_COLOR_THRESHOLDS } from "./config";
24
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/usage-lib/color.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAErD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,KAAK,EACZ,UAAU,CAAC,EAAE,eAAe,GAC3B,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAK1B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,KAAK,EACZ,UAAU,CAAC,EAAE,eAAe,GAC3B,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAK1B;AAED,8DAA8D;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Color threshold helpers for usage display.
4
+ */
5
+ import { loadColorThresholds } from "./config";
6
+ /**
7
+ * Get the appropriate TUI color function for a percentage-based usage value.
8
+ *
9
+ * - accent (default) when percentage ≤ warning threshold
10
+ * - warning when percentage > warning threshold
11
+ * - error when percentage ≥ critical threshold
12
+ */
13
+ export function colorForPercentage(percentage, theme, thresholds) {
14
+ const t = thresholds ?? loadColorThresholds();
15
+ if (percentage >= t.percentage.critical)
16
+ return (s) => theme.fg("error", s);
17
+ if (percentage > t.percentage.warning)
18
+ return (s) => theme.fg("warning", s);
19
+ return (s) => theme.fg("accent", s);
20
+ }
21
+ /**
22
+ * Get the appropriate TUI color function for a credit / monetary balance value.
23
+ *
24
+ * - accent (default) when credit ≥ warning threshold
25
+ * - warning when credit < warning threshold
26
+ * - error when credit ≤ critical threshold
27
+ */
28
+ export function colorForCredit(credit, theme, thresholds) {
29
+ const t = thresholds ?? loadColorThresholds();
30
+ if (credit <= t.credit.critical)
31
+ return (s) => theme.fg("error", s);
32
+ if (credit < t.credit.warning)
33
+ return (s) => theme.fg("warning", s);
34
+ return (s) => theme.fg("accent", s);
35
+ }
36
+ /** Default color thresholds — re-exported for convenience. */
37
+ export { DEFAULT_COLOR_THRESHOLDS } from "./config";
38
+ //# sourceMappingURL=color.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/usage-lib/color.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,KAAY,EACZ,UAA4B;IAE5B,MAAM,CAAC,GAAG,UAAU,IAAI,mBAAmB,EAAE,CAAA;IAC7C,IAAI,UAAU,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IACnF,IAAI,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,OAAO;QAAE,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IACnF,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAc,EACd,KAAY,EACZ,UAA4B;IAE5B,MAAM,CAAC,GAAG,UAAU,IAAI,mBAAmB,EAAE,CAAA;IAC7C,IAAI,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;IAC3E,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IAC3E,OAAO,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;AAC7C,CAAC;AAED,8DAA8D;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * User configuration management for color thresholds.
4
+ */
5
+ import type { ColorThresholds } from "./types";
6
+ /** Default color thresholds used when no user overrides are present. */
7
+ export declare const DEFAULT_COLOR_THRESHOLDS: ColorThresholds;
8
+ /** Filename for user-managed settings, relative to the home directory. */
9
+ export declare const SETTINGS_RELATIVE_PATH = ".pi/agent/usage-lib.json";
10
+ /** Resolve the absolute path to the user settings file. */
11
+ export declare function getSettingsFilePath(): string;
12
+ /**
13
+ * Merge a *partial* set of user-provided thresholds into the defaults.
14
+ *
15
+ * Only known, numeric keys are applied — everything else (unknown keys,
16
+ * non-numeric values) is ignored so a malformed file cannot break rendering.
17
+ */
18
+ export declare function mergeThresholds(defaults: ColorThresholds, overrides: unknown): ColorThresholds;
19
+ /**
20
+ * Load color thresholds from `~/.pi/agent/usage-lib.json`, merged with defaults.
21
+ *
22
+ * The file is read **once** per process and cached — subsequent calls return
23
+ * the cached object without touching the filesystem.
24
+ *
25
+ * Returns the built-in defaults if the file is missing, unreadable, or
26
+ * contains invalid JSON.
27
+ */
28
+ export declare function loadColorThresholds(): ColorThresholds;
29
+ /**
30
+ * Reset the internal cache so the next `loadColorThresholds()` call re-reads
31
+ * the settings file. Primarily useful for testing.
32
+ */
33
+ export declare function resetThresholdsCache(): void;
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/usage-lib/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE9C,wEAAwE;AACxE,eAAO,MAAM,wBAAwB,EAAE,eAG7B,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB,6BAA6B,CAAA;AAEhE,2DAA2D;AAC3D,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,OAAO,GAAG,eAAe,CAe9F;AASD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,CAwBrD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * User configuration management for color thresholds.
4
+ */
5
+ import { readFileSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ /** Default color thresholds used when no user overrides are present. */
9
+ export const DEFAULT_COLOR_THRESHOLDS = {
10
+ percentage: { warning: 80, critical: 90 },
11
+ credit: { warning: 5, critical: 1 },
12
+ };
13
+ /** Filename for user-managed settings, relative to the home directory. */
14
+ export const SETTINGS_RELATIVE_PATH = ".pi/agent/usage-lib.json";
15
+ /** Resolve the absolute path to the user settings file. */
16
+ export function getSettingsFilePath() {
17
+ return join(homedir(), SETTINGS_RELATIVE_PATH);
18
+ }
19
+ /**
20
+ * Merge a *partial* set of user-provided thresholds into the defaults.
21
+ *
22
+ * Only known, numeric keys are applied — everything else (unknown keys,
23
+ * non-numeric values) is ignored so a malformed file cannot break rendering.
24
+ */
25
+ export function mergeThresholds(defaults, overrides) {
26
+ const o = (overrides ?? {});
27
+ const pct = o.percentage;
28
+ const credit = o.credit;
29
+ return {
30
+ percentage: {
31
+ warning: pickNumber(pct?.warning, defaults.percentage.warning),
32
+ critical: pickNumber(pct?.critical, defaults.percentage.critical),
33
+ },
34
+ credit: {
35
+ warning: pickNumber(credit?.warning, defaults.credit.warning),
36
+ critical: pickNumber(credit?.critical, defaults.credit.critical),
37
+ },
38
+ };
39
+ }
40
+ /** Return the value if it is a finite number, otherwise the fallback. */
41
+ function pickNumber(value, fallback) {
42
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
43
+ }
44
+ let cachedThresholds = null;
45
+ /**
46
+ * Load color thresholds from `~/.pi/agent/usage-lib.json`, merged with defaults.
47
+ *
48
+ * The file is read **once** per process and cached — subsequent calls return
49
+ * the cached object without touching the filesystem.
50
+ *
51
+ * Returns the built-in defaults if the file is missing, unreadable, or
52
+ * contains invalid JSON.
53
+ */
54
+ export function loadColorThresholds() {
55
+ if (cachedThresholds)
56
+ return cachedThresholds;
57
+ let fileContent;
58
+ try {
59
+ fileContent = readFileSync(getSettingsFilePath(), "utf-8");
60
+ }
61
+ catch {
62
+ // File missing or unreadable — use defaults
63
+ cachedThresholds = { ...DEFAULT_COLOR_THRESHOLDS };
64
+ return cachedThresholds;
65
+ }
66
+ let parsed;
67
+ try {
68
+ parsed = JSON.parse(fileContent);
69
+ }
70
+ catch {
71
+ // Invalid JSON — use defaults
72
+ cachedThresholds = { ...DEFAULT_COLOR_THRESHOLDS };
73
+ return cachedThresholds;
74
+ }
75
+ const thresholds = parsed?.thresholds;
76
+ cachedThresholds = mergeThresholds(DEFAULT_COLOR_THRESHOLDS, thresholds);
77
+ return cachedThresholds;
78
+ }
79
+ /**
80
+ * Reset the internal cache so the next `loadColorThresholds()` call re-reads
81
+ * the settings file. Primarily useful for testing.
82
+ */
83
+ export function resetThresholdsCache() {
84
+ cachedThresholds = null;
85
+ }
86
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/usage-lib/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGhC,wEAAwE;AACxE,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;IACzC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;CAC3B,CAAA;AAEV,0EAA0E;AAC1E,MAAM,CAAC,MAAM,sBAAsB,GAAG,0BAA0B,CAAA;AAEhE,2DAA2D;AAC3D,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAA;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,QAAyB,EAAE,SAAkB;IAC3E,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAA4B,CAAA;IACtD,MAAM,GAAG,GAAG,CAAC,CAAC,UAAiD,CAAA;IAC/D,MAAM,MAAM,GAAG,CAAC,CAAC,MAA6C,CAAA;IAE9D,OAAO;QACL,UAAU,EAAE;YACV,OAAO,EAAE,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;YAC9D,QAAQ,EAAE,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC;SAClE;QACD,MAAM,EAAE;YACN,OAAO,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;YAC7D,QAAQ,EAAE,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;SACjE;KACF,CAAA;AACH,CAAC;AAED,yEAAyE;AACzE,SAAS,UAAU,CAAC,KAAc,EAAE,QAAgB;IAClD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAA;AAC/E,CAAC;AAED,IAAI,gBAAgB,GAA2B,IAAI,CAAA;AAEnD;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB;IACjC,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAA;IAE7C,IAAI,WAAmB,CAAA;IACvB,IAAI,CAAC;QACH,WAAW,GAAG,YAAY,CAAC,mBAAmB,EAAE,EAAE,OAAO,CAAC,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,4CAA4C;QAC5C,gBAAgB,GAAG,EAAE,GAAG,wBAAwB,EAAE,CAAA;QAClD,OAAO,gBAAgB,CAAA;IACzB,CAAC;IAED,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;QAC9B,gBAAgB,GAAG,EAAE,GAAG,wBAAwB,EAAE,CAAA;QAClD,OAAO,gBAAgB,CAAA;IACzB,CAAC;IAED,MAAM,UAAU,GAAI,MAAyC,EAAE,UAAU,CAAA;IACzE,gBAAgB,GAAG,eAAe,CAAC,wBAAwB,EAAE,UAAU,CAAC,CAAA;IACxE,OAAO,gBAAgB,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,gBAAgB,GAAG,IAAI,CAAA;AACzB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Date/time formatting utilities using Temporal.
4
+ */
5
+ /**
6
+ * Format an instant (epoch milliseconds) as a localized date/time string
7
+ */
8
+ export declare function formatInstantFromEpochMs(ms: number): string;
9
+ /**
10
+ * Format the remaining time from an instant (epoch milliseconds) to now
11
+ */
12
+ export declare function formatTimeRemainingFromEpochMs(ms: number): string;
13
+ //# sourceMappingURL=datetime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datetime.d.ts","sourceRoot":"","sources":["../../src/usage-lib/datetime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAa3D;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAuBjE"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Date/time formatting utilities using Temporal.
4
+ */
5
+ import { Temporal } from "temporal-polyfill";
6
+ /**
7
+ * Format an instant (epoch milliseconds) as a localized date/time string
8
+ */
9
+ export function formatInstantFromEpochMs(ms) {
10
+ const instant = Temporal.Instant.fromEpochMilliseconds(ms);
11
+ const zonedDateTime = instant.toZonedDateTimeISO(Temporal.Now.timeZoneId() ?? "UTC");
12
+ return zonedDateTime.toLocaleString(undefined, {
13
+ weekday: "short",
14
+ day: "2-digit",
15
+ month: "short",
16
+ year: "numeric",
17
+ hour: "2-digit",
18
+ minute: "2-digit",
19
+ second: "2-digit",
20
+ timeZoneName: "short",
21
+ });
22
+ }
23
+ /**
24
+ * Format the remaining time from an instant (epoch milliseconds) to now
25
+ */
26
+ export function formatTimeRemainingFromEpochMs(ms) {
27
+ const now = Temporal.Now.instant();
28
+ const target = Temporal.Instant.fromEpochMilliseconds(ms);
29
+ // If the target time is in the past, return zero
30
+ if (target.epochMilliseconds < now.epochMilliseconds) {
31
+ return "0h 0m 0s";
32
+ }
33
+ const duration = target.since(now);
34
+ const totalSeconds = Math.round(Math.abs(duration.seconds));
35
+ const hours = Math.floor(totalSeconds / 3600);
36
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
37
+ const seconds = totalSeconds % 60;
38
+ if (hours > 0) {
39
+ return `${hours}h ${minutes}m ${seconds}s`;
40
+ }
41
+ if (minutes > 0) {
42
+ return `${minutes}m ${seconds}s`;
43
+ }
44
+ return `${seconds}s`;
45
+ }
46
+ //# sourceMappingURL=datetime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datetime.js","sourceRoot":"","sources":["../../src/usage-lib/datetime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE5C;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,EAAU;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAA;IAC1D,MAAM,aAAa,GAAG,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,KAAK,CAAC,CAAA;IACpF,OAAO,aAAa,CAAC,cAAc,CAAC,SAAS,EAAE;QAC7C,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,OAAO;QACd,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B,CAAC,EAAU;IACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAA;IAEzD,iDAAiD;IACjD,IAAI,MAAM,CAAC,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACrD,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAElC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IACtD,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE,CAAA;IAEjC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO,GAAG,CAAA;IAC5C,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAA;IAClC,CAAC;IACD,OAAO,GAAG,OAAO,GAAG,CAAA;AACtB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Factory for usage-monitoring Pi extensions.
4
+ */
5
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+ import type { UsageExtensionConfig } from "./types";
7
+ /**
8
+ * Create a Pi usage extension from a configuration object.
9
+ *
10
+ * Handles all boilerplate: event registration, provider matching,
11
+ * cache management, and footer lifecycle.
12
+ */
13
+ export declare function createUsageExtension<TData>(config: UsageExtensionConfig<TData>): (pi: ExtensionAPI) => void;
14
+ //# sourceMappingURL=extension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../src/usage-lib/extension.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,iCAAiC,CAAA;AAErF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAYnD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,oBAAoB,CAAC,KAAK,CAAC,IAGnD,IAAI,YAAY,UAsC3C"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Factory for usage-monitoring Pi extensions.
4
+ */
5
+ import { UsageCache } from "./cache";
6
+ /** Check if a provider name matches the given prefix (case-insensitive) */
7
+ function isProviderMatch(provider, prefix) {
8
+ return provider?.toLowerCase().startsWith(prefix) ?? false;
9
+ }
10
+ /** Check if the current model's provider matches the given prefix */
11
+ function isCurrentProvider(ctx, prefix) {
12
+ return isProviderMatch(ctx.model?.provider, prefix);
13
+ }
14
+ /**
15
+ * Create a Pi usage extension from a configuration object.
16
+ *
17
+ * Handles all boilerplate: event registration, provider matching,
18
+ * cache management, and footer lifecycle.
19
+ */
20
+ export function createUsageExtension(config) {
21
+ const { providerPrefix, statusKey, label, cooldownMs = 30_000 } = config;
22
+ return function extension(pi) {
23
+ const cache = new UsageCache(statusKey, label, config.fetchUsage, config.renderStatus, config.renderError, cooldownMs);
24
+ // Show footer at session start (only when using matching model)
25
+ pi.on("session_start", async (_event, ctx) => {
26
+ if (isCurrentProvider(ctx, providerPrefix)) {
27
+ await cache.updateStatus(ctx);
28
+ }
29
+ });
30
+ // Update footer on model select
31
+ pi.on("model_select", async (event, ctx) => {
32
+ if (isProviderMatch(event.model.provider, providerPrefix)) {
33
+ await cache.updateStatus(ctx);
34
+ }
35
+ else {
36
+ cache.clear(ctx);
37
+ }
38
+ });
39
+ // Update footer after each turn
40
+ pi.on("turn_end", async (_event, ctx) => {
41
+ if (isCurrentProvider(ctx, providerPrefix)) {
42
+ await cache.updateStatus(ctx);
43
+ }
44
+ });
45
+ // Clear footer on session shutdown
46
+ pi.on("session_shutdown", async (_event, ctx) => {
47
+ cache.clear(ctx);
48
+ });
49
+ };
50
+ }
51
+ //# sourceMappingURL=extension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../src/usage-lib/extension.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGpC,2EAA2E;AAC3E,SAAS,eAAe,CAAC,QAA4B,EAAE,MAAc;IACnE,OAAO,QAAQ,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,CAAA;AAC5D,CAAC;AAED,qEAAqE;AACrE,SAAS,iBAAiB,CAAC,GAAqB,EAAE,MAAc;IAC9D,OAAO,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAQ,MAAmC;IAC7E,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,GAAG,MAAM,CAAA;IAExE,OAAO,SAAS,SAAS,CAAC,EAAgB;QACxC,MAAM,KAAK,GAAG,IAAI,UAAU,CAC1B,SAAS,EACT,KAAK,EACL,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,WAAW,EAClB,UAAU,CACX,CAAA;QAED,gEAAgE;QAChE,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YAC3C,IAAI,iBAAiB,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC3C,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,gCAAgC;QAChC,EAAE,CAAC,EAAE,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YACzC,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC1D,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;YAC/B,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAClB,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,gCAAgC;QAChC,EAAE,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YACtC,IAAI,iBAAiB,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,CAAC;gBAC3C,MAAM,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;YAC/B,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,mCAAmC;QACnC,EAAE,CAAC,EAAE,CAAC,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YAC9C,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAClB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Vendored usage helper public API.
3
+ *
4
+ * Source adapted from @alexanderfortin/pi-usage-lib under the MIT license so
5
+ * @beyona/pi-zai-usage can be redistributed without that runtime dependency.
6
+ */
7
+ export { buildAuthHeaders, safeFetch, safeParseJson, UsageError } from "./api";
8
+ export { UsageCache } from "./cache";
9
+ export { colorForCredit, colorForPercentage } from "./color";
10
+ export { DEFAULT_COLOR_THRESHOLDS, getSettingsFilePath, loadColorThresholds, mergeThresholds, resetThresholdsCache, } from "./config";
11
+ export { formatInstantFromEpochMs, formatTimeRemainingFromEpochMs } from "./datetime";
12
+ export { createUsageExtension } from "./extension";
13
+ export type { ColorThresholds, FetchUsageFn, RenderErrorFn, RenderStatusFn, Theme, UsageExtensionConfig, } from "./types";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/usage-lib/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAA;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAElD,YAAY,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,EACL,oBAAoB,GACrB,MAAM,SAAS,CAAA"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Vendored usage helper public API.
3
+ *
4
+ * Source adapted from @alexanderfortin/pi-usage-lib under the MIT license so
5
+ * @beyona/pi-zai-usage can be redistributed without that runtime dependency.
6
+ */
7
+ export { buildAuthHeaders, safeFetch, safeParseJson, UsageError } from "./api";
8
+ export { UsageCache } from "./cache";
9
+ export { colorForCredit, colorForPercentage } from "./color";
10
+ export { DEFAULT_COLOR_THRESHOLDS, getSettingsFilePath, loadColorThresholds, mergeThresholds, resetThresholdsCache, } from "./config";
11
+ export { formatInstantFromEpochMs, formatTimeRemainingFromEpochMs } from "./datetime";
12
+ export { createUsageExtension } from "./extension";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/usage-lib/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAC5D,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAA;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Shared public API types for usage monitoring helpers.
4
+ */
5
+ import type { ExtensionContext, ModelRegistry } from "@earendil-works/pi-coding-agent";
6
+ /** Theme helper — matches ctx.ui.theme */
7
+ export type Theme = ExtensionContext["ui"]["theme"];
8
+ /**
9
+ * Color thresholds for usage display.
10
+ *
11
+ * Users can override any subset of these values via the
12
+ * `~/.pi/agent/usage-lib.json` settings file.
13
+ */
14
+ export interface ColorThresholds {
15
+ /** Percentage-based usage thresholds (0–100) */
16
+ percentage: {
17
+ /** Above this % → **warning** color (default: 80) */
18
+ warning: number;
19
+ /** At or above this % → **critical** color (default: 90) */
20
+ critical: number;
21
+ };
22
+ /** Credit / monetary balance thresholds (in USD) */
23
+ credit: {
24
+ /** Below this → **warning** color (default: 5) */
25
+ warning: number;
26
+ /** At or below this → **critical** color (default: 1) */
27
+ critical: number;
28
+ };
29
+ }
30
+ /** Fetch function signature */
31
+ export type FetchUsageFn<TData> = (modelRegistry: Pick<ModelRegistry, "getApiKeyForProvider">) => Promise<TData>;
32
+ /** Render usage data into a themed footer string */
33
+ export type RenderStatusFn<TData> = (data: TData, theme: Theme) => string;
34
+ /** Render an error into a themed footer string. Return undefined to clear the footer. */
35
+ export type RenderErrorFn = (error: unknown, theme: Theme) => string | undefined;
36
+ /** Configuration to define a usage extension */
37
+ export interface UsageExtensionConfig<TData> {
38
+ /** Provider name prefix for matching (e.g. "zai", "deepseek") */
39
+ providerPrefix: string;
40
+ /** Status key for ctx.ui.setStatus() (e.g. "zai-usage") */
41
+ statusKey: string;
42
+ /** Display label for footer prefix (e.g. "MyProvider") */
43
+ label: string;
44
+ /** Cache cooldown in ms (default: 30_000) */
45
+ cooldownMs?: number;
46
+ /** Fetch usage data from the provider API */
47
+ fetchUsage: FetchUsageFn<TData>;
48
+ /** Render usage data into a themed footer string */
49
+ renderStatus: RenderStatusFn<TData>;
50
+ /**
51
+ * Render an error into a themed footer string.
52
+ * Default: shows themed `<err:code>` using UsageError.code,
53
+ * falling back to "fetch" for unknown errors.
54
+ * Return undefined to clear the footer instead.
55
+ */
56
+ renderError?: RenderErrorFn;
57
+ }
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/usage-lib/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAEtF,0CAA0C;AAC1C,MAAM,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,gDAAgD;IAChD,UAAU,EAAE;QACV,qDAAqD;QACrD,OAAO,EAAE,MAAM,CAAA;QACf,4DAA4D;QAC5D,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;IACD,oDAAoD;IACpD,MAAM,EAAE;QACN,kDAAkD;QAClD,OAAO,EAAE,MAAM,CAAA;QACf,yDAAyD;QACzD,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,+BAA+B;AAC/B,MAAM,MAAM,YAAY,CAAC,KAAK,IAAI,CAChC,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,sBAAsB,CAAC,KACvD,OAAO,CAAC,KAAK,CAAC,CAAA;AAEnB,oDAAoD;AACpD,MAAM,MAAM,cAAc,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,KAAK,MAAM,CAAA;AAEzE,yFAAyF;AACzF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,KAAK,MAAM,GAAG,SAAS,CAAA;AAEhF,gDAAgD;AAChD,MAAM,WAAW,oBAAoB,CAAC,KAAK;IACzC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAA;IAEtB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAA;IAEjB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IAEb,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,6CAA6C;IAC7C,UAAU,EAAE,YAAY,CAAC,KAAK,CAAC,CAAA;IAE/B,oDAAoD;IACpD,YAAY,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;IAEnC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,aAAa,CAAA;CAC5B"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Vendored from @alexanderfortin/pi-usage-lib (MIT).
3
+ * Shared public API types for usage monitoring helpers.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/usage-lib/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "@beyona/pi-zai-usage",
3
+ "version": "0.3.2",
4
+ "description": "Pi extension for monitoring Z.ai API token usage quota",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "dev": "bun --watch src/index.ts",
16
+ "build": "bun run typecheck && bun run build:tsc",
17
+ "build:tsc": "tsc",
18
+ "typecheck": "tsc --noEmit --project tsconfig.test.json",
19
+ "lint": "biome check src/ tests/",
20
+ "lint:fix": "biome check --write src/ tests/",
21
+ "format": "biome format --write src/",
22
+ "check": "bun run typecheck && bun run lint",
23
+ "test": "bun test",
24
+ "test:coverage": "bun test --coverage --coverage-reporter=lcov",
25
+ "release": "semantic-release",
26
+ "release:dry-run": "semantic-release --dry-run"
27
+ },
28
+ "dependencies": {
29
+ "temporal-polyfill": "^1.0.1"
30
+ },
31
+ "devDependencies": {
32
+ "@alexanderfortin/semantic-release-keep-a-changelog": "^0.4.4",
33
+ "@biomejs/biome": "^2.5.1",
34
+ "@semantic-release/commit-analyzer": "^13.0.1",
35
+ "@semantic-release/exec": "^7.1.0",
36
+ "@semantic-release/git": "^10.0.1",
37
+ "@semantic-release/github": "^12.0.8",
38
+ "@semantic-release/npm": "^13.1.5",
39
+ "@types/bun": "^1.3.14",
40
+ "semantic-release": "^25.0.5",
41
+ "typescript": "^6.0.3"
42
+ },
43
+ "peerDependencies": {
44
+ "@earendil-works/pi-coding-agent": "^0.80.2",
45
+ "@earendil-works/pi-tui": "^0.80.2"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "files": [
51
+ "dist",
52
+ "package.json",
53
+ "README.md",
54
+ "CHANGELOG.md",
55
+ "LICENSE"
56
+ ],
57
+ "keywords": [
58
+ "pi-package",
59
+ "pi-extension",
60
+ "zai",
61
+ "Z.ai",
62
+ "usage-monitoring",
63
+ "api-quota"
64
+ ],
65
+ "pi": {
66
+ "extensions": [
67
+ "./dist/index.js"
68
+ ]
69
+ },
70
+ "author": "Alexander Fortin",
71
+ "contributors": [
72
+ "beyona"
73
+ ],
74
+ "license": "MIT"
75
+ }