@mdrv/opencode-quota 262.0.0

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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +189 -0
  3. package/bin/copilot-quota.ts +374 -0
  4. package/bin/glm-quota.ts +467 -0
  5. package/bin/install.js +439 -0
  6. package/bin/kimi-quota.ts +314 -0
  7. package/dist/bin/copilot-quota.d.ts +8 -0
  8. package/dist/bin/copilot-quota.d.ts.map +1 -0
  9. package/dist/bin/copilot-quota.js +298 -0
  10. package/dist/bin/copilot-quota.js.map +1 -0
  11. package/dist/bin/glm-quota.d.ts +8 -0
  12. package/dist/bin/glm-quota.d.ts.map +1 -0
  13. package/dist/bin/glm-quota.js +367 -0
  14. package/dist/bin/glm-quota.js.map +1 -0
  15. package/dist/bin/kimi-quota.d.ts +3 -0
  16. package/dist/bin/kimi-quota.d.ts.map +1 -0
  17. package/dist/bin/kimi-quota.js +241 -0
  18. package/dist/bin/kimi-quota.js.map +1 -0
  19. package/dist/src/api/client.d.ts +76 -0
  20. package/dist/src/api/client.d.ts.map +1 -0
  21. package/dist/src/api/client.js +203 -0
  22. package/dist/src/api/client.js.map +1 -0
  23. package/dist/src/api/endpoints.d.ts +22 -0
  24. package/dist/src/api/endpoints.d.ts.map +1 -0
  25. package/dist/src/api/endpoints.js +41 -0
  26. package/dist/src/api/endpoints.js.map +1 -0
  27. package/dist/src/api/platforms.d.ts +20 -0
  28. package/dist/src/api/platforms.d.ts.map +1 -0
  29. package/dist/src/api/platforms.js +38 -0
  30. package/dist/src/api/platforms.js.map +1 -0
  31. package/dist/src/index.d.ts +10 -0
  32. package/dist/src/index.d.ts.map +1 -0
  33. package/dist/src/index.js +723 -0
  34. package/dist/src/index.js.map +1 -0
  35. package/dist/src/shared/logging.d.ts +7 -0
  36. package/dist/src/shared/logging.d.ts.map +1 -0
  37. package/dist/src/shared/logging.js +29 -0
  38. package/dist/src/shared/logging.js.map +1 -0
  39. package/dist/src/utils/box-constants.d.ts +43 -0
  40. package/dist/src/utils/box-constants.d.ts.map +1 -0
  41. package/dist/src/utils/box-constants.js +43 -0
  42. package/dist/src/utils/box-constants.js.map +1 -0
  43. package/dist/src/utils/date-formatter.d.ts +17 -0
  44. package/dist/src/utils/date-formatter.d.ts.map +1 -0
  45. package/dist/src/utils/date-formatter.js +33 -0
  46. package/dist/src/utils/date-formatter.js.map +1 -0
  47. package/dist/src/utils/error-formatter.d.ts +17 -0
  48. package/dist/src/utils/error-formatter.d.ts.map +1 -0
  49. package/dist/src/utils/error-formatter.js +60 -0
  50. package/dist/src/utils/error-formatter.js.map +1 -0
  51. package/dist/src/utils/progress-bar.d.ts +35 -0
  52. package/dist/src/utils/progress-bar.d.ts.map +1 -0
  53. package/dist/src/utils/progress-bar.js +43 -0
  54. package/dist/src/utils/progress-bar.js.map +1 -0
  55. package/dist/src/utils/reset-timer.d.ts +11 -0
  56. package/dist/src/utils/reset-timer.d.ts.map +1 -0
  57. package/dist/src/utils/reset-timer.js +32 -0
  58. package/dist/src/utils/reset-timer.js.map +1 -0
  59. package/dist/src/utils/time-window.d.ts +30 -0
  60. package/dist/src/utils/time-window.d.ts.map +1 -0
  61. package/dist/src/utils/time-window.js +34 -0
  62. package/dist/src/utils/time-window.js.map +1 -0
  63. package/dist/tests/error-handling/api-errors.test.d.ts +7 -0
  64. package/dist/tests/error-handling/api-errors.test.d.ts.map +1 -0
  65. package/dist/tests/error-handling/api-errors.test.js +110 -0
  66. package/dist/tests/error-handling/api-errors.test.js.map +1 -0
  67. package/dist/tests/error-handling/auth-errors.test.d.ts +7 -0
  68. package/dist/tests/error-handling/auth-errors.test.d.ts.map +1 -0
  69. package/dist/tests/error-handling/auth-errors.test.js +110 -0
  70. package/dist/tests/error-handling/auth-errors.test.js.map +1 -0
  71. package/dist/tests/error-handling/network-errors.test.d.ts +7 -0
  72. package/dist/tests/error-handling/network-errors.test.d.ts.map +1 -0
  73. package/dist/tests/error-handling/network-errors.test.js +94 -0
  74. package/dist/tests/error-handling/network-errors.test.js.map +1 -0
  75. package/dist/tests/error-handling/parse-errors.test.d.ts +7 -0
  76. package/dist/tests/error-handling/parse-errors.test.d.ts.map +1 -0
  77. package/dist/tests/error-handling/parse-errors.test.js +87 -0
  78. package/dist/tests/error-handling/parse-errors.test.js.map +1 -0
  79. package/dist/tests/error-handling/token-sanitization.test.d.ts +2 -0
  80. package/dist/tests/error-handling/token-sanitization.test.d.ts.map +1 -0
  81. package/dist/tests/error-handling/token-sanitization.test.js +59 -0
  82. package/dist/tests/error-handling/token-sanitization.test.js.map +1 -0
  83. package/dist/tests/functional/date-formatter.test.d.ts +5 -0
  84. package/dist/tests/functional/date-formatter.test.d.ts.map +1 -0
  85. package/dist/tests/functional/date-formatter.test.js +46 -0
  86. package/dist/tests/functional/date-formatter.test.js.map +1 -0
  87. package/dist/tests/functional/progress-bar.test.d.ts +5 -0
  88. package/dist/tests/functional/progress-bar.test.d.ts.map +1 -0
  89. package/dist/tests/functional/progress-bar.test.js +82 -0
  90. package/dist/tests/functional/progress-bar.test.js.map +1 -0
  91. package/dist/tests/functional/reset-timer.test.d.ts +6 -0
  92. package/dist/tests/functional/reset-timer.test.d.ts.map +1 -0
  93. package/dist/tests/functional/reset-timer.test.js +67 -0
  94. package/dist/tests/functional/reset-timer.test.js.map +1 -0
  95. package/dist/tests/functional/time-window.test.d.ts +5 -0
  96. package/dist/tests/functional/time-window.test.d.ts.map +1 -0
  97. package/dist/tests/functional/time-window.test.js +46 -0
  98. package/dist/tests/functional/time-window.test.js.map +1 -0
  99. package/dist/tests/integration/box-alignment.test.d.ts +8 -0
  100. package/dist/tests/integration/box-alignment.test.d.ts.map +1 -0
  101. package/dist/tests/integration/box-alignment.test.js +238 -0
  102. package/dist/tests/integration/box-alignment.test.js.map +1 -0
  103. package/dist/tests/integration/error-handling.test.d.ts +2 -0
  104. package/dist/tests/integration/error-handling.test.d.ts.map +1 -0
  105. package/dist/tests/integration/error-handling.test.js +36 -0
  106. package/dist/tests/integration/error-handling.test.js.map +1 -0
  107. package/dist/tests/integration/installer-config.test.d.ts +2 -0
  108. package/dist/tests/integration/installer-config.test.d.ts.map +1 -0
  109. package/dist/tests/integration/installer-config.test.js +65 -0
  110. package/dist/tests/integration/installer-config.test.js.map +1 -0
  111. package/dist/tests/integration/plugin-catch-block.test.d.ts +2 -0
  112. package/dist/tests/integration/plugin-catch-block.test.d.ts.map +1 -0
  113. package/dist/tests/integration/plugin-catch-block.test.js +134 -0
  114. package/dist/tests/integration/plugin-catch-block.test.js.map +1 -0
  115. package/dist/tests/integration/reset-time-display.test.d.ts +6 -0
  116. package/dist/tests/integration/reset-time-display.test.d.ts.map +1 -0
  117. package/dist/tests/integration/reset-time-display.test.js +138 -0
  118. package/dist/tests/integration/reset-time-display.test.js.map +1 -0
  119. package/dist/tests/module/http-client.test.d.ts +2 -0
  120. package/dist/tests/module/http-client.test.d.ts.map +1 -0
  121. package/dist/tests/module/http-client.test.js +49 -0
  122. package/dist/tests/module/http-client.test.js.map +1 -0
  123. package/dist/tests/module/platform-detection.test.d.ts +5 -0
  124. package/dist/tests/module/platform-detection.test.d.ts.map +1 -0
  125. package/dist/tests/module/platform-detection.test.js +48 -0
  126. package/dist/tests/module/platform-detection.test.js.map +1 -0
  127. package/integration/agents/copilot-quota-exec.md +20 -0
  128. package/integration/agents/glm-quota-exec.md +20 -0
  129. package/integration/command/copilot_quota.md +6 -0
  130. package/integration/command/glm_quota.md +6 -0
  131. package/integration/skills/copilot-quota/SKILL.md +11 -0
  132. package/integration/skills/glm-quota/SKILL.md +11 -0
  133. package/package.json +69 -0
