farming-code 2.2.19 → 2.2.20
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.
- package/backend/server.js +5 -1
- package/backend/terminal-screen-worker-pool.js +15 -6
- package/backend/usage-monitor.js +11 -0
- package/dist/assets/{App-CbXYBccJ.js → App-BupehIbc.js} +12 -12
- package/dist/assets/{code-dark-qIBiLBWV.css → code-dark-BAt0Q_Op.css} +1 -1
- package/dist/assets/{index-DQdtPfCk.js → index-DuMjesL2.js} +2 -2
- package/dist/assets/{main-yzZEfgft.css → main-y2aK_56c.css} +1 -1
- package/dist/index.html +1 -1
- package/frontend/skins/crt/app.js +166 -26
- package/frontend/skins/crt/index.html +5 -10
- package/frontend/skins/crt/styles/billing.css +6 -1
- package/package.json +1 -1
package/backend/server.js
CHANGED
|
@@ -744,8 +744,12 @@ app.get(routePath(BASE_PATH, '/api/claude/settings'), (req, res) => {
|
|
|
744
744
|
app.get(routePath(BASE_PATH, '/api/usage'), async (req, res) => {
|
|
745
745
|
try {
|
|
746
746
|
const fresh = req.query.fresh === '1';
|
|
747
|
+
const live = req.query.live === '1';
|
|
747
748
|
if (fresh) usageMonitor.invalidateDailyCache();
|
|
748
|
-
const usage = await usageSummaryCache.get(
|
|
749
|
+
const usage = await usageSummaryCache.get(
|
|
750
|
+
'summary',
|
|
751
|
+
fresh ? { force: true } : live ? { maxAgeMs: 15_000 } : {},
|
|
752
|
+
);
|
|
749
753
|
res.json({ usage });
|
|
750
754
|
} catch (error) {
|
|
751
755
|
res.status(500).json({ error: error.message || 'Failed to read usage information' });
|
|
@@ -23,6 +23,7 @@ class TerminalScreenWorkerPool {
|
|
|
23
23
|
this.waiters = [];
|
|
24
24
|
this.readyWaiters = [];
|
|
25
25
|
this.pendingStarts = 0;
|
|
26
|
+
this.startTasks = new Set();
|
|
26
27
|
this.consecutiveStartFailures = 0;
|
|
27
28
|
this.retryDelayMs = Number.isFinite(options.retryDelayMs)
|
|
28
29
|
? Math.max(0, Number(options.retryDelayMs))
|
|
@@ -91,13 +92,12 @@ class TerminalScreenWorkerPool {
|
|
|
91
92
|
startWorker() {
|
|
92
93
|
this.pendingStarts += 1;
|
|
93
94
|
let failed = false;
|
|
94
|
-
this.createReadyWorker()
|
|
95
|
+
const startTask = this.createReadyWorker()
|
|
95
96
|
.then((worker) => {
|
|
96
97
|
this.pendingStarts -= 1;
|
|
97
98
|
this.consecutiveStartFailures = 0;
|
|
98
99
|
if (this.disposed) {
|
|
99
|
-
worker.dispose().catch(() => {});
|
|
100
|
-
return;
|
|
100
|
+
return worker.dispose().catch(() => {});
|
|
101
101
|
}
|
|
102
102
|
this.deliverWorker(worker);
|
|
103
103
|
})
|
|
@@ -122,6 +122,11 @@ class TerminalScreenWorkerPool {
|
|
|
122
122
|
this.ensureCapacity();
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
|
+
this.startTasks.add(startTask);
|
|
126
|
+
startTask.then(
|
|
127
|
+
() => this.startTasks.delete(startTask),
|
|
128
|
+
() => this.startTasks.delete(startTask),
|
|
129
|
+
);
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
scheduleCapacityRetry() {
|
|
@@ -197,8 +202,8 @@ class TerminalScreenWorkerPool {
|
|
|
197
202
|
}
|
|
198
203
|
|
|
199
204
|
async dispose() {
|
|
200
|
-
if (this.
|
|
201
|
-
return;
|
|
205
|
+
if (this.disposePromise) {
|
|
206
|
+
return this.disposePromise;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
this.disposed = true;
|
|
@@ -210,7 +215,11 @@ class TerminalScreenWorkerPool {
|
|
|
210
215
|
this.waiters.splice(0).forEach(({ reject }) => reject(error));
|
|
211
216
|
this.readyWaiters.splice(0).forEach(({ reject }) => reject(error));
|
|
212
217
|
const workers = this.idle.splice(0);
|
|
213
|
-
|
|
218
|
+
this.disposePromise = Promise.allSettled([
|
|
219
|
+
...workers.map(worker => worker.dispose()),
|
|
220
|
+
...this.startTasks,
|
|
221
|
+
]).then(() => undefined);
|
|
222
|
+
return this.disposePromise;
|
|
214
223
|
}
|
|
215
224
|
}
|
|
216
225
|
|
package/backend/usage-monitor.js
CHANGED
|
@@ -10,6 +10,8 @@ const execFileAsync = promisify(execFile);
|
|
|
10
10
|
const USAGE_WINDOW_MS = 5 * 60 * 1000;
|
|
11
11
|
const USAGE_TIMELINE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
12
12
|
const USAGE_TIMELINE_BUCKET_COUNT = 24;
|
|
13
|
+
const USAGE_LIVE_TIMELINE_WINDOW_MS = 60 * 60 * 1000;
|
|
14
|
+
const USAGE_LIVE_TIMELINE_BUCKET_COUNT = 60;
|
|
13
15
|
const USAGE_DAILY_DAYS = 52 * 7;
|
|
14
16
|
const USAGE_DAILY_CACHE_MS = 5 * 60 * 1000;
|
|
15
17
|
const USAGE_LIVE_DAY_CACHE_MS = 5 * 1000;
|
|
@@ -1020,6 +1022,12 @@ class UsageMonitor {
|
|
|
1020
1022
|
windowMs: historyWindowMs,
|
|
1021
1023
|
alignToBucket: true,
|
|
1022
1024
|
});
|
|
1025
|
+
const liveTimeline = buildUsageTimeline(history.providerEvents, {
|
|
1026
|
+
now,
|
|
1027
|
+
windowMs: USAGE_LIVE_TIMELINE_WINDOW_MS,
|
|
1028
|
+
bucketCount: USAGE_LIVE_TIMELINE_BUCKET_COUNT,
|
|
1029
|
+
alignToBucket: true,
|
|
1030
|
+
});
|
|
1023
1031
|
const openCodeCoverage = history.coverage.find(entry => entry.provider === 'opencode');
|
|
1024
1032
|
const qoderCoverage = history.coverage.find(entry => entry.provider === 'qoder');
|
|
1025
1033
|
|
|
@@ -1027,6 +1035,7 @@ class UsageMonitor {
|
|
|
1027
1035
|
sampledAt: now,
|
|
1028
1036
|
windowMs,
|
|
1029
1037
|
timeline,
|
|
1038
|
+
liveTimeline,
|
|
1030
1039
|
daily: history.daily,
|
|
1031
1040
|
providers: [
|
|
1032
1041
|
{
|
|
@@ -1099,6 +1108,8 @@ module.exports = {
|
|
|
1099
1108
|
USAGE_WINDOW_MS,
|
|
1100
1109
|
USAGE_TIMELINE_WINDOW_MS,
|
|
1101
1110
|
USAGE_TIMELINE_BUCKET_COUNT,
|
|
1111
|
+
USAGE_LIVE_TIMELINE_WINDOW_MS,
|
|
1112
|
+
USAGE_LIVE_TIMELINE_BUCKET_COUNT,
|
|
1102
1113
|
USAGE_DAILY_DAYS,
|
|
1103
1114
|
USAGE_DAILY_CACHE_MS,
|
|
1104
1115
|
USAGE_LIVE_DAY_CACHE_MS,
|