oc2token 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.
- package/LICENSE +21 -0
- package/README.md +399 -0
- package/dist/src/accounting/index.d.ts +1 -0
- package/dist/src/accounting/index.js +2 -0
- package/dist/src/accounting/index.js.map +1 -0
- package/dist/src/accounting/reducer.d.ts +21 -0
- package/dist/src/accounting/reducer.js +105 -0
- package/dist/src/accounting/reducer.js.map +1 -0
- package/dist/src/antigravity/discovery.d.ts +18 -0
- package/dist/src/antigravity/discovery.js +95 -0
- package/dist/src/antigravity/discovery.js.map +1 -0
- package/dist/src/antigravity/doctor.d.ts +6 -0
- package/dist/src/antigravity/doctor.js +78 -0
- package/dist/src/antigravity/doctor.js.map +1 -0
- package/dist/src/antigravity/index.d.ts +3 -0
- package/dist/src/antigravity/index.js +4 -0
- package/dist/src/antigravity/index.js.map +1 -0
- package/dist/src/antigravity/proto.d.ts +73 -0
- package/dist/src/antigravity/proto.js +259 -0
- package/dist/src/antigravity/proto.js.map +1 -0
- package/dist/src/antigravity/scanner.d.ts +8 -0
- package/dist/src/antigravity/scanner.js +552 -0
- package/dist/src/antigravity/scanner.js.map +1 -0
- package/dist/src/application.d.ts +73 -0
- package/dist/src/application.js +657 -0
- package/dist/src/application.js.map +1 -0
- package/dist/src/cache/filesystem.d.ts +8 -0
- package/dist/src/cache/filesystem.js +70 -0
- package/dist/src/cache/filesystem.js.map +1 -0
- package/dist/src/cache/index.d.ts +5 -0
- package/dist/src/cache/index.js +6 -0
- package/dist/src/cache/index.js.map +1 -0
- package/dist/src/cache/lock.d.ts +40 -0
- package/dist/src/cache/lock.js +227 -0
- package/dist/src/cache/lock.js.map +1 -0
- package/dist/src/cache/schema.d.ts +45 -0
- package/dist/src/cache/schema.js +308 -0
- package/dist/src/cache/schema.js.map +1 -0
- package/dist/src/cache/store.d.ts +46 -0
- package/dist/src/cache/store.js +396 -0
- package/dist/src/cache/store.js.map +1 -0
- package/dist/src/cache/types.d.ts +130 -0
- package/dist/src/cache/types.js +6 -0
- package/dist/src/cache/types.js.map +1 -0
- package/dist/src/cli.d.ts +8 -0
- package/dist/src/cli.js +874 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/codex/discovery.d.ts +6 -0
- package/dist/src/codex/discovery.js +88 -0
- package/dist/src/codex/discovery.js.map +1 -0
- package/dist/src/codex/doctor.d.ts +6 -0
- package/dist/src/codex/doctor.js +52 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/index.d.ts +3 -0
- package/dist/src/codex/index.js +3 -0
- package/dist/src/codex/index.js.map +1 -0
- package/dist/src/codex/scanner.d.ts +6 -0
- package/dist/src/codex/scanner.js +487 -0
- package/dist/src/codex/scanner.js.map +1 -0
- package/dist/src/codex/types.d.ts +31 -0
- package/dist/src/codex/types.js +5 -0
- package/dist/src/codex/types.js.map +1 -0
- package/dist/src/collector/collector.d.ts +15 -0
- package/dist/src/collector/collector.js +597 -0
- package/dist/src/collector/collector.js.map +1 -0
- package/dist/src/collector/index.d.ts +3 -0
- package/dist/src/collector/index.js +3 -0
- package/dist/src/collector/index.js.map +1 -0
- package/dist/src/collector/types.d.ts +55 -0
- package/dist/src/collector/types.js +18 -0
- package/dist/src/collector/types.js.map +1 -0
- package/dist/src/dashboard/render/ansi.d.ts +53 -0
- package/dist/src/dashboard/render/ansi.js +106 -0
- package/dist/src/dashboard/render/ansi.js.map +1 -0
- package/dist/src/dashboard/render/dashboard.d.ts +13 -0
- package/dist/src/dashboard/render/dashboard.js +750 -0
- package/dist/src/dashboard/render/dashboard.js.map +1 -0
- package/dist/src/dashboard/render/format.d.ts +23 -0
- package/dist/src/dashboard/render/format.js +169 -0
- package/dist/src/dashboard/render/format.js.map +1 -0
- package/dist/src/dashboard/render/redraw.d.ts +13 -0
- package/dist/src/dashboard/render/redraw.js +24 -0
- package/dist/src/dashboard/render/redraw.js.map +1 -0
- package/dist/src/dashboard/render/types.d.ts +83 -0
- package/dist/src/dashboard/render/types.js +528 -0
- package/dist/src/dashboard/render/types.js.map +1 -0
- package/dist/src/dashboard/scheduler/index.d.ts +1 -0
- package/dist/src/dashboard/scheduler/index.js +2 -0
- package/dist/src/dashboard/scheduler/index.js.map +1 -0
- package/dist/src/dashboard/scheduler/refresh-scheduler.d.ts +46 -0
- package/dist/src/dashboard/scheduler/refresh-scheduler.js +137 -0
- package/dist/src/dashboard/scheduler/refresh-scheduler.js.map +1 -0
- package/dist/src/dashboard/settings/index.d.ts +25 -0
- package/dist/src/dashboard/settings/index.js +162 -0
- package/dist/src/dashboard/settings/index.js.map +1 -0
- package/dist/src/dashboard/state/index.d.ts +2 -0
- package/dist/src/dashboard/state/index.js +3 -0
- package/dist/src/dashboard/state/index.js.map +1 -0
- package/dist/src/dashboard/state/refresh-coordinator.d.ts +72 -0
- package/dist/src/dashboard/state/refresh-coordinator.js +346 -0
- package/dist/src/dashboard/state/refresh-coordinator.js.map +1 -0
- package/dist/src/dashboard/state/types.d.ts +68 -0
- package/dist/src/dashboard/state/types.js +2 -0
- package/dist/src/dashboard/state/types.js.map +1 -0
- package/dist/src/domain/contracts.d.ts +219 -0
- package/dist/src/domain/contracts.js +2 -0
- package/dist/src/domain/contracts.js.map +1 -0
- package/dist/src/domain/errors.d.ts +25 -0
- package/dist/src/domain/errors.js +65 -0
- package/dist/src/domain/errors.js.map +1 -0
- package/dist/src/domain/index.d.ts +5 -0
- package/dist/src/domain/index.js +6 -0
- package/dist/src/domain/index.js.map +1 -0
- package/dist/src/domain/records.d.ts +59 -0
- package/dist/src/domain/records.js +141 -0
- package/dist/src/domain/records.js.map +1 -0
- package/dist/src/domain/tokens.d.ts +51 -0
- package/dist/src/domain/tokens.js +93 -0
- package/dist/src/domain/tokens.js.map +1 -0
- package/dist/src/domain/windows.d.ts +59 -0
- package/dist/src/domain/windows.js +272 -0
- package/dist/src/domain/windows.js.map +1 -0
- package/dist/src/index.d.ts +9 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/opencode/adapter.d.ts +47 -0
- package/dist/src/opencode/adapter.js +118 -0
- package/dist/src/opencode/adapter.js.map +1 -0
- package/dist/src/opencode/client.d.ts +64 -0
- package/dist/src/opencode/client.js +118 -0
- package/dist/src/opencode/client.js.map +1 -0
- package/dist/src/opencode/doctor.d.ts +28 -0
- package/dist/src/opencode/doctor.js +82 -0
- package/dist/src/opencode/doctor.js.map +1 -0
- package/dist/src/opencode/index.d.ts +5 -0
- package/dist/src/opencode/index.js +6 -0
- package/dist/src/opencode/index.js.map +1 -0
- package/dist/src/opencode/stats.d.ts +8 -0
- package/dist/src/opencode/stats.js +174 -0
- package/dist/src/opencode/stats.js.map +1 -0
- package/dist/src/opencode/transport.d.ts +54 -0
- package/dist/src/opencode/transport.js +621 -0
- package/dist/src/opencode/transport.js.map +1 -0
- package/dist/src/output/index.d.ts +20 -0
- package/dist/src/output/index.js +46 -0
- package/dist/src/output/index.js.map +1 -0
- package/dist/src/output/json.d.ts +72 -0
- package/dist/src/output/json.js +133 -0
- package/dist/src/output/json.js.map +1 -0
- package/dist/src/output/table.d.ts +4 -0
- package/dist/src/output/table.js +81 -0
- package/dist/src/output/table.js.map +1 -0
- package/dist/src/pricing/index.d.ts +1 -0
- package/dist/src/pricing/index.js +2 -0
- package/dist/src/pricing/index.js.map +1 -0
- package/dist/src/pricing/pricing.d.ts +19 -0
- package/dist/src/pricing/pricing.js +441 -0
- package/dist/src/pricing/pricing.js.map +1 -0
- package/package.json +27 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { createUsageWindows } from "../../domain/windows.js";
|
|
2
|
+
import { RefreshScheduler, } from "../scheduler/refresh-scheduler.js";
|
|
3
|
+
const REASON_PRIORITY = {
|
|
4
|
+
timer: 1,
|
|
5
|
+
wake: 2,
|
|
6
|
+
manual: 3,
|
|
7
|
+
};
|
|
8
|
+
function copyDate(date) {
|
|
9
|
+
return new Date(date.getTime());
|
|
10
|
+
}
|
|
11
|
+
function cancelledOutcome(generation, reason) {
|
|
12
|
+
return { kind: "cancelled", generation, reason };
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Owns every visible refresh transition. Sources do not mutate dashboard
|
|
16
|
+
* state; they return one result which is committed only by its current
|
|
17
|
+
* generation.
|
|
18
|
+
*/
|
|
19
|
+
export class RefreshCoordinator {
|
|
20
|
+
source;
|
|
21
|
+
clock;
|
|
22
|
+
timezone;
|
|
23
|
+
project;
|
|
24
|
+
listeners = new Set();
|
|
25
|
+
scheduler;
|
|
26
|
+
cleanupTimeoutMilliseconds;
|
|
27
|
+
state;
|
|
28
|
+
active;
|
|
29
|
+
pendingReason;
|
|
30
|
+
pendingWaiters = [];
|
|
31
|
+
nextGeneration = 0;
|
|
32
|
+
started = false;
|
|
33
|
+
quitting = false;
|
|
34
|
+
startPromise;
|
|
35
|
+
configuredOnStateChange;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
this.source = options.source;
|
|
38
|
+
this.clock = options.clock;
|
|
39
|
+
this.timezone = options.timezone;
|
|
40
|
+
this.project = options.project;
|
|
41
|
+
this.cleanupTimeoutMilliseconds = options.cleanupTimeoutMilliseconds ?? 250;
|
|
42
|
+
if (!Number.isFinite(this.cleanupTimeoutMilliseconds) || this.cleanupTimeoutMilliseconds < 0) {
|
|
43
|
+
throw new RangeError("cleanupTimeoutMilliseconds must be non-negative");
|
|
44
|
+
}
|
|
45
|
+
this.configuredOnStateChange = options.onStateChange;
|
|
46
|
+
this.state = {
|
|
47
|
+
status: "idle",
|
|
48
|
+
generation: 0,
|
|
49
|
+
stale: false,
|
|
50
|
+
period: options.initialPeriod ?? "day",
|
|
51
|
+
navigation: options.initialNavigation ?? {},
|
|
52
|
+
...(options.initialSnapshot === undefined
|
|
53
|
+
? {}
|
|
54
|
+
: {
|
|
55
|
+
snapshot: options.initialSnapshot,
|
|
56
|
+
lastGoodSnapshot: options.initialSnapshot,
|
|
57
|
+
lastUpdated: new Date(options.initialSnapshot.capturedAt.getTime()),
|
|
58
|
+
stale: true,
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
this.scheduler = options.scheduler ?? new RefreshScheduler({
|
|
62
|
+
clock: options.clock,
|
|
63
|
+
refreshIntervalSeconds: options.refreshIntervalSeconds,
|
|
64
|
+
timers: options.timers,
|
|
65
|
+
onRequest: (reason) => this.handleScheduledRequest(reason),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
get refreshScheduler() {
|
|
69
|
+
return this.scheduler;
|
|
70
|
+
}
|
|
71
|
+
get isRefreshing() {
|
|
72
|
+
return this.active !== undefined;
|
|
73
|
+
}
|
|
74
|
+
get isStopped() {
|
|
75
|
+
return this.quitting;
|
|
76
|
+
}
|
|
77
|
+
getState() {
|
|
78
|
+
// Dates are copied so a renderer cannot mutate coordinator state between
|
|
79
|
+
// event-loop turns. Result/navigation are owned by their immutable seams.
|
|
80
|
+
return {
|
|
81
|
+
...this.state,
|
|
82
|
+
...(this.state.lastUpdated === undefined
|
|
83
|
+
? {}
|
|
84
|
+
: { lastUpdated: copyDate(this.state.lastUpdated) }),
|
|
85
|
+
...(this.state.nextRefreshAt === undefined
|
|
86
|
+
? {}
|
|
87
|
+
: { nextRefreshAt: this.state.nextRefreshAt }),
|
|
88
|
+
...(this.active === undefined ? {} : { activeGeneration: this.active.generation }),
|
|
89
|
+
...(this.scheduler.nextRefreshAt() === undefined
|
|
90
|
+
? { nextRefreshAt: undefined, countdownSeconds: undefined }
|
|
91
|
+
: {
|
|
92
|
+
nextRefreshAt: this.scheduler.nextRefreshAt(),
|
|
93
|
+
countdownSeconds: this.scheduler.countdownSeconds(),
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
subscribe(listener) {
|
|
98
|
+
this.listeners.add(listener);
|
|
99
|
+
return () => this.listeners.delete(listener);
|
|
100
|
+
}
|
|
101
|
+
setPeriod(period) {
|
|
102
|
+
this.state = { ...this.state, period };
|
|
103
|
+
this.emit();
|
|
104
|
+
}
|
|
105
|
+
setNavigation(navigation) {
|
|
106
|
+
this.state = { ...this.state, navigation };
|
|
107
|
+
this.emit();
|
|
108
|
+
}
|
|
109
|
+
get refreshIntervalSeconds() {
|
|
110
|
+
return this.scheduler.refreshIntervalSeconds
|
|
111
|
+
?? this.scheduler.refreshIntervalSeconds
|
|
112
|
+
?? 0;
|
|
113
|
+
}
|
|
114
|
+
setRefreshIntervalSeconds(seconds) {
|
|
115
|
+
if (this.scheduler.setRefreshIntervalSeconds === undefined) {
|
|
116
|
+
throw new Error("Scheduler does not support dynamic interval updates");
|
|
117
|
+
}
|
|
118
|
+
this.scheduler.setRefreshIntervalSeconds(seconds);
|
|
119
|
+
this.emit();
|
|
120
|
+
}
|
|
121
|
+
/** Start the scheduler and immediately issue exactly one initial refresh. */
|
|
122
|
+
start() {
|
|
123
|
+
if (this.started) {
|
|
124
|
+
return this.startPromise ?? Promise.resolve(cancelledOutcome(this.nextGeneration, "initial"));
|
|
125
|
+
}
|
|
126
|
+
this.started = true;
|
|
127
|
+
this.scheduler.start();
|
|
128
|
+
this.startPromise = this.begin("initial");
|
|
129
|
+
return this.startPromise;
|
|
130
|
+
}
|
|
131
|
+
/** Request a refresh; concurrent requests are reduced to one pending reason. */
|
|
132
|
+
request(reason = "manual") {
|
|
133
|
+
if (!this.started || this.quitting) {
|
|
134
|
+
return Promise.resolve(cancelledOutcome(this.nextGeneration, reason));
|
|
135
|
+
}
|
|
136
|
+
if (reason === "manual" || reason === "wake") {
|
|
137
|
+
this.scheduler.reset();
|
|
138
|
+
}
|
|
139
|
+
if (this.active !== undefined) {
|
|
140
|
+
if (reason === "initial") {
|
|
141
|
+
return this.active.promise;
|
|
142
|
+
}
|
|
143
|
+
this.pendingReason = this.mergePendingReason(this.pendingReason, reason);
|
|
144
|
+
this.state = { ...this.state, pendingReason: this.pendingReason };
|
|
145
|
+
this.emit();
|
|
146
|
+
return new Promise((resolve) => {
|
|
147
|
+
this.pendingWaiters.push({ resolve });
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return this.begin(reason);
|
|
151
|
+
}
|
|
152
|
+
refresh() {
|
|
153
|
+
return this.request("manual");
|
|
154
|
+
}
|
|
155
|
+
manualRefresh() {
|
|
156
|
+
return this.request("manual");
|
|
157
|
+
}
|
|
158
|
+
wake() {
|
|
159
|
+
return this.request("wake");
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Stop scheduling, invalidate the current generation, abort network work,
|
|
163
|
+
* and wait only briefly for sources which honor cancellation.
|
|
164
|
+
*/
|
|
165
|
+
async quit() {
|
|
166
|
+
if (this.quitting) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.quitting = true;
|
|
170
|
+
this.scheduler.stop();
|
|
171
|
+
this.nextGeneration += 1;
|
|
172
|
+
const active = this.active;
|
|
173
|
+
if (active !== undefined) {
|
|
174
|
+
active.controller.abort();
|
|
175
|
+
}
|
|
176
|
+
const cancelled = cancelledOutcome(this.nextGeneration, "manual");
|
|
177
|
+
for (const waiter of this.pendingWaiters) {
|
|
178
|
+
waiter.resolve(cancelled);
|
|
179
|
+
}
|
|
180
|
+
this.pendingWaiters = [];
|
|
181
|
+
this.pendingReason = undefined;
|
|
182
|
+
this.state = {
|
|
183
|
+
...this.state,
|
|
184
|
+
status: "stopped",
|
|
185
|
+
generation: this.nextGeneration,
|
|
186
|
+
activeGeneration: undefined,
|
|
187
|
+
pendingReason: undefined,
|
|
188
|
+
};
|
|
189
|
+
this.emit();
|
|
190
|
+
if (active !== undefined) {
|
|
191
|
+
await this.waitForCleanup(active.promise);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
begin(reason) {
|
|
195
|
+
if (this.quitting) {
|
|
196
|
+
return Promise.resolve(cancelledOutcome(this.nextGeneration, reason));
|
|
197
|
+
}
|
|
198
|
+
const generation = ++this.nextGeneration;
|
|
199
|
+
const controller = new AbortController();
|
|
200
|
+
const wallNow = copyDate(this.clock.wallNow());
|
|
201
|
+
const monotonicStartedAt = this.clock.monotonicNow();
|
|
202
|
+
const active = {
|
|
203
|
+
generation,
|
|
204
|
+
reason,
|
|
205
|
+
controller,
|
|
206
|
+
promise: Promise.resolve(cancelledOutcome(generation, reason)),
|
|
207
|
+
};
|
|
208
|
+
this.active = active;
|
|
209
|
+
this.state = {
|
|
210
|
+
...this.state,
|
|
211
|
+
status: "refreshing",
|
|
212
|
+
generation,
|
|
213
|
+
activeGeneration: generation,
|
|
214
|
+
pendingReason: undefined,
|
|
215
|
+
// A previous result remains visible while the next one is loading.
|
|
216
|
+
stale: this.state.lastGoodSnapshot !== undefined,
|
|
217
|
+
};
|
|
218
|
+
this.emit();
|
|
219
|
+
active.promise = Promise.resolve()
|
|
220
|
+
.then(() => {
|
|
221
|
+
const request = {
|
|
222
|
+
generation,
|
|
223
|
+
reason,
|
|
224
|
+
wallNow,
|
|
225
|
+
monotonicStartedAt,
|
|
226
|
+
capturedAt: wallNow,
|
|
227
|
+
windows: Object.values(createUsageWindows(wallNow, this.timezone)),
|
|
228
|
+
...(this.project === undefined ? {} : { project: this.project }),
|
|
229
|
+
includeSubagents: true,
|
|
230
|
+
includeProvisional: false,
|
|
231
|
+
signal: controller.signal,
|
|
232
|
+
};
|
|
233
|
+
return this.source.collect(request);
|
|
234
|
+
})
|
|
235
|
+
.then((result) => {
|
|
236
|
+
if (this.quitting ||
|
|
237
|
+
controller.signal.aborted ||
|
|
238
|
+
this.active !== active ||
|
|
239
|
+
this.nextGeneration !== generation) {
|
|
240
|
+
return { kind: "discarded", generation, reason };
|
|
241
|
+
}
|
|
242
|
+
const lastUpdated = copyDate(this.clock.wallNow());
|
|
243
|
+
this.state = {
|
|
244
|
+
...this.state,
|
|
245
|
+
status: "ready",
|
|
246
|
+
generation,
|
|
247
|
+
activeGeneration: undefined,
|
|
248
|
+
snapshot: result,
|
|
249
|
+
lastGoodSnapshot: result,
|
|
250
|
+
lastUpdated,
|
|
251
|
+
lastError: undefined,
|
|
252
|
+
stale: false,
|
|
253
|
+
};
|
|
254
|
+
this.emit();
|
|
255
|
+
return { kind: "committed", generation, reason, result };
|
|
256
|
+
}, (error) => {
|
|
257
|
+
if (this.quitting ||
|
|
258
|
+
controller.signal.aborted ||
|
|
259
|
+
this.active !== active ||
|
|
260
|
+
this.nextGeneration !== generation) {
|
|
261
|
+
return { kind: "cancelled", generation, reason, error };
|
|
262
|
+
}
|
|
263
|
+
this.state = {
|
|
264
|
+
...this.state,
|
|
265
|
+
status: "error",
|
|
266
|
+
generation,
|
|
267
|
+
activeGeneration: undefined,
|
|
268
|
+
// Keep the last good snapshot in both fields. A renderer can show
|
|
269
|
+
// the error without losing the most recent trustworthy totals.
|
|
270
|
+
snapshot: this.state.lastGoodSnapshot,
|
|
271
|
+
lastError: error,
|
|
272
|
+
stale: this.state.lastGoodSnapshot !== undefined,
|
|
273
|
+
};
|
|
274
|
+
this.emit();
|
|
275
|
+
return { kind: "failed", generation, reason, error };
|
|
276
|
+
})
|
|
277
|
+
.finally(() => {
|
|
278
|
+
if (this.active !== active) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.active = undefined;
|
|
282
|
+
this.state = {
|
|
283
|
+
...this.state,
|
|
284
|
+
activeGeneration: undefined,
|
|
285
|
+
};
|
|
286
|
+
this.emit();
|
|
287
|
+
if (!this.quitting && this.pendingReason !== undefined) {
|
|
288
|
+
const pendingReason = this.pendingReason;
|
|
289
|
+
const waiters = this.pendingWaiters;
|
|
290
|
+
this.pendingReason = undefined;
|
|
291
|
+
this.pendingWaiters = [];
|
|
292
|
+
this.state = { ...this.state, pendingReason: undefined };
|
|
293
|
+
this.emit();
|
|
294
|
+
void this.begin(pendingReason).then((outcome) => {
|
|
295
|
+
for (const waiter of waiters) {
|
|
296
|
+
waiter.resolve(outcome);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
return active.promise;
|
|
302
|
+
}
|
|
303
|
+
mergePendingReason(current, requested) {
|
|
304
|
+
if (current === undefined || REASON_PRIORITY[requested] > REASON_PRIORITY[current]) {
|
|
305
|
+
return requested;
|
|
306
|
+
}
|
|
307
|
+
return current;
|
|
308
|
+
}
|
|
309
|
+
handleScheduledRequest(reason) {
|
|
310
|
+
if (!this.started || this.quitting) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
// Timer callbacks have no caller waiting for a Promise. Update the one
|
|
314
|
+
// pending reason in place so delayed wake/sleep periods cannot accumulate
|
|
315
|
+
// an unbounded waiter queue.
|
|
316
|
+
if (this.active !== undefined) {
|
|
317
|
+
this.pendingReason = this.mergePendingReason(this.pendingReason, reason);
|
|
318
|
+
this.state = { ...this.state, pendingReason: this.pendingReason };
|
|
319
|
+
this.emit();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
void this.request(reason);
|
|
323
|
+
}
|
|
324
|
+
async waitForCleanup(activePromise) {
|
|
325
|
+
let timeoutHandle;
|
|
326
|
+
const timeout = new Promise((resolve) => {
|
|
327
|
+
timeoutHandle = setTimeout(resolve, this.cleanupTimeoutMilliseconds);
|
|
328
|
+
if (timeoutHandle !== undefined && typeof timeoutHandle === "object" && "unref" in timeoutHandle) {
|
|
329
|
+
timeoutHandle.unref();
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
await Promise.race([activePromise.then(() => undefined), timeout]);
|
|
333
|
+
if (timeoutHandle !== undefined) {
|
|
334
|
+
clearTimeout(timeoutHandle);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
emit() {
|
|
338
|
+
const next = this.getState();
|
|
339
|
+
this.configuredOnStateChange?.(next);
|
|
340
|
+
for (const listener of this.listeners) {
|
|
341
|
+
listener(next);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
export { RefreshScheduler };
|
|
346
|
+
//# sourceMappingURL=refresh-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh-coordinator.js","sourceRoot":"","sources":["../../../../src/dashboard/state/refresh-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Clock as DomainClock, CollectionRequest, CollectionResult, UsageSource as DomainUsageSource, UsageWindow, UsageWindowKind } from "../../domain/index.js";
|
|
2
|
+
/** Reasons which can enter the refresh lifecycle. */
|
|
3
|
+
export type RefreshReason = "initial" | "timer" | "manual" | "wake";
|
|
4
|
+
/**
|
|
5
|
+
* The clock used by the dashboard. `wallNow` is for report windows and
|
|
6
|
+
* timestamps; `monotonicNow` is for scheduling and countdowns.
|
|
7
|
+
*/
|
|
8
|
+
export type Clock = DomainClock;
|
|
9
|
+
/** The request handed to the usage source for one immutable generation. */
|
|
10
|
+
export interface RefreshRequest extends CollectionRequest {
|
|
11
|
+
readonly generation: number;
|
|
12
|
+
readonly reason: RefreshReason;
|
|
13
|
+
readonly wallNow: Date;
|
|
14
|
+
readonly monotonicStartedAt: number;
|
|
15
|
+
readonly capturedAt: Date;
|
|
16
|
+
readonly windows: ReadonlyArray<UsageWindow>;
|
|
17
|
+
readonly signal: AbortSignal;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* This is deliberately structural. The collector/domain seam can return its
|
|
21
|
+
* immutable CollectionResult directly, so the dashboard never knows how the
|
|
22
|
+
* result is assembled or persisted.
|
|
23
|
+
*/
|
|
24
|
+
export type UsageSource = DomainUsageSource;
|
|
25
|
+
export type DashboardStatus = "idle" | "refreshing" | "ready" | "error" | "stopped";
|
|
26
|
+
export interface DashboardNavigation {
|
|
27
|
+
readonly panel?: string;
|
|
28
|
+
readonly index?: number;
|
|
29
|
+
readonly scrollOffset?: number;
|
|
30
|
+
readonly [key: string]: unknown;
|
|
31
|
+
}
|
|
32
|
+
export interface RefreshState<Navigation = DashboardNavigation> {
|
|
33
|
+
readonly status: DashboardStatus;
|
|
34
|
+
readonly generation: number;
|
|
35
|
+
readonly activeGeneration?: number;
|
|
36
|
+
/** The latest successful result, retained while a refresh is in flight/fails. */
|
|
37
|
+
readonly snapshot?: CollectionResult;
|
|
38
|
+
readonly lastGoodSnapshot?: CollectionResult;
|
|
39
|
+
readonly lastUpdated?: Date;
|
|
40
|
+
readonly lastError?: unknown;
|
|
41
|
+
readonly stale: boolean;
|
|
42
|
+
readonly pendingReason?: Exclude<RefreshReason, "initial">;
|
|
43
|
+
readonly period: UsageWindowKind;
|
|
44
|
+
readonly navigation: Navigation;
|
|
45
|
+
/** Monotonic deadline; absent in manual-only mode. */
|
|
46
|
+
readonly nextRefreshAt?: number;
|
|
47
|
+
/** Whole seconds remaining, derived from monotonic time. */
|
|
48
|
+
readonly countdownSeconds?: number;
|
|
49
|
+
}
|
|
50
|
+
export type RefreshOutcomeKind = "committed" | "failed" | "discarded" | "cancelled";
|
|
51
|
+
export interface RefreshOutcome {
|
|
52
|
+
readonly kind: RefreshOutcomeKind;
|
|
53
|
+
readonly generation: number;
|
|
54
|
+
readonly reason: RefreshReason;
|
|
55
|
+
readonly result?: CollectionResult;
|
|
56
|
+
readonly error?: unknown;
|
|
57
|
+
}
|
|
58
|
+
export interface RefreshSchedulerLike {
|
|
59
|
+
start(): void;
|
|
60
|
+
stop(): void;
|
|
61
|
+
reset(): void;
|
|
62
|
+
manual(): void;
|
|
63
|
+
wake(): void;
|
|
64
|
+
countdownSeconds(): number | undefined;
|
|
65
|
+
nextRefreshAt(): number | undefined;
|
|
66
|
+
readonly refreshIntervalSeconds?: number;
|
|
67
|
+
setRefreshIntervalSeconds?(seconds: number): void;
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/dashboard/state/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { CollectionError } from "./errors.js";
|
|
2
|
+
import type { TokenComponentsInput, UsageTotals } from "./tokens.js";
|
|
3
|
+
import type { UsageRecord, UsageRecordCompleteness } from "./records.js";
|
|
4
|
+
import type { UsageBucket, UsageWindow, UsageWindowKind } from "./windows.js";
|
|
5
|
+
export type CollectionSource = "stats" | "message-scan" | "codex" | "antigravity" | "unified";
|
|
6
|
+
export type ProviderKind = "opencode" | "codex" | "antigravity";
|
|
7
|
+
/**
|
|
8
|
+
* Coverage describes what a collection actually observed. `complete` means
|
|
9
|
+
* traversal finished without a known gap; it does not turn provisional usage
|
|
10
|
+
* into final usage and it must never be inferred from non-zero totals.
|
|
11
|
+
*/
|
|
12
|
+
export interface Coverage {
|
|
13
|
+
readonly complete: boolean;
|
|
14
|
+
readonly sessionsDiscovered: number;
|
|
15
|
+
readonly sessionsScanned: number;
|
|
16
|
+
readonly sessionsSkipped: number;
|
|
17
|
+
readonly pagesRead: number;
|
|
18
|
+
readonly jobsRetried: number;
|
|
19
|
+
readonly provisionalMessages: number;
|
|
20
|
+
readonly errors: ReadonlyArray<CollectionError>;
|
|
21
|
+
}
|
|
22
|
+
export type UsageTotalsByWindow = Readonly<Partial<Record<UsageWindowKind, UsageTotals>>>;
|
|
23
|
+
/** Aggregate model/provider data returned by the stats endpoint. */
|
|
24
|
+
export interface UsageBreakdown {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly provider?: string;
|
|
27
|
+
readonly totals: UsageTotals;
|
|
28
|
+
}
|
|
29
|
+
export type UsageBreakdownsByWindow = Readonly<Partial<Record<UsageWindowKind, ReadonlyArray<UsageBreakdown>>>>;
|
|
30
|
+
/** Range accepted by the OpenCode stats endpoint. */
|
|
31
|
+
export interface UsageStatsRange {
|
|
32
|
+
readonly from: Date;
|
|
33
|
+
readonly to: Date;
|
|
34
|
+
readonly timezone: string;
|
|
35
|
+
}
|
|
36
|
+
export interface UsageTrendBucket extends UsageBucket {
|
|
37
|
+
readonly totals: UsageTotals;
|
|
38
|
+
}
|
|
39
|
+
export type UsageTrendsByWindow = Readonly<Partial<Record<UsageWindowKind, ReadonlyArray<UsageTrendBucket>>>>;
|
|
40
|
+
/**
|
|
41
|
+
* One immutable collection intent. `capturedAt` and `windows` are created
|
|
42
|
+
* together so hour/day/week workers cannot each choose a different `now`.
|
|
43
|
+
*
|
|
44
|
+
* Recoverable item failures should be represented in a resolved partial result
|
|
45
|
+
* with `coverage.complete === false`. Cancellation is control flow instead:
|
|
46
|
+
* implementations must reject with a `DomainError` whose code is `cancelled`
|
|
47
|
+
* after observing `signal`; callers may retain a prior snapshot but may not
|
|
48
|
+
* publish the cancelled result as current.
|
|
49
|
+
*/
|
|
50
|
+
export interface CollectionRequest {
|
|
51
|
+
readonly capturedAt: Date;
|
|
52
|
+
readonly windows: ReadonlyArray<UsageWindow>;
|
|
53
|
+
readonly project?: string;
|
|
54
|
+
/** Defaults to true in the collector; child sessions are model work. */
|
|
55
|
+
readonly includeSubagents?: boolean;
|
|
56
|
+
/** Defaults to false so provisional usage is not silently presented as final. */
|
|
57
|
+
readonly includeProvisional?: boolean;
|
|
58
|
+
/** Refresh generation used to discard late results. */
|
|
59
|
+
readonly generation?: number;
|
|
60
|
+
readonly signal?: AbortSignal;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A collection may be partial while still carrying useful records. Consumers
|
|
64
|
+
* must inspect Coverage and source together with totals. No implementation may
|
|
65
|
+
* combine stats totals and message-scan totals for the same requested window.
|
|
66
|
+
*/
|
|
67
|
+
export interface CollectionResult {
|
|
68
|
+
readonly capturedAt: Date;
|
|
69
|
+
readonly windows: ReadonlyArray<UsageWindow>;
|
|
70
|
+
readonly source: CollectionSource;
|
|
71
|
+
readonly records: ReadonlyArray<UsageRecord>;
|
|
72
|
+
readonly totalsByWindow: UsageTotalsByWindow;
|
|
73
|
+
readonly models?: ReadonlyArray<UsageBreakdown>;
|
|
74
|
+
readonly providers?: ReadonlyArray<UsageBreakdown>;
|
|
75
|
+
readonly projects?: ReadonlyArray<UsageBreakdown>;
|
|
76
|
+
readonly modelsByWindow?: UsageBreakdownsByWindow;
|
|
77
|
+
readonly providersByWindow?: UsageBreakdownsByWindow;
|
|
78
|
+
readonly projectsByWindow?: UsageBreakdownsByWindow;
|
|
79
|
+
readonly trendsByWindow?: UsageTrendsByWindow;
|
|
80
|
+
readonly coverage: Coverage;
|
|
81
|
+
readonly serverFingerprint?: string;
|
|
82
|
+
readonly serverVersion?: string;
|
|
83
|
+
}
|
|
84
|
+
export declare const SNAPSHOT_SCHEMA_VERSION: 1;
|
|
85
|
+
/**
|
|
86
|
+
* Persistable read model. A store commit must publish this as one immutable
|
|
87
|
+
* snapshot (normally via temp-file flush and same-directory rename). A failed
|
|
88
|
+
* commit leaves the previous snapshot readable. Store cancellation before the
|
|
89
|
+
* atomic publish must reject and must not report a successful commit.
|
|
90
|
+
*/
|
|
91
|
+
export interface StoredSnapshot {
|
|
92
|
+
readonly schemaVersion: typeof SNAPSHOT_SCHEMA_VERSION;
|
|
93
|
+
readonly generation: number;
|
|
94
|
+
readonly capturedAt: Date;
|
|
95
|
+
readonly requestedWindows: ReadonlyArray<UsageWindow>;
|
|
96
|
+
readonly source: CollectionSource;
|
|
97
|
+
readonly records: ReadonlyArray<UsageRecord>;
|
|
98
|
+
readonly totalsByWindow: UsageTotalsByWindow;
|
|
99
|
+
readonly models?: ReadonlyArray<UsageBreakdown>;
|
|
100
|
+
readonly providers?: ReadonlyArray<UsageBreakdown>;
|
|
101
|
+
readonly projects?: ReadonlyArray<UsageBreakdown>;
|
|
102
|
+
readonly modelsByWindow?: UsageBreakdownsByWindow;
|
|
103
|
+
readonly providersByWindow?: UsageBreakdownsByWindow;
|
|
104
|
+
readonly projectsByWindow?: UsageBreakdownsByWindow;
|
|
105
|
+
readonly trendsByWindow?: UsageTrendsByWindow;
|
|
106
|
+
readonly coverage: Coverage;
|
|
107
|
+
readonly serverFingerprint?: string;
|
|
108
|
+
readonly serverVersion?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface TransportRequestOptions {
|
|
111
|
+
/** A transport must stop issuing work and reject with cancellation promptly. */
|
|
112
|
+
readonly signal?: AbortSignal;
|
|
113
|
+
}
|
|
114
|
+
export interface SessionListRequest extends TransportRequestOptions {
|
|
115
|
+
readonly cursor?: string;
|
|
116
|
+
readonly limit?: number;
|
|
117
|
+
}
|
|
118
|
+
export interface MessageListRequest extends TransportRequestOptions {
|
|
119
|
+
readonly sessionID: string;
|
|
120
|
+
readonly cursor?: string;
|
|
121
|
+
readonly limit?: number;
|
|
122
|
+
}
|
|
123
|
+
export interface OpenCodeSession {
|
|
124
|
+
readonly sessionID: string;
|
|
125
|
+
readonly parentSessionID?: string;
|
|
126
|
+
readonly projectID?: string;
|
|
127
|
+
readonly directory?: string;
|
|
128
|
+
readonly workspaceID?: string;
|
|
129
|
+
}
|
|
130
|
+
export interface OpenCodeAssistantMessage {
|
|
131
|
+
readonly sessionID: string;
|
|
132
|
+
readonly messageID: string;
|
|
133
|
+
readonly createdAt: Date;
|
|
134
|
+
readonly model: string;
|
|
135
|
+
/** Undefined means the API omitted the token object, not zero usage. */
|
|
136
|
+
readonly tokens?: TokenComponentsInput;
|
|
137
|
+
readonly completeness: UsageRecordCompleteness;
|
|
138
|
+
}
|
|
139
|
+
export interface SessionPage {
|
|
140
|
+
readonly sessions: ReadonlyArray<OpenCodeSession>;
|
|
141
|
+
/** `null` means exhausted; a repeated cursor is a protocol error. */
|
|
142
|
+
readonly nextCursor: string | null;
|
|
143
|
+
}
|
|
144
|
+
export interface MessagePage {
|
|
145
|
+
readonly messages: ReadonlyArray<OpenCodeAssistantMessage>;
|
|
146
|
+
/** `null` means exhausted; a repeated cursor is a protocol error. */
|
|
147
|
+
readonly nextCursor: string | null;
|
|
148
|
+
}
|
|
149
|
+
export interface OpenCodeHealth {
|
|
150
|
+
readonly version: string;
|
|
151
|
+
readonly fingerprint: string;
|
|
152
|
+
}
|
|
153
|
+
export interface OpenCodeRange {
|
|
154
|
+
readonly from: Date;
|
|
155
|
+
readonly to: Date;
|
|
156
|
+
readonly timezone: string;
|
|
157
|
+
}
|
|
158
|
+
export interface OpenCodeProject {
|
|
159
|
+
readonly id: string;
|
|
160
|
+
readonly canonical: string;
|
|
161
|
+
readonly name?: string;
|
|
162
|
+
}
|
|
163
|
+
export interface OpenCodeSessionStats {
|
|
164
|
+
readonly requestedWindow: UsageStatsRange;
|
|
165
|
+
/** The server-reported range must be compared with requestedWindow by the collector. */
|
|
166
|
+
readonly reportedRange: OpenCodeRange;
|
|
167
|
+
readonly totals: UsageTotals;
|
|
168
|
+
readonly models?: ReadonlyArray<UsageBreakdown>;
|
|
169
|
+
readonly providers?: ReadonlyArray<UsageBreakdown>;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Adapter seam for the read-only OpenCode 2 V2 server API.
|
|
173
|
+
*
|
|
174
|
+
* Every operation is an idempotent read. Implementations may retry reads but
|
|
175
|
+
* must not duplicate accounting as a retry side effect. They must honor an
|
|
176
|
+
* AbortSignal promptly, reject with cancellation rather than return a falsely
|
|
177
|
+
* complete page, and avoid exposing prompts/tool content in these DTOs.
|
|
178
|
+
* `getSessionStats` is usable only after its reported range is validated;
|
|
179
|
+
* callers must fall back to paginated messages when the server ignores bounds.
|
|
180
|
+
*/
|
|
181
|
+
export interface OpenCodeTransport {
|
|
182
|
+
getHealth(options?: TransportRequestOptions): Promise<OpenCodeHealth>;
|
|
183
|
+
getSessionStats(window: UsageStatsRange, options?: TransportRequestOptions & {
|
|
184
|
+
readonly project?: string;
|
|
185
|
+
}): Promise<OpenCodeSessionStats>;
|
|
186
|
+
listSessions(request?: SessionListRequest): Promise<SessionPage>;
|
|
187
|
+
listMessages(request: MessageListRequest): Promise<MessagePage>;
|
|
188
|
+
listProjects?(options?: TransportRequestOptions): Promise<ReadonlyArray<OpenCodeProject>>;
|
|
189
|
+
}
|
|
190
|
+
/** A source such as stats or a paginated message collector. */
|
|
191
|
+
export interface UsageSource {
|
|
192
|
+
/**
|
|
193
|
+
* Resolve with a partial result for bounded, recoverable scan gaps. Reject
|
|
194
|
+
* cancellation so the refresh coordinator can discard this generation;
|
|
195
|
+
* never label a partial or cancelled result as complete.
|
|
196
|
+
*/
|
|
197
|
+
collect(request: CollectionRequest): Promise<CollectionResult>;
|
|
198
|
+
}
|
|
199
|
+
export interface SnapshotStoreReadOptions extends TransportRequestOptions {
|
|
200
|
+
}
|
|
201
|
+
export interface SnapshotStoreCommitOptions extends TransportRequestOptions {
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Process-safe snapshot persistence seam. Implementations serialize commits;
|
|
205
|
+
* a cache-busy condition should be reported rather than waiting forever, so a
|
|
206
|
+
* caller can continue with in-memory data and visible stale/partial status.
|
|
207
|
+
*/
|
|
208
|
+
export interface SnapshotStore {
|
|
209
|
+
read(options?: SnapshotStoreReadOptions): Promise<StoredSnapshot | null>;
|
|
210
|
+
commit(snapshot: StoredSnapshot, options?: SnapshotStoreCommitOptions): Promise<void>;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Wall time drives calendar windows; monotonic milliseconds drive scheduling
|
|
214
|
+
* and elapsed-time budgets. Tests provide a fake implementation for both.
|
|
215
|
+
*/
|
|
216
|
+
export interface Clock {
|
|
217
|
+
wallNow(): Date;
|
|
218
|
+
monotonicNow(): number;
|
|
219
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../src/domain/contracts.ts"],"names":[],"mappings":"AAqGA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAU,CAAC"}
|