opencode-copilot-usage-detector 0.1.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.
@@ -0,0 +1,500 @@
1
+ import { recoverFromJSONL, processAssistantMessage, processErrorEvent, getDaily, getCurrentRPM, setTimezone, } from "./aggregator.js";
2
+ import { ensureDataDir, readConfig, appendObservation, readObservations, readEstimates, } from "./persistence.js";
3
+ import { budgetTool, formatStatus, formatHistory, formatErrors, formatInsights } from "./tools.js";
4
+ import { enableDebug, debugLogEvent, debugLogChatParams } from "./debug.js";
5
+ import { classifyErrorImmediate, extractRateLimitHeaders, scheduleReclassification, } from "./classifier.js";
6
+ import { getBudgetStatus, checkThresholds, computeEstimates } from "./estimator.js";
7
+ import { pollPremiumRequests, getCachedPremiumRequests, formatPremiumRequestStatus, } from "./github-api.js";
8
+ // ============================================================
9
+ // Helpers
10
+ // ============================================================
11
+ export function formatTokensShort(n) {
12
+ if (n >= 1_000_000)
13
+ return `${(n / 1_000_000).toFixed(1)}M`;
14
+ if (n >= 1_000)
15
+ return `${(n / 1_000).toFixed(0)}K`;
16
+ return String(n);
17
+ }
18
+ export function isAssistantMessage(msg) {
19
+ return (typeof msg === "object" &&
20
+ msg !== null &&
21
+ msg.role === "assistant" &&
22
+ typeof msg.id === "string");
23
+ }
24
+ export function isApiError(error) {
25
+ return (typeof error === "object" &&
26
+ error !== null &&
27
+ error.name === "APIError");
28
+ }
29
+ const MODEL_BLOCKED_MESSAGE_PATTERNS = [
30
+ "not available",
31
+ "not supported",
32
+ "forbidden",
33
+ "access denied",
34
+ "not authorized",
35
+ "not included",
36
+ "not enabled",
37
+ "model not found",
38
+ "not allowed",
39
+ "not permitted",
40
+ "does not have access",
41
+ "not part of your",
42
+ "unavailable for your",
43
+ ];
44
+ export function isModelBlockedError(error, modelCumulativeTokens, modelCumulativeRequests) {
45
+ const code = error.data?.statusCode;
46
+ const msg = error.data?.message?.toLowerCase() ?? "";
47
+ // 403 Forbidden — always blocked
48
+ if (code === 403)
49
+ return true;
50
+ // Message patterns + model was never successfully used
51
+ if (modelCumulativeTokens === 0 && modelCumulativeRequests === 0) {
52
+ if (MODEL_BLOCKED_MESSAGE_PATTERNS.some((p) => msg.includes(p)))
53
+ return true;
54
+ }
55
+ // 401 with model-specific denial (not generic auth failure)
56
+ if (code === 401 && MODEL_BLOCKED_MESSAGE_PATTERNS.some((p) => msg.includes(p))) {
57
+ return true;
58
+ }
59
+ return false;
60
+ }
61
+ export function isRateLimitError(error) {
62
+ const code = error.data?.statusCode;
63
+ const msg = error.data?.message?.toLowerCase() ?? "";
64
+ return (code === 429 ||
65
+ msg.includes("rate") ||
66
+ msg.includes("limit") ||
67
+ msg.includes("exceeded") ||
68
+ msg.includes("capacity") ||
69
+ msg.includes("throttl"));
70
+ }
71
+ function readRecentObservations(sinceTs) {
72
+ return readObservations({ since: sinceTs });
73
+ }
74
+ // ============================================================
75
+ // Plugin
76
+ // ============================================================
77
+ const plugin = (async (ctx) => {
78
+ const { client } = ctx;
79
+ // Initialize
80
+ ensureDataDir();
81
+ const config = readConfig();
82
+ if (config.debug) {
83
+ enableDebug();
84
+ }
85
+ if (config.timezone) {
86
+ setTimezone(config.timezone);
87
+ }
88
+ recoverFromJSONL();
89
+ // Track the last requested model per session (avoids cross-session contamination)
90
+ const sessionModels = new Map();
91
+ const SESSION_MODEL_MAX = 500;
92
+ const SESSION_MODEL_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
93
+ function getSessionModel(sessionId) {
94
+ const entry = sessionModels.get(sessionId);
95
+ return entry ? { model: entry.model, provider: entry.provider } : { model: null, provider: null };
96
+ }
97
+ function pruneSessionModels() {
98
+ if (sessionModels.size <= SESSION_MODEL_MAX)
99
+ return;
100
+ const now = Date.now();
101
+ for (const [key, val] of sessionModels) {
102
+ if (now - val.ts > SESSION_MODEL_TTL_MS)
103
+ sessionModels.delete(key);
104
+ }
105
+ // If still over limit, drop oldest half
106
+ if (sessionModels.size > SESSION_MODEL_MAX) {
107
+ const entries = [...sessionModels.entries()].sort((a, b) => a[1].ts - b[1].ts);
108
+ const toDelete = entries.slice(0, Math.floor(entries.length / 2));
109
+ for (const [key] of toDelete)
110
+ sessionModels.delete(key);
111
+ }
112
+ }
113
+ // Auto-recompute estimates periodically
114
+ let usageEventsSinceRecompute = 0;
115
+ const RECOMPUTE_EVERY_N_EVENTS = 50;
116
+ let lastRecomputeTime = 0;
117
+ const RECOMPUTE_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
118
+ function maybeRecomputeEstimates(force = false) {
119
+ const now = Date.now();
120
+ if (force || usageEventsSinceRecompute >= RECOMPUTE_EVERY_N_EVENTS || now - lastRecomputeTime > RECOMPUTE_INTERVAL_MS) {
121
+ try {
122
+ computeEstimates(config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
123
+ usageEventsSinceRecompute = 0;
124
+ lastRecomputeTime = now;
125
+ }
126
+ catch {
127
+ // Recompute failure is not critical
128
+ }
129
+ }
130
+ }
131
+ // Helper to send a message to the user without triggering a reply
132
+ async function sendMessage(sessionId, text) {
133
+ try {
134
+ await client.session.prompt({
135
+ path: { id: sessionId },
136
+ body: {
137
+ noReply: true,
138
+ parts: [{ type: "text", text, ignored: true }],
139
+ },
140
+ });
141
+ }
142
+ catch {
143
+ // Notification failure is not critical
144
+ }
145
+ }
146
+ return {
147
+ // ----------------------------------------------------------
148
+ // Config hook: register /budget command
149
+ // ----------------------------------------------------------
150
+ config: async (opencodeConfig) => {
151
+ opencodeConfig.command ??= {};
152
+ opencodeConfig.command["budget"] = {
153
+ template: "",
154
+ description: "Show Copilot budget status, usage history, and insights",
155
+ };
156
+ },
157
+ // ----------------------------------------------------------
158
+ // Command handler: /budget [subcommand]
159
+ // ----------------------------------------------------------
160
+ "command.execute.before": async (input, _output) => {
161
+ if (input.command !== "budget")
162
+ return;
163
+ const args = (input.arguments || "").trim().split(/\s+/).filter(Boolean);
164
+ const subcommand = args[0]?.toLowerCase() || "status";
165
+ let result;
166
+ switch (subcommand) {
167
+ case "status":
168
+ result = formatStatus();
169
+ break;
170
+ case "history":
171
+ result = formatHistory(14);
172
+ break;
173
+ case "insights":
174
+ result = formatInsights();
175
+ break;
176
+ case "errors":
177
+ result = formatErrors();
178
+ break;
179
+ case "recompute":
180
+ computeEstimates(config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
181
+ result = "Estimates recomputed. Run `/budget insights` to see results.";
182
+ break;
183
+ default:
184
+ result = [
185
+ "## /budget commands",
186
+ "",
187
+ "- `/budget` or `/budget status` — Current usage and estimates",
188
+ "- `/budget history` — Daily usage for the last 14 days",
189
+ "- `/budget insights` — Learned patterns and limit analysis",
190
+ "- `/budget errors` — Rate limit events and error catalog",
191
+ "- `/budget recompute` — Force recompute all estimates",
192
+ ].join("\n");
193
+ }
194
+ await sendMessage(input.sessionID, result);
195
+ },
196
+ // ----------------------------------------------------------
197
+ // Event handler
198
+ // ----------------------------------------------------------
199
+ event: async ({ event }) => {
200
+ try {
201
+ debugLogEvent(event.type, event);
202
+ // ----- message.updated: extract tokens from assistant messages -----
203
+ if (event.type === "message.updated") {
204
+ const msgEvent = event;
205
+ const msg = msgEvent.properties.info;
206
+ if (!isAssistantMessage(msg))
207
+ return;
208
+ const finished = !!msg.finish;
209
+ const tokens = msg.tokens ?? {
210
+ input: 0,
211
+ output: 0,
212
+ reasoning: 0,
213
+ cache: { read: 0, write: 0 },
214
+ };
215
+ const sm = getSessionModel(msg.sessionID);
216
+ const incoming = {
217
+ messageId: msg.id,
218
+ sessionId: msg.sessionID,
219
+ modelId: msg.modelID ?? sm.model ?? "unknown",
220
+ providerId: msg.providerID ?? sm.provider ?? "unknown",
221
+ tokens: {
222
+ total: tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write,
223
+ input: tokens.input,
224
+ output: tokens.output,
225
+ reasoning: tokens.reasoning,
226
+ cache: tokens.cache,
227
+ },
228
+ cost: msg.cost ?? 0,
229
+ finished,
230
+ };
231
+ processAssistantMessage(incoming);
232
+ usageEventsSinceRecompute++;
233
+ maybeRecomputeEstimates();
234
+ // Detect silent model fallback
235
+ if (finished && msg.modelID && sm.model && msg.modelID !== sm.model) {
236
+ appendObservation({
237
+ ts: new Date().toISOString(),
238
+ type: "model_fallback",
239
+ requested: sm.model,
240
+ received: msg.modelID,
241
+ day_cumulative_tokens: getDaily().totalTokens,
242
+ });
243
+ }
244
+ // Check threshold notifications
245
+ if (finished && !config.quiet_mode) {
246
+ const d = getDaily();
247
+ const status = getBudgetStatus(d.totalTokens, d.totalRequests, d.totalCost, d.byModel, d.limitHits.length, config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
248
+ const threshold = checkThresholds(status.percentage, config.notification_thresholds, d.notifiedThresholds);
249
+ if (threshold !== null) {
250
+ d.notifiedThresholds.add(threshold);
251
+ const pctStr = status.percentage !== null ? `${status.percentage}%` : "?";
252
+ const limitStr = status.estimatedTokenLimit
253
+ ? formatTokensShort(status.estimatedTokenLimit) : "unknown";
254
+ const confStr = status.confidence > 0.8 ? ""
255
+ : status.confidence > 0.5 ? " (moderate confidence)" : " (low confidence)";
256
+ await sendMessage(msg.sessionID, `\u{26A1} **${pctStr} of daily Copilot budget used** (${formatTokensShort(d.totalTokens)} / ~${limitStr} est.)${confStr}`);
257
+ }
258
+ }
259
+ }
260
+ // ----- session.error: log all errors, detect rate limits -----
261
+ if (event.type === "session.error") {
262
+ const errEvent = event;
263
+ const error = errEvent.properties.error;
264
+ if (!error)
265
+ return;
266
+ const sessionId = errEvent.properties.sessionID;
267
+ const errSm = getSessionModel(sessionId ?? "");
268
+ if (isApiError(error)) {
269
+ const apiErr = error;
270
+ const errModel = errSm.model ?? "unknown";
271
+ const modelUsage = getDaily().byModel[errModel];
272
+ const modelTokens = modelUsage?.tokens ?? 0;
273
+ const modelRequests = modelUsage?.requests ?? 0;
274
+ // Check for blocked model BEFORE rate limit check
275
+ if (isModelBlockedError(apiErr, modelTokens, modelRequests)) {
276
+ const d = getDaily();
277
+ const blockedTs = new Date().toISOString();
278
+ d.blockedModels.push({
279
+ ts: blockedTs,
280
+ model: errModel,
281
+ errorMessage: apiErr.data?.message ?? "",
282
+ statusCode: apiErr.data?.statusCode,
283
+ });
284
+ appendObservation({
285
+ ts: blockedTs,
286
+ type: "model_blocked",
287
+ session: sessionId ?? "unknown",
288
+ model: errModel,
289
+ provider: errSm.provider ?? "unknown",
290
+ error_name: apiErr.name,
291
+ error_message: apiErr.data?.message ?? "",
292
+ error_raw: JSON.stringify(apiErr),
293
+ status_code: apiErr.data?.statusCode,
294
+ is_retryable: apiErr.data?.isRetryable ?? false,
295
+ day_cumulative_tokens: d.totalTokens,
296
+ day_cumulative_requests: d.totalRequests,
297
+ });
298
+ if (sessionId) {
299
+ await sendMessage(sessionId, `\u{1F6AB} **Model blocked:** ${errModel} is not available on your plan (status: ${apiErr.data?.statusCode ?? "unknown"}). This won't count toward rate limit estimates.`);
300
+ }
301
+ return; // Skip rate-limit path entirely
302
+ }
303
+ const rateLimitHeaders = extractRateLimitHeaders(apiErr.data?.responseHeaders);
304
+ const classification = classifyErrorImmediate(apiErr.data?.message ?? "", apiErr.data?.statusCode, apiErr.data?.responseHeaders);
305
+ if (isRateLimitError(apiErr)) {
306
+ const incomingError = {
307
+ sessionId,
308
+ errorName: apiErr.name,
309
+ errorMessage: apiErr.data?.message ?? "",
310
+ errorRaw: JSON.stringify(apiErr),
311
+ statusCode: apiErr.data?.statusCode,
312
+ isRetryable: apiErr.data?.isRetryable ?? false,
313
+ responseHeaders: apiErr.data?.responseHeaders,
314
+ responseBody: apiErr.data?.responseBody,
315
+ };
316
+ const errorTs = processErrorEvent(incomingError, errSm.model, errSm.provider);
317
+ maybeRecomputeEstimates(true);
318
+ const d = getDaily();
319
+ if (d.limitHits.length > 0) {
320
+ d.limitHits[d.limitHits.length - 1].class = classification.class;
321
+ }
322
+ // Schedule delayed reclassification (10 min after event)
323
+ scheduleReclassification(errorTs, () => {
324
+ const current = getDaily();
325
+ const recentObs = readRecentObservations(errorTs);
326
+ const errorModel = errSm.model ?? "unknown";
327
+ const otherModels = recentObs
328
+ .filter((o) => o.type === "usage" && o.model !== errorModel)
329
+ .map((o) => o.model);
330
+ const uniqueOtherModels = [...new Set(otherModels)];
331
+ const totalRecent = recentObs.length;
332
+ const errorRecent = recentObs.filter((o) => o.type === "limit_hit").length;
333
+ const recoveryEvent = recentObs.find((o) => o.type === "recovery");
334
+ const recoveryMinutes = recoveryEvent
335
+ ? (new Date(recoveryEvent.ts).getTime() - new Date(errorTs).getTime()) / 60_000
336
+ : null;
337
+ return {
338
+ recentObservations: recentObs.map((o) => ({
339
+ type: o.type,
340
+ model: "model" in o ? String(o.model) : undefined,
341
+ ts: o.ts,
342
+ })),
343
+ dailyTokens: current.totalTokens,
344
+ dailyRequests: current.totalRequests,
345
+ globalEstimate: (() => {
346
+ try {
347
+ const est = readEstimates();
348
+ if (est && typeof est === "object") {
349
+ const gdb = est.globalDailyBudget;
350
+ if (gdb && typeof gdb === "object") {
351
+ const te = gdb.tokenEstimate;
352
+ if (te && typeof te === "object") {
353
+ const val = te.value;
354
+ return typeof val === "number" ? val : null;
355
+ }
356
+ }
357
+ }
358
+ return null;
359
+ }
360
+ catch {
361
+ return null;
362
+ }
363
+ })(),
364
+ otherModelsWorking: uniqueOtherModels.length > 0,
365
+ workingModels: uniqueOtherModels,
366
+ errorRate: totalRecent > 0 ? errorRecent / totalRecent : 0,
367
+ minutesSinceError: (Date.now() - new Date(errorTs).getTime()) / 60_000,
368
+ hasRecovered: !!recoveryEvent,
369
+ recoveryMinutes,
370
+ };
371
+ });
372
+ // Notify user
373
+ if (sessionId) {
374
+ const headerInfo = rateLimitHeaders
375
+ ? ` | Headers: ${Object.entries(rateLimitHeaders.all).map(([k, v]) => `${k}=${v}`).join(", ")}`
376
+ : "";
377
+ await sendMessage(sessionId, `\u{1F534} **Rate limited!** Day total: ${formatTokensShort(d.totalTokens)} tokens, ${d.totalRequests} requests | Model: ${errSm.model ?? "unknown"} | Status: ${apiErr.data?.statusCode ?? "unknown"} | Class: ${classification.class}${headerInfo}\n\nRun \`/budget errors\` for details.`);
378
+ }
379
+ }
380
+ else {
381
+ appendObservation({
382
+ ts: new Date().toISOString(),
383
+ type: "error_logged",
384
+ session: sessionId ?? "unknown",
385
+ model: errSm.model ?? "unknown",
386
+ provider: errSm.provider ?? "unknown",
387
+ error_name: apiErr.name,
388
+ error_message: apiErr.data?.message ?? "",
389
+ error_raw: JSON.stringify(apiErr),
390
+ status_code: apiErr.data?.statusCode,
391
+ is_retryable: apiErr.data?.isRetryable ?? false,
392
+ });
393
+ }
394
+ }
395
+ else {
396
+ appendObservation({
397
+ ts: new Date().toISOString(),
398
+ type: "error_logged",
399
+ session: sessionId ?? "unknown",
400
+ model: errSm.model ?? "unknown",
401
+ provider: errSm.provider ?? "unknown",
402
+ error_name: error.name ?? "Unknown",
403
+ error_message: error.data?.message ?? "",
404
+ error_raw: JSON.stringify(error),
405
+ status_code: undefined,
406
+ is_retryable: false,
407
+ });
408
+ }
409
+ }
410
+ }
411
+ catch (err) {
412
+ try {
413
+ await client.app.log({
414
+ body: {
415
+ service: "copilot-budget",
416
+ level: "error",
417
+ message: `Event handler error: ${err instanceof Error ? err.message : String(err)}`,
418
+ },
419
+ });
420
+ }
421
+ catch {
422
+ // Even logging failed, silently ignore
423
+ }
424
+ }
425
+ },
426
+ // ----------------------------------------------------------
427
+ // chat.params: capture model/provider before each LLM call
428
+ // ----------------------------------------------------------
429
+ "chat.params": async ({ sessionID, model, provider }) => {
430
+ try {
431
+ sessionModels.set(sessionID, { model: model.id, provider: provider.info.id, ts: Date.now() });
432
+ pruneSessionModels();
433
+ debugLogChatParams(model, provider);
434
+ }
435
+ catch {
436
+ // Non-critical
437
+ }
438
+ },
439
+ // ----------------------------------------------------------
440
+ // System prompt injection
441
+ // ----------------------------------------------------------
442
+ "experimental.chat.system.transform": async (_input, output) => {
443
+ try {
444
+ const d = getDaily();
445
+ const rpm = getCurrentRPM();
446
+ const status = getBudgetStatus(d.totalTokens, d.totalRequests, d.totalCost, d.byModel, d.limitHits.length, config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
447
+ const pr = await pollPremiumRequests(config).catch(() => getCachedPremiumRequests());
448
+ const premiumLine = pr ? formatPremiumRequestStatus(pr) : "";
449
+ const limitLine = status.estimatedTokenLimit
450
+ ? `Estimated daily limit: ~${formatTokensShort(status.estimatedTokenLimit)} tokens (confidence: ${Math.round(status.confidence * 100)}%)`
451
+ : "Estimated daily limit: unknown (still learning)";
452
+ const pctLine = status.percentage !== null ? `Usage percentage: ~${status.percentage}%` : "";
453
+ const limitHitLine = d.limitHits.length > 0
454
+ ? `Limit hits today: ${d.limitHits.length} (last at ${d.limitHits[d.limitHits.length - 1]?.ts.split("T")[1]?.split(".")[0] ?? "?"})`
455
+ : "";
456
+ const blockedLine = d.blockedModels.length > 0
457
+ ? `Blocked models: ${[...new Set(d.blockedModels.map((b) => b.model))].join(", ")}`
458
+ : "";
459
+ const previewLine = status.previewWarnings ? `\nPreview model warnings:\n${status.previewWarnings}` : "";
460
+ const insightLine = status.insights ? `\nInsights:\n${status.insights}` : "";
461
+ output.system.push(`<copilot-budget>
462
+ ${premiumLine ? premiumLine + "\n" : ""}Daily token usage: ${formatTokensShort(d.totalTokens)} tokens (${d.totalRequests} requests)
463
+ ${limitLine}
464
+ ${pctLine}
465
+ Cost today: $${d.totalCost.toFixed(4)}
466
+ Current rate: ${rpm} req/min (peak: ${d.peakRPM})
467
+ ${status.modelBreakdown ? `\nModel breakdown:\n${status.modelBreakdown}` : ""}
468
+ ${limitHitLine}
469
+ ${blockedLine}${previewLine}${insightLine}
470
+ </copilot-budget>`);
471
+ }
472
+ catch {
473
+ // Non-critical
474
+ }
475
+ },
476
+ // ----------------------------------------------------------
477
+ // Session compaction
478
+ // ----------------------------------------------------------
479
+ "experimental.session.compacting": async (_input, output) => {
480
+ try {
481
+ const d = getDaily();
482
+ const blockedStr = d.blockedModels.length > 0
483
+ ? ` ${[...new Set(d.blockedModels.map((b) => b.model))].length} model(s) are blocked.`
484
+ : "";
485
+ output.context.push(`The user has used ${formatTokensShort(d.totalTokens)} tokens today across ${d.totalRequests} requests. ${d.limitHits.length > 0 ? `Rate-limited ${d.limitHits.length} time(s) today.` : "No rate limits hit today."}${blockedStr}`);
486
+ }
487
+ catch {
488
+ // Non-critical
489
+ }
490
+ },
491
+ // ----------------------------------------------------------
492
+ // Custom tool (for LLM to call)
493
+ // ----------------------------------------------------------
494
+ tool: {
495
+ budget: budgetTool,
496
+ },
497
+ };
498
+ });
499
+ export default plugin;
500
+ //# sourceMappingURL=copilot-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot-budget.js","sourceRoot":"","sources":["../src/copilot-budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function enableDebug(): void;
2
+ export declare function isDebugEnabled(): boolean;
3
+ /** Reset debug state. For testing only. */
4
+ export declare function resetDebug(): void;
5
+ export declare function debugLogEvent(type: string, data: unknown): void;
6
+ export declare function debugLogChatParams(model: unknown, provider: unknown): void;
7
+ //# sourceMappingURL=debug.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAUA,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAY/D;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,OAAO,GAChB,IAAI,CAaN"}
package/dist/debug.js ADDED
@@ -0,0 +1,49 @@
1
+ import { appendFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ const DEBUG_FILE = join(homedir(), ".config", "copilot-budget", "debug-events.jsonl");
5
+ // Set to true to enable debug logging of ALL events
6
+ // Controlled via config.json: { "debug": true }
7
+ let enabled = false;
8
+ export function enableDebug() {
9
+ enabled = true;
10
+ }
11
+ export function isDebugEnabled() {
12
+ return enabled;
13
+ }
14
+ /** Reset debug state. For testing only. */
15
+ export function resetDebug() {
16
+ enabled = false;
17
+ }
18
+ export function debugLogEvent(type, data) {
19
+ if (!enabled)
20
+ return;
21
+ try {
22
+ const line = JSON.stringify({
23
+ ts: new Date().toISOString(),
24
+ type,
25
+ data,
26
+ });
27
+ appendFileSync(DEBUG_FILE, line + "\n");
28
+ }
29
+ catch {
30
+ // Debug logging must never fail loudly
31
+ }
32
+ }
33
+ export function debugLogChatParams(model, provider) {
34
+ if (!enabled)
35
+ return;
36
+ try {
37
+ const line = JSON.stringify({
38
+ ts: new Date().toISOString(),
39
+ type: "chat.params",
40
+ model,
41
+ provider,
42
+ });
43
+ appendFileSync(DEBUG_FILE, line + "\n");
44
+ }
45
+ catch {
46
+ // Debug logging must never fail loudly
47
+ }
48
+ }
49
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,oBAAoB,CAAC,CAAA;AAErF,oDAAoD;AACpD,gDAAgD;AAChD,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,MAAM,UAAU,WAAW;IACzB,OAAO,GAAG,IAAI,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,UAAU;IACxB,OAAO,GAAG,KAAK,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAa;IACvD,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI;YACJ,IAAI;SACL,CAAC,CAAA;QACF,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAc,EACd,QAAiB;IAEjB,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI,EAAE,aAAa;YACnB,KAAK;YACL,QAAQ;SACT,CAAC,CAAA;QACF,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC"}