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,11 @@
1
+ import type { ApiStatus, PremiumRequestSummary, PluginConfig } from "./types.js";
2
+ export declare function parsePremiumRequestResponse(data: unknown, config: PluginConfig): PremiumRequestSummary | null;
3
+ export declare function pollPremiumRequests(config: PluginConfig, force?: boolean): Promise<PremiumRequestSummary | null>;
4
+ export declare function getCachedPremiumRequests(): PremiumRequestSummary | null;
5
+ export declare function getApiStatus(): ApiStatus;
6
+ export declare function needsAuthSetup(): boolean;
7
+ export declare function getAuthSetupMessage(): string | null;
8
+ /** Reset all module-level state. For testing only. */
9
+ export declare function resetApiState(): void;
10
+ export declare function formatPremiumRequestStatus(pr: PremiumRequestSummary): string;
11
+ //# sourceMappingURL=github-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-api.d.ts","sourceRoot":"","sources":["../src/github-api.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,SAAS,EACT,qBAAqB,EAErB,YAAY,EACb,MAAM,YAAY,CAAA;AAoKnB,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,YAAY,GACnB,qBAAqB,GAAG,IAAI,CAkE9B;AAMD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,KAAK,UAAQ,GACZ,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAqBvC;AAED,wBAAgB,wBAAwB,IAAI,qBAAqB,GAAG,IAAI,CAEvE;AAED,wBAAgB,YAAY,IAAI,SAAS,CAExC;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAInD;AAED,sDAAsD;AACtD,wBAAgB,aAAa,IAAI,IAAI,CAUpC;AAED,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,qBAAqB,GAAG,MAAM,CAa5E"}
@@ -0,0 +1,273 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { execFileSync } from "node:child_process";
5
+ // ============================================================
6
+ // Constants
7
+ // ============================================================
8
+ const POLL_INTERVAL_MS = 15 * 60 * 1000; // 15 minutes
9
+ const AUTH_FILE = join(homedir(), ".local", "share", "opencode", "auth.json");
10
+ const GITHUB_API_BASE = "https://api.github.com";
11
+ // Monthly allowances by plan
12
+ const PLAN_ALLOWANCES = {
13
+ free: 50,
14
+ pro: 300,
15
+ "pro+": 1500,
16
+ business: 300,
17
+ enterprise: 1000,
18
+ };
19
+ // ============================================================
20
+ // State
21
+ // ============================================================
22
+ let apiStatus = {
23
+ authMethod: "none",
24
+ username: null,
25
+ lastFetch: 0,
26
+ lastError: null,
27
+ premiumRequests: null,
28
+ };
29
+ let authProbed = false;
30
+ let authNotifiedUser = false;
31
+ // ============================================================
32
+ // Auth probing
33
+ // ============================================================
34
+ function readCopilotToken() {
35
+ try {
36
+ if (!existsSync(AUTH_FILE))
37
+ return null;
38
+ const raw = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
39
+ const copilot = raw["github-copilot"];
40
+ if (copilot && typeof copilot.access === "string") {
41
+ return copilot.access;
42
+ }
43
+ return null;
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ }
49
+ async function tryFetchWithToken(url, token) {
50
+ try {
51
+ const resp = await fetch(url, {
52
+ headers: {
53
+ Accept: "application/vnd.github+json",
54
+ Authorization: `Bearer ${token}`,
55
+ "X-GitHub-Api-Version": "2022-11-28",
56
+ },
57
+ });
58
+ const data = await resp.json();
59
+ return { ok: resp.ok, status: resp.status, data };
60
+ }
61
+ catch (err) {
62
+ return { ok: false, status: 0, data: { error: String(err) } };
63
+ }
64
+ }
65
+ function tryGhCli(path) {
66
+ try {
67
+ const result = execFileSync("gh", ["api", path], {
68
+ encoding: "utf-8",
69
+ timeout: 10_000,
70
+ stdio: ["pipe", "pipe", "pipe"],
71
+ });
72
+ return { ok: true, data: JSON.parse(result) };
73
+ }
74
+ catch {
75
+ return { ok: false, data: null };
76
+ }
77
+ }
78
+ async function probeAuth() {
79
+ if (authProbed)
80
+ return;
81
+ authProbed = true;
82
+ // Try 1: Copilot OAuth token
83
+ const copilotToken = readCopilotToken();
84
+ if (copilotToken) {
85
+ const result = await tryFetchWithToken(`${GITHUB_API_BASE}/user`, copilotToken);
86
+ if (result.ok && typeof result.data === "object" && result.data !== null) {
87
+ const login = result.data.login;
88
+ if (typeof login === "string") {
89
+ apiStatus.authMethod = "copilot_token";
90
+ apiStatus.username = login;
91
+ return;
92
+ }
93
+ }
94
+ }
95
+ // Try 2: gh CLI
96
+ const ghResult = tryGhCli("/user");
97
+ if (ghResult.ok && typeof ghResult.data === "object" && ghResult.data !== null) {
98
+ const login = ghResult.data.login;
99
+ if (typeof login === "string") {
100
+ apiStatus.authMethod = "gh_cli";
101
+ apiStatus.username = login;
102
+ return;
103
+ }
104
+ }
105
+ apiStatus.authMethod = "none";
106
+ apiStatus.lastError = "No valid auth method found";
107
+ }
108
+ // ============================================================
109
+ // Fetch premium request usage
110
+ // ============================================================
111
+ async function fetchPremiumRequests(config) {
112
+ await probeAuth();
113
+ if (apiStatus.authMethod === "none" || !apiStatus.username) {
114
+ return null;
115
+ }
116
+ const now = new Date();
117
+ const year = now.getUTCFullYear();
118
+ const month = now.getUTCMonth() + 1;
119
+ const path = `/users/${apiStatus.username}/settings/billing/premium_request/usage?year=${year}&month=${month}`;
120
+ let data = null;
121
+ if (apiStatus.authMethod === "copilot_token") {
122
+ const token = readCopilotToken();
123
+ if (!token)
124
+ return null;
125
+ const result = await tryFetchWithToken(`${GITHUB_API_BASE}${path}`, token);
126
+ if (!result.ok) {
127
+ // Token might not have the right scope — try gh CLI as fallback
128
+ apiStatus.authMethod = "gh_cli";
129
+ }
130
+ else {
131
+ data = result.data;
132
+ }
133
+ }
134
+ if (apiStatus.authMethod === "gh_cli" && !data) {
135
+ const result = tryGhCli(path);
136
+ if (!result.ok) {
137
+ apiStatus.lastError = "gh CLI failed to fetch billing data. Run: gh auth refresh -h github.com -s user";
138
+ return null;
139
+ }
140
+ data = result.data;
141
+ }
142
+ if (!data)
143
+ return null;
144
+ // Parse the response
145
+ return parsePremiumRequestResponse(data, config);
146
+ }
147
+ export function parsePremiumRequestResponse(data, config) {
148
+ try {
149
+ // The API may return different structures depending on the endpoint version
150
+ // Handle both array and object responses
151
+ let items = [];
152
+ if (Array.isArray(data)) {
153
+ items = data;
154
+ }
155
+ else if (typeof data === "object" && data !== null) {
156
+ const obj = data;
157
+ if (Array.isArray(obj.usageItems)) {
158
+ items = obj.usageItems;
159
+ }
160
+ else if (Array.isArray(obj.usage_items)) {
161
+ items = obj.usage_items;
162
+ }
163
+ }
164
+ if (items.length === 0 && typeof data === "object" && data !== null) {
165
+ // Maybe the response itself is the summary
166
+ const obj = data;
167
+ if (typeof obj.total_premium_requests === "number" || typeof obj.totalPremiumRequests === "number") {
168
+ const total = (obj.total_premium_requests ?? obj.totalPremiumRequests);
169
+ const allowance = PLAN_ALLOWANCES[config.copilot_plan.toLowerCase()] ?? config.monthly_premium_allowance;
170
+ return {
171
+ totalPremiumRequests: total,
172
+ byModel: {},
173
+ byProduct: {},
174
+ monthlyAllowance: allowance,
175
+ remaining: Math.max(0, allowance - total),
176
+ percentUsed: allowance > 0 ? Math.round((total / allowance) * 100) : 0,
177
+ fetchedAt: new Date().toISOString(),
178
+ };
179
+ }
180
+ }
181
+ // Parse individual items
182
+ const byModel = {};
183
+ const byProduct = {};
184
+ let totalQuantity = 0;
185
+ for (const item of items) {
186
+ if (typeof item !== "object" || item === null)
187
+ continue;
188
+ const entry = item;
189
+ const quantity = typeof entry.quantity === "number" ? entry.quantity : 0;
190
+ const sku = typeof entry.sku === "string" ? entry.sku : "unknown";
191
+ const product = typeof entry.product === "string" ? entry.product : "unknown";
192
+ totalQuantity += quantity;
193
+ byModel[sku] = (byModel[sku] ?? 0) + quantity;
194
+ byProduct[product] = (byProduct[product] ?? 0) + quantity;
195
+ }
196
+ const allowance = PLAN_ALLOWANCES[config.copilot_plan.toLowerCase()] ?? config.monthly_premium_allowance;
197
+ return {
198
+ totalPremiumRequests: totalQuantity,
199
+ byModel,
200
+ byProduct,
201
+ monthlyAllowance: allowance,
202
+ remaining: Math.max(0, allowance - totalQuantity),
203
+ percentUsed: allowance > 0 ? Math.round((totalQuantity / allowance) * 100) : 0,
204
+ fetchedAt: new Date().toISOString(),
205
+ };
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ // ============================================================
212
+ // Public API
213
+ // ============================================================
214
+ export async function pollPremiumRequests(config, force = false) {
215
+ const now = Date.now();
216
+ // Don't poll more often than the interval
217
+ if (!force && now - apiStatus.lastFetch < POLL_INTERVAL_MS) {
218
+ return apiStatus.premiumRequests;
219
+ }
220
+ apiStatus.lastFetch = now;
221
+ try {
222
+ const result = await fetchPremiumRequests(config);
223
+ if (result) {
224
+ apiStatus.premiumRequests = result;
225
+ apiStatus.lastError = null;
226
+ }
227
+ return result;
228
+ }
229
+ catch (err) {
230
+ apiStatus.lastError = err instanceof Error ? err.message : String(err);
231
+ return apiStatus.premiumRequests; // Return cached data on error
232
+ }
233
+ }
234
+ export function getCachedPremiumRequests() {
235
+ return apiStatus.premiumRequests;
236
+ }
237
+ export function getApiStatus() {
238
+ return { ...apiStatus };
239
+ }
240
+ export function needsAuthSetup() {
241
+ return authProbed && apiStatus.authMethod === "none";
242
+ }
243
+ export function getAuthSetupMessage() {
244
+ if (!needsAuthSetup() || authNotifiedUser)
245
+ return null;
246
+ authNotifiedUser = true;
247
+ return "To enable premium request tracking from the GitHub API, run:\n`gh auth refresh -h github.com -s user`\nThen restart OpenCode. Without this, the plugin uses empirical tracking only.";
248
+ }
249
+ /** Reset all module-level state. For testing only. */
250
+ export function resetApiState() {
251
+ apiStatus = {
252
+ authMethod: "none",
253
+ username: null,
254
+ lastFetch: 0,
255
+ lastError: null,
256
+ premiumRequests: null,
257
+ };
258
+ authProbed = false;
259
+ authNotifiedUser = false;
260
+ }
261
+ export function formatPremiumRequestStatus(pr) {
262
+ const lines = [
263
+ `Premium requests this month: ${pr.totalPremiumRequests} / ${pr.monthlyAllowance} (${pr.percentUsed}% used, ${pr.remaining} remaining)`,
264
+ ];
265
+ const modelEntries = Object.entries(pr.byModel);
266
+ if (modelEntries.length > 0) {
267
+ for (const [model, count] of modelEntries.sort((a, b) => b[1] - a[1])) {
268
+ lines.push(` ${model}: ${count} requests`);
269
+ }
270
+ }
271
+ return lines.join("\n");
272
+ }
273
+ //# sourceMappingURL=github-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-api.js","sourceRoot":"","sources":["../src/github-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { ObservationEvent, PluginConfig } from "./types.js";
2
+ export declare function ensureDataDir(): void;
3
+ export declare function isWritable(): boolean;
4
+ export declare function appendObservation(event: ObservationEvent): void;
5
+ export declare function readObservations(filter?: {
6
+ since?: string;
7
+ type?: string;
8
+ }): ObservationEvent[];
9
+ export declare function readTodayObservations(today: string): ObservationEvent[];
10
+ export declare function readEstimates(): Record<string, unknown> | null;
11
+ export declare function writeEstimates(data: Record<string, unknown> | object): void;
12
+ export declare function readConfig(): PluginConfig;
13
+ export declare function getDataDir(): string;
14
+ export interface PersistenceInstance {
15
+ ensureDataDir(): void;
16
+ appendObservation(event: ObservationEvent): void;
17
+ readObservations(filter?: {
18
+ since?: string;
19
+ type?: string;
20
+ }): ObservationEvent[];
21
+ readTodayObservations(today: string): ObservationEvent[];
22
+ readEstimates(): Record<string, unknown> | null;
23
+ writeEstimates(data: Record<string, unknown> | object): void;
24
+ readConfig(): PluginConfig;
25
+ getDataDir(): string;
26
+ }
27
+ export declare function createPersistence(dataDir: string): PersistenceInstance;
28
+ //# sourceMappingURL=persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAahE,wBAAgB,aAAa,IAAI,IAAI,CASpC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAMD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAY/D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,gBAAgB,EAAE,CAerB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAEvE;AAgFD,wBAAgB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAO9D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAQ3E;AAMD,wBAAgB,UAAU,IAAI,YAAY,CAQzC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAMD,MAAM,WAAW,mBAAmB;IAClC,aAAa,IAAI,IAAI,CAAA;IACrB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAChD,gBAAgB,CAAC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,gBAAgB,EAAE,CAAA;IAChF,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAAA;IACxD,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAC/C,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,UAAU,IAAI,YAAY,CAAA;IAC1B,UAAU,IAAI,MAAM,CAAA;CACrB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAkEtE"}
@@ -0,0 +1,246 @@
1
+ import { appendFileSync, readFileSync, writeFileSync, renameSync, existsSync, mkdirSync, statSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ import { DEFAULT_CONFIG } from "./types.js";
5
+ const DATA_DIR = join(homedir(), ".config", "copilot-budget");
6
+ const OBSERVATIONS_FILE = join(DATA_DIR, "observations.jsonl");
7
+ const ESTIMATES_FILE = join(DATA_DIR, "estimates.json");
8
+ const CONFIG_FILE = join(DATA_DIR, "config.json");
9
+ const MAX_JSONL_SIZE_BYTES = 50 * 1024 * 1024; // 50 MB
10
+ const MAX_JSONL_AGE_DAYS = 90;
11
+ let writable = true; // Track if the data dir is writable
12
+ export function ensureDataDir() {
13
+ try {
14
+ if (!existsSync(DATA_DIR)) {
15
+ mkdirSync(DATA_DIR, { recursive: true });
16
+ }
17
+ writable = true;
18
+ }
19
+ catch {
20
+ writable = false;
21
+ }
22
+ }
23
+ export function isWritable() {
24
+ return writable;
25
+ }
26
+ // ============================================================
27
+ // observations.jsonl
28
+ // ============================================================
29
+ export function appendObservation(event) {
30
+ if (!writable)
31
+ return;
32
+ try {
33
+ ensureDataDir();
34
+ const line = JSON.stringify(event);
35
+ appendFileSync(OBSERVATIONS_FILE, line + "\n");
36
+ // Check if rotation needed
37
+ maybeRotateJsonl();
38
+ }
39
+ catch {
40
+ // Graceful degradation — don't crash if we can't write
41
+ }
42
+ }
43
+ export function readObservations(filter) {
44
+ if (!existsSync(OBSERVATIONS_FILE))
45
+ return [];
46
+ try {
47
+ return readFileSync(OBSERVATIONS_FILE, "utf-8")
48
+ .split("\n")
49
+ .filter(Boolean)
50
+ .map((line) => JSON.parse(line))
51
+ .filter((e) => {
52
+ if (filter?.since && e.ts < filter.since)
53
+ return false;
54
+ if (filter?.type && e.type !== filter.type)
55
+ return false;
56
+ return true;
57
+ });
58
+ }
59
+ catch {
60
+ return [];
61
+ }
62
+ }
63
+ export function readTodayObservations(today) {
64
+ return readObservations({ since: today + "T00:00:00" });
65
+ }
66
+ // ============================================================
67
+ // JSONL rotation
68
+ // ============================================================
69
+ let lastRotationCheck = 0;
70
+ function maybeRotateJsonl() {
71
+ // Only check every 5 minutes
72
+ const now = Date.now();
73
+ if (now - lastRotationCheck < 5 * 60 * 1000)
74
+ return;
75
+ lastRotationCheck = now;
76
+ try {
77
+ if (!existsSync(OBSERVATIONS_FILE))
78
+ return;
79
+ const stats = statSync(OBSERVATIONS_FILE);
80
+ // Rotate by size
81
+ if (stats.size > MAX_JSONL_SIZE_BYTES) {
82
+ rotateJsonl("size_exceeded");
83
+ return;
84
+ }
85
+ // Rotate by age: check if the oldest entry is > MAX_JSONL_AGE_DAYS old
86
+ const allObs = readObservations();
87
+ if (allObs.length > 0) {
88
+ const oldest = new Date(allObs[0].ts);
89
+ const ageDays = (Date.now() - oldest.getTime()) / (24 * 60 * 60 * 1000);
90
+ if (ageDays > MAX_JSONL_AGE_DAYS) {
91
+ // Keep last 30 days, archive the rest
92
+ const cutoff = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
93
+ const recent = allObs.filter((e) => e.ts >= cutoff);
94
+ // Write recent events to temp file, then swap with rollback on failure
95
+ const recentContent = recent.map((e) => JSON.stringify(e)).join("\n") + "\n";
96
+ const tempPath = OBSERVATIONS_FILE + ".tmp";
97
+ writeFileSync(tempPath, recentContent);
98
+ const archivePath = safeArchivePath("archive");
99
+ renameSync(OBSERVATIONS_FILE, archivePath);
100
+ try {
101
+ renameSync(tempPath, OBSERVATIONS_FILE);
102
+ }
103
+ catch {
104
+ // Rollback: restore original from archive
105
+ try {
106
+ renameSync(archivePath, OBSERVATIONS_FILE);
107
+ }
108
+ catch { /* best effort */ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ catch {
114
+ // Rotation failure is not critical
115
+ }
116
+ }
117
+ function safeArchivePath(reason) {
118
+ // Use full ISO timestamp (colons replaced for filesystem safety) to avoid collisions
119
+ const ts = new Date().toISOString().replace(/:/g, "-");
120
+ let path = join(DATA_DIR, `observations.${ts}.${reason}.jsonl`);
121
+ // If somehow exists (very unlikely with millisecond timestamps), add a counter
122
+ let counter = 1;
123
+ while (existsSync(path)) {
124
+ path = join(DATA_DIR, `observations.${ts}.${reason}.${counter}.jsonl`);
125
+ counter++;
126
+ }
127
+ return path;
128
+ }
129
+ function rotateJsonl(reason) {
130
+ try {
131
+ const archivePath = safeArchivePath(reason);
132
+ renameSync(OBSERVATIONS_FILE, archivePath);
133
+ }
134
+ catch {
135
+ // Archive failure is not critical
136
+ }
137
+ }
138
+ // ============================================================
139
+ // estimates.json
140
+ // ============================================================
141
+ export function readEstimates() {
142
+ if (!existsSync(ESTIMATES_FILE))
143
+ return null;
144
+ try {
145
+ return JSON.parse(readFileSync(ESTIMATES_FILE, "utf-8"));
146
+ }
147
+ catch {
148
+ return null;
149
+ }
150
+ }
151
+ export function writeEstimates(data) {
152
+ if (!writable)
153
+ return;
154
+ try {
155
+ ensureDataDir();
156
+ writeFileSync(ESTIMATES_FILE, JSON.stringify(data, null, 2) + "\n");
157
+ }
158
+ catch {
159
+ // Graceful degradation
160
+ }
161
+ }
162
+ // ============================================================
163
+ // config.json
164
+ // ============================================================
165
+ export function readConfig() {
166
+ if (!existsSync(CONFIG_FILE))
167
+ return { ...DEFAULT_CONFIG };
168
+ try {
169
+ const raw = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
170
+ return { ...DEFAULT_CONFIG, ...raw };
171
+ }
172
+ catch {
173
+ return { ...DEFAULT_CONFIG };
174
+ }
175
+ }
176
+ export function getDataDir() {
177
+ return DATA_DIR;
178
+ }
179
+ export function createPersistence(dataDir) {
180
+ const obsFile = join(dataDir, "observations.jsonl");
181
+ const estFile = join(dataDir, "estimates.json");
182
+ const cfgFile = join(dataDir, "config.json");
183
+ return {
184
+ ensureDataDir() {
185
+ if (!existsSync(dataDir)) {
186
+ mkdirSync(dataDir, { recursive: true });
187
+ }
188
+ },
189
+ appendObservation(event) {
190
+ this.ensureDataDir();
191
+ appendFileSync(obsFile, JSON.stringify(event) + "\n");
192
+ },
193
+ readObservations(filter) {
194
+ if (!existsSync(obsFile))
195
+ return [];
196
+ try {
197
+ return readFileSync(obsFile, "utf-8")
198
+ .split("\n")
199
+ .filter(Boolean)
200
+ .map((line) => JSON.parse(line))
201
+ .filter((e) => {
202
+ if (filter?.since && e.ts < filter.since)
203
+ return false;
204
+ if (filter?.type && e.type !== filter.type)
205
+ return false;
206
+ return true;
207
+ });
208
+ }
209
+ catch {
210
+ return [];
211
+ }
212
+ },
213
+ readTodayObservations(today) {
214
+ return this.readObservations({ since: today + "T00:00:00" });
215
+ },
216
+ readEstimates() {
217
+ if (!existsSync(estFile))
218
+ return null;
219
+ try {
220
+ return JSON.parse(readFileSync(estFile, "utf-8"));
221
+ }
222
+ catch {
223
+ return null;
224
+ }
225
+ },
226
+ writeEstimates(data) {
227
+ this.ensureDataDir();
228
+ writeFileSync(estFile, JSON.stringify(data, null, 2) + "\n");
229
+ },
230
+ readConfig() {
231
+ if (!existsSync(cfgFile))
232
+ return { ...DEFAULT_CONFIG };
233
+ try {
234
+ const raw = JSON.parse(readFileSync(cfgFile, "utf-8"));
235
+ return { ...DEFAULT_CONFIG, ...raw };
236
+ }
237
+ catch {
238
+ return { ...DEFAULT_CONFIG };
239
+ }
240
+ },
241
+ getDataDir() {
242
+ return dataDir;
243
+ },
244
+ };
245
+ }
246
+ //# sourceMappingURL=persistence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export declare function formatStatus(): string;
2
+ export declare function formatHistory(days: number): string;
3
+ export declare function formatErrors(): string;
4
+ export declare function formatInsights(): string;
5
+ export declare const budgetTool: {
6
+ description: string;
7
+ args: {
8
+ action: import("zod").ZodEnum<{
9
+ insights: "insights";
10
+ status: "status";
11
+ history: "history";
12
+ errors: "errors";
13
+ recompute: "recompute";
14
+ }>;
15
+ };
16
+ execute(args: {
17
+ action: "insights" | "status" | "history" | "errors" | "recompute";
18
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
19
+ };
20
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAYA,wBAAgB,YAAY,IAAI,MAAM,CA8HrC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwBlD;AAED,wBAAgB,YAAY,IAAI,MAAM,CA0ErC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAoFvC;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;;;;CA6BrB,CAAA"}