@@ -0,0 +1,314 @@
1
+ #!/usr/bin/env bun
2
+ import { configureLogging, getLogger } from '../src/shared/logging.js'
3
+
4
+ const logger = getLogger('opencode-quota.cli.kimi')
5
+ const AUTH_JSON_PATH = `${process.env.HOME}/.local/share/opencode/auth.json`
6
+
7
+ interface ApiResponse<T> {
8
+ code?: number
9
+ msg?: string
10
+ data?: T
11
+ success?: boolean
12
+ }
13
+
14
+ interface LimitDetail {
15
+ limit?: number | null
16
+ used?: number | null
17
+ remaining?: number | null
18
+ reset_at?: string | null
19
+ resetTime?: string | null
20
+ }
21
+
22
+ interface LimitWindow {
23
+ duration?: number | null
24
+ timeUnit?: string | null
25
+ }
26
+
27
+ interface LimitItem {
28
+ name?: string | null
29
+ title?: string | null
30
+ scope?: string | null
31
+ window?: LimitWindow | null
32
+ detail?: LimitDetail | null
33
+ }
34
+
35
+ interface UsageData {
36
+ limit?: number | null
37
+ used?: number | null
38
+ remaining?: number | null
39
+ reset_at?: string | null
40
+ resetTime?: string | null
41
+ }
42
+
43
+ interface BalanceResponse {
44
+ usage?: UsageData | null
45
+ limits?: LimitItem[] | null
46
+ }
47
+
48
+ async function getCredentials(): Promise<string | null> {
49
+ try {
50
+ const authResp = await fetch(`file://${AUTH_JSON_PATH}`)
51
+ if (!authResp.ok) {
52
+ throw new Error('Failed to read auth.json')
53
+ }
54
+ const auth = await authResp.text()
55
+ const authJson = JSON.parse(auth)
56
+ const kimiData = authJson['kimi-for-coding'] || authJson.kimi || authJson.moonshot
57
+ if (!kimiData) {
58
+ logger.error('opencode-kimi-quota: Not configured. Run: opencode connect kimi-for-coding')
59
+ return null
60
+ }
61
+ const kimiKey = typeof kimiData === 'string' ? kimiData : kimiData.key || kimiData.token
62
+ if (!kimiKey) {
63
+ logger.error('opencode-kimi-quota: Not configured. Run: opencode connect kimi-for-coding')
64
+ return null
65
+ }
66
+ return kimiKey
67
+ } catch {
68
+ logger.error('opencode-kimi-quota: Not configured. Run: opencode connect kimi')
69
+ return null
70
+ }
71
+ }
72
+
73
+ async function queryBalance(apiKey: string): Promise<BalanceResponse> {
74
+ const url = 'https://api.kimi.com/coding/v1/usages'
75
+ logger.debug(`Making request to: ${url}`)
76
+ logger.debug(`Method: GET`)
77
+ logger.debug(`Authorization: ${apiKey.substring(0, 20)}***`)
78
+
79
+ const response = await fetch(url, {
80
+ method: 'GET',
81
+ headers: {
82
+ 'Authorization': `Bearer ${apiKey}`,
83
+ 'Accept': 'application/json',
84
+ },
85
+ })
86
+
87
+ const statusCode = response.status
88
+ const body = await response.text()
89
+
90
+ logger.debug(`← Response: ${statusCode}, body: ${body.length} bytes`)
91
+
92
+ if (statusCode === 200) {
93
+ try {
94
+ const result = JSON.parse(body)
95
+ return {
96
+ usage: result.usage || null,
97
+ limits: result.limits || [],
98
+ }
99
+ } catch (error) {
100
+ logger.debug(`Failed to parse response: ${error}`)
101
+ }
102
+ }
103
+
104
+ if (statusCode !== 200 && statusCode !== 401 && statusCode !== 403 && statusCode !== 404) {
105
+ throw new Error(`HTTP ${statusCode}: ${body.substring(0, 200)}`)
106
+ }
107
+
108
+ return {
109
+ usage: null,
110
+ limits: [],
111
+ }
112
+ }
113
+
114
+ function formatDurationCompact(ms: number | string | undefined): string {
115
+ if (!ms) return ''
116
+
117
+ let timestamp: number
118
+ if (typeof ms === 'string') {
119
+ timestamp = new Date(ms).getTime()
120
+ } else {
121
+ timestamp = ms
122
+ }
123
+
124
+ const now = Date.now()
125
+ const diffMs = timestamp - now
126
+
127
+ if (diffMs < 0) {
128
+ return 'now'
129
+ }
130
+
131
+ const days = Math.floor(diffMs / (1000 * 60 * 60 * 24))
132
+ const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
133
+ const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60))
134
+ const seconds = Math.floor((diffMs % (1000 * 60)) / 1000)
135
+
136
+ const parts = []
137
+ if (days > 0) parts.push(`${days}d`)
138
+ if (hours > 0) parts.push(`${hours}h`)
139
+ if (minutes > 0) parts.push(`${minutes}m`)
140
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`)
141
+
142
+ return parts.join(' ')
143
+ }
144
+
145
+ function formatLimitLabel(item: LimitItem): string {
146
+ const window = item.window || {}
147
+ const duration = window.duration
148
+ let timeUnit = window.timeUnit
149
+
150
+ // Handle "TIME_UNIT_" prefix
151
+ if (timeUnit && timeUnit.startsWith('TIME_UNIT_')) {
152
+ timeUnit = timeUnit.replace('TIME_UNIT_', '')
153
+ }
154
+
155
+ if (duration == null) {
156
+ return item.name || item.title || item.scope || 'Unknown'
157
+ }
158
+
159
+ if (timeUnit === 'MINUTE') {
160
+ if (duration >= 60 && duration % 60 === 0) {
161
+ return `${duration / 60}h limit`
162
+ }
163
+ return `${duration}m limit`
164
+ }
165
+ if (timeUnit === 'HOUR') {
166
+ return `${duration}h limit`
167
+ }
168
+ if (timeUnit === 'DAY') {
169
+ return `${duration}d limit`
170
+ }
171
+
172
+ return `${duration} ${timeUnit} limit`
173
+ }
174
+
175
+ function formatUsage(balance: BalanceResponse): void {
176
+ console.log('')
177
+ console.log('Kimi Coding Plan Usage Statistics')
178
+ console.log('')
179
+
180
+ if (!balance.usage && (!balance.limits || balance.limits.length === 0)) {
181
+ console.log('No usage data available.')
182
+ console.log('')
183
+ console.log('Possible reasons:')
184
+ console.log(' - Not configured: Run `opencode connect kimi-for-coding`')
185
+ console.log(' - API key format mismatch')
186
+ console.log(' - No quota usage data available yet')
187
+ console.log('')
188
+ console.log('Please check your usage at:')
189
+ console.log(' https://platform.moonshot.ai/console')
190
+ console.log(' https://kimi-ai.chat/code/console')
191
+ return
192
+ }
193
+
194
+ // Display main usage summary
195
+ if (balance.usage) {
196
+ const { limit, used, remaining, reset_at, resetTime } = balance.usage
197
+ if (limit != null && used != null) {
198
+ const percentage = (used / limit) * 100
199
+ console.log(`Total Usage: ${used} / ${limit} (${percentage.toFixed(1)}% used)`)
200
+ console.log(`Remaining: ${remaining ?? (limit - used).toFixed(0)}`)
201
+ const resetTimeField = reset_at || resetTime
202
+ if (resetTimeField) {
203
+ const resetDate = new Date(resetTimeField)
204
+ console.log(`Next Reset: ${resetDate.toLocaleString()} (${formatDurationCompact(resetTimeField)})`)
205
+ }
206
+ }
207
+ console.log('')
208
+ }
209
+
210
+ // Display detailed limits
211
+ if (balance.limits && balance.limits.length > 0) {
212
+ console.log('Usage Details:')
213
+ console.log('')
214
+
215
+ for (const item of balance.limits) {
216
+ const detail = (item.detail || item) as LimitItem & LimitDetail
217
+ const limit = detail.limit
218
+ const used = detail.used
219
+ const remaining = detail.remaining
220
+ const resetAt = detail.reset_at || detail.resetTime
221
+
222
+ if (limit != null) {
223
+ const label = formatLimitLabel(item)
224
+ console.log(` ${label}:`)
225
+
226
+ // Calculate used if not provided
227
+ const usedValue = used != null ? used : (remaining != null && limit != null ? limit - remaining : null)
228
+
229
+ if (usedValue != null) {
230
+ const percentage = (usedValue / limit) * 100
231
+ console.log(` Used: ${usedValue} / ${limit} (${percentage.toFixed(1)}% used)`)
232
+ }
233
+
234
+ if (remaining != null) {
235
+ console.log(` Remaining: ${remaining}`)
236
+ }
237
+
238
+ if (resetAt) {
239
+ const resetDate = new Date(resetAt)
240
+ console.log(` Next Reset: ${resetDate.toLocaleString()} (${formatDurationCompact(resetAt)})`)
241
+ }
242
+ console.log('')
243
+ }
244
+ }
245
+ }
246
+ }
247
+
248
+ function showHelp(): void {
249
+ console.log('opencode-kimi-quota: Check Kimi Coding Plan quota from terminal')
250
+ console.log('')
251
+ console.log('Usage:')
252
+ console.log(' bun run bin/kimi-quota.ts [--debug|--raw]')
253
+ console.log('')
254
+ console.log('Options:')
255
+ console.log(' --debug, -d Enable debug logging')
256
+ console.log(' --raw Output raw JSON (default: formatted text)')
257
+ console.log('')
258
+ console.log('Environment:')
259
+ console.log(' LOG_LEVEL=debug Enable debug logging')
260
+ console.log('')
261
+ console.log('Authentication:')
262
+ console.log(' Reads from ~/.local/share/opencode/auth.json (kimi-for-coding, kimi, or moonshot provider)')
263
+ }
264
+
265
+ async function main(): Promise<void> {
266
+ const args = process.argv.slice(2)
267
+ const debugIndex = args.findIndex(a => a === '--debug' || a === '-d')
268
+ const rawIndex = args.findIndex(a => a === '--raw')
269
+ const helpIndex = args.findIndex(a => a === '--help' || a === '-h')
270
+
271
+ if (helpIndex !== -1) {
272
+ showHelp()
273
+ process.exit(0)
274
+ }
275
+
276
+ const rawOutput = rawIndex !== -1
277
+
278
+ if (debugIndex !== -1) {
279
+ configureLogging('debug')
280
+ }
281
+
282
+ logger.info('Starting opencode-kimi-quota CLI')
283
+ logger.debug(`Arguments: ${JSON.stringify({ debug: debugIndex !== -1, rawOutput, _: args })}`)
284
+
285
+ const apiKey = await getCredentials()
286
+ if (!apiKey) {
287
+ process.exit(1)
288
+ }
289
+
290
+ try {
291
+ const balance = await queryBalance(apiKey)
292
+
293
+ if (rawOutput) {
294
+ console.log(JSON.stringify(balance, null, 2))
295
+ process.exit(0)
296
+ }
297
+
298
+ formatUsage(balance)
299
+ } catch (error) {
300
+ const errorMessage = error instanceof Error ? error.message : String(error)
301
+ logger.error(`Error: ${errorMessage}`)
302
+ if (error instanceof Error && error.stack) {
303
+ logger.debug(`Stack: ${error.stack}`)
304
+ }
305
+ if (!rawOutput) {
306
+ console.log('')
307
+ console.log('Kimi Usage Check Failed')
308
+ console.log(`Error: ${errorMessage}`)
309
+ }
310
+ process.exit(1)
311
+ }
312
+ }
313
+
314
+ main()
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env -S bun
2
+ /**
3
+ * GitHub Copilot quota CLI tool
4
+ * Fetches and displays GitHub Copilot usage statistics from command line
5
+ * Credentials are fetched from OpenCode's auth.json
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=copilot-quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-quota.d.ts","sourceRoot":"","sources":["../../bin/copilot-quota.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env -S bun
2
+ /**
3
+ * GitHub Copilot quota CLI tool
4
+ * Fetches and displays GitHub Copilot usage statistics from command line
5
+ * Credentials are fetched from OpenCode's auth.json
6
+ */
7
+ import * as https from 'https';
8
+ import * as os from 'os';
9
+ import * as path from 'path';
10
+ import { configureLogging, getLogger } from '../src/shared/logging.js';
11
+ const COMMAND_NAME = 'opencode-copilot-quota';
12
+ const AUTH_JSON_PATH = path.join(os.homedir(), '.local', 'share', 'opencode', 'auth.json');
13
+ // Global logger, assigned after configureLogging()
14
+ let logger;
15
+ /**
16
+ * Calculate duration until reset date
17
+ * @param resetDate - Reset date string (ISO 8601)
18
+ * @returns Human-readable duration (e.g., "7d 4h 32m 15s", "2h 57m 31s", "5m")
19
+ */
20
+ function calculateDurationToReset(resetDate) {
21
+ const now = new Date();
22
+ const reset = new Date(resetDate);
23
+ const diffMs = reset.getTime() - now.getTime();
24
+ // If reset date is in the past, show "0d 0h 0m 0s"
25
+ if (diffMs <= 0) {
26
+ return '0d 0h 0m 0s';
27
+ }
28
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
29
+ const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
30
+ const diffMinutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
31
+ const diffSeconds = Math.floor((diffMs % (1000 * 60)) / 1000);
32
+ // Build duration string, hiding zero values
33
+ const parts = [];
34
+ if (diffDays > 0)
35
+ parts.push(`${diffDays}d`);
36
+ if (diffHours > 0)
37
+ parts.push(`${diffHours}h`);
38
+ if (diffMinutes > 0)
39
+ parts.push(`${diffMinutes}m`);
40
+ if (diffSeconds > 0)
41
+ parts.push(`${diffSeconds}s`);
42
+ return parts.length > 0 ? parts.join(' ') : '0s';
43
+ }
44
+ /**
45
+ * Parse Copilot response and format output
46
+ * @param response - Raw JSON response string
47
+ * @returns Formatted output string
48
+ */
49
+ function parseCopilotResponse(response) {
50
+ const data = JSON.parse(response);
51
+ const { login, copilot_plan, quota_reset_date_utc, quota_snapshots } = data;
52
+ // Format reset date and duration
53
+ const resetDate = new Date(quota_reset_date_utc)
54
+ .toLocaleDateString('en-US', {
55
+ year: 'numeric',
56
+ month: '2-digit',
57
+ day: '2-digit',
58
+ });
59
+ const duration = calculateDurationToReset(quota_reset_date_utc);
60
+ // Build formatted output (plain text, no boxes)
61
+ let output = '';
62
+ output += `GitHub Copilot Usage Statistics\n`;
63
+ output += `\n`;
64
+ output += `User: ${login}\n`;
65
+ output += `Plan: ${copilot_plan}\n`;
66
+ output += `Reset: ${resetDate} (${duration})\n`;
67
+ output += `\n`;
68
+ output += `QUOTA USAGE\n`;
69
+ output += `\n`;
70
+ // Chat
71
+ if (quota_snapshots.chat.unlimited) {
72
+ output += `Chat: Unlimited\n`;
73
+ }
74
+ else {
75
+ const remaining = quota_snapshots.chat.percent_remaining ?? 0;
76
+ const used = 100 - remaining;
77
+ output += `Chat: ${used}% used\n`;
78
+ }
79
+ // Completions
80
+ if (quota_snapshots.completions.unlimited) {
81
+ output += `Completions: Unlimited\n`;
82
+ }
83
+ else {
84
+ const remaining = quota_snapshots.completions.percent_remaining ?? 0;
85
+ const used = 100 - remaining;
86
+ output += `Completions: ${used}% used\n`;
87
+ }
88
+ // Premium
89
+ const premium = quota_snapshots.premium_interactions;
90
+ if (premium.unlimited) {
91
+ output += `Premium: Unlimited\n`;
92
+ }
93
+ else {
94
+ const remaining = premium.quota_remaining ?? 0;
95
+ const entitlement = premium.entitlement ?? 0;
96
+ const used = entitlement - remaining;
97
+ const percentUsed = entitlement > 0 ? ((used / entitlement) * 100).toFixed(1) : '0.0';
98
+ output += `Premium: ${used.toFixed(2)} / ${entitlement} (${percentUsed}% used)\n`;
99
+ }
100
+ return output;
101
+ }
102
+ /**
103
+ * Make HTTPS request with timeout
104
+ */
105
+ function makeRequest(url, token, headers = {}) {
106
+ logger.debug(`Making request to ${url}`);
107
+ logger.debug(`Using token: ${token.slice(0, 8)}...${token.slice(-4)}`);
108
+ return new Promise((resolve, reject) => {
109
+ const timeout = 10000; // 10 seconds
110
+ const timer = setTimeout(() => {
111
+ req.destroy();
112
+ logger.error(`Request timeout for ${url}`);
113
+ reject(new Error('Request timeout'));
114
+ }, timeout);
115
+ const urlObj = new URL(url);
116
+ const options = {
117
+ hostname: urlObj.hostname,
118
+ port: urlObj.port || 443,
119
+ path: urlObj.pathname + urlObj.search,
120
+ method: 'GET',
121
+ headers: {
122
+ 'Authorization': `token ${token}`,
123
+ 'Accept': 'application/json',
124
+ 'Content-Type': 'application/json',
125
+ ...headers,
126
+ },
127
+ };
128
+ logger.debug(`Request options: ${JSON.stringify({
129
+ hostname: options.hostname,
130
+ path: options.path,
131
+ method: options.method,
132
+ headers: Object.fromEntries(Object.entries(options.headers).map(([k, v]) => [
133
+ k,
134
+ k === 'Authorization' ? `${v.slice(0, 13)}...${v.slice(-4)}` : v,
135
+ ])),
136
+ })}`);
137
+ const req = https.request(options, (res) => {
138
+ let data = '';
139
+ logger.debug(`Response status: ${res.statusCode} ${res.statusMessage}`);
140
+ res.on('data', chunk => {
141
+ data += chunk;
142
+ });
143
+ res.on('end', () => {
144
+ clearTimeout(timer);
145
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
146
+ logger.debug(`Response received: ${data.slice(0, 100)}... (${data.length} bytes)`);
147
+ resolve(data);
148
+ }
149
+ else {
150
+ logger.error(`HTTP error: ${res.statusCode} ${res.statusMessage}`);
151
+ logger.debug(`Error response: ${data}`);
152
+ reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
153
+ }
154
+ });
155
+ });
156
+ req.on('error', (err) => {
157
+ clearTimeout(timer);
158
+ logger.error(`Request error: ${err.message}`);
159
+ reject(err);
160
+ });
161
+ req.end();
162
+ });
163
+ }
164
+ /**
165
+ * Get credentials from OpenCode auth.json
166
+ */
167
+ function getCredentials() {
168
+ logger.debug(`Looking for credentials at ${AUTH_JSON_PATH}`);
169
+ try {
170
+ const fs = require('fs');
171
+ if (!fs.existsSync(AUTH_JSON_PATH)) {
172
+ logger.debug('auth.json does not exist');
173
+ return null;
174
+ }
175
+ const content = fs.readFileSync(AUTH_JSON_PATH, 'utf-8');
176
+ const auth = JSON.parse(content);
177
+ logger.debug(`auth.json loaded with ${Object.keys(auth).length} providers`);
178
+ const copilotToken = auth['github-copilot']?.access ?? auth['github-copilot']?.refresh;
179
+ if (copilotToken) {
180
+ logger.info('Found credentials for provider: github-copilot');
181
+ return { token: copilotToken };
182
+ }
183
+ logger.debug('No credentials found for github-copilot provider');
184
+ return null;
185
+ }
186
+ catch (error) {
187
+ logger.error(`Error reading auth.json: ${error}`);
188
+ return null;
189
+ }
190
+ }
191
+ /**
192
+ * Display help message
193
+ */
194
+ function showHelp() {
195
+ console.log(`
196
+ ${COMMAND_NAME} - Check GitHub Copilot quota from terminal
197
+
198
+ USAGE:
199
+ bun run bin/copilot-quota.ts [--raw] [--debug]
200
+
201
+ OPTIONS:
202
+ --raw Output raw JSON (default: formatted output)
203
+ --debug, -d Enable debug logging (logs hidden by default)
204
+ --help, -h Display this help message
205
+
206
+ AUTHENTICATION:
207
+ Reads credentials from ~/.local/share/opencode/auth.json
208
+ Provider: github-copilot
209
+
210
+ EXAMPLES:
211
+ bun run bin/copilot-quota.ts
212
+ bun run bin/copilot-quota.ts --debug
213
+ bun run bin/copilot-quota.ts --raw
214
+ `);
215
+ }
216
+ /**
217
+ * Main CLI entry point
218
+ */
219
+ async function main() {
220
+ const args = process.argv.slice(2);
221
+ // Check for help flag first (before logging config)
222
+ if (args.includes('--help') || args.includes('-h')) {
223
+ showHelp();
224
+ process.exit(0);
225
+ }
226
+ // Check for debug flag before configuring logging
227
+ const debugMode = args.includes('--debug') || args.includes('-d');
228
+ // Only configure logging when --debug is present
229
+ if (debugMode) {
230
+ await configureLogging('debug');
231
+ }
232
+ // Create logger after configureLogging (or with no-op if not configured)
233
+ if (debugMode) {
234
+ logger = getLogger(['opencode-quota', 'cli', 'copilot']);
235
+ }
236
+ else {
237
+ // No-op logger when debug mode is off
238
+ logger = {
239
+ debug: () => { },
240
+ info: () => { },
241
+ warn: () => { },
242
+ error: () => { },
243
+ };
244
+ }
245
+ logger.info(`${COMMAND_NAME} starting...`);
246
+ const rawOutput = args.includes('--raw');
247
+ logger.debug(`Arguments: ${args.join(' ')}`);
248
+ logger.debug(`Raw output: ${rawOutput}`);
249
+ try {
250
+ // Get credentials from OpenCode auth.json
251
+ const credentials = getCredentials();
252
+ if (!credentials) {
253
+ logger.error('No credentials found');
254
+ console.error(`\n${COMMAND_NAME}: Not configured.\nPlease connect to GitHub Copilot in OpenCode first.\n`);
255
+ process.exit(1);
256
+ }
257
+ // Query GitHub Copilot internal API
258
+ const customHeaders = {
259
+ 'X-GitHub-Api-Version': '2025-04-01',
260
+ 'User-Agent': 'GitHubCopilotChat/0.26.7',
261
+ 'Editor-Version': 'vscode/1.96.2',
262
+ };
263
+ logger.info('Querying GitHub Copilot internal API...');
264
+ const response = await makeRequest('https://api.github.com/copilot_internal/user', credentials.token, customHeaders);
265
+ logger.info('Received response from GitHub API');
266
+ if (!rawOutput) {
267
+ // Parse and display formatted output
268
+ try {
269
+ const formatted = parseCopilotResponse(response);
270
+ console.log(formatted);
271
+ }
272
+ catch (error) {
273
+ logger.error(`Failed to parse Copilot response: ${error}`);
274
+ logger.debug(`Invalid response: ${response}`);
275
+ throw new Error(`Parse error: ${error instanceof Error ? error.message : String(error)}`);
276
+ }
277
+ }
278
+ else {
279
+ // Print raw response
280
+ console.log(response);
281
+ }
282
+ logger.info('Completed successfully');
283
+ }
284
+ catch (error) {
285
+ if (error instanceof Error) {
286
+ logger.error(`${error.name}: ${error.message}`);
287
+ console.error(`\n${COMMAND_NAME}: ${error.message}\n`);
288
+ }
289
+ else {
290
+ logger.error(`Unknown error: ${String(error)}`);
291
+ console.error(`\n${COMMAND_NAME}: Unknown error occurred\n`);
292
+ }
293
+ process.exit(1);
294
+ }
295
+ }
296
+ // Run CLI
297
+ main();
298
+ //# sourceMappingURL=copilot-quota.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-quota.js","sourceRoot":"","sources":["../../bin/copilot-quota.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env -S bun
2
+ /**
3
+ * GLM quota CLI tool
4
+ * Fetches and displays Z.AI GLM Coding Plan usage statistics from command line
5
+ * Credentials are fetched from OpenCode's auth.json
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=glm-quota.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glm-quota.d.ts","sourceRoot":"","sources":["../../bin/glm-quota.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}