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,118 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { Service, headers as serviceHeaders, } from "@opencode-ai/client/service";
|
|
3
|
+
import { OpenCode } from "@opencode-ai/client";
|
|
4
|
+
import { DomainError, cancellationError } from "../domain/index.js";
|
|
5
|
+
export const defaultService = {
|
|
6
|
+
discover: Service.discover,
|
|
7
|
+
ensure: Service.ensure,
|
|
8
|
+
headers: serviceHeaders,
|
|
9
|
+
};
|
|
10
|
+
/** Create the official promise client with the service's auth headers. */
|
|
11
|
+
export function createOpenCodeClient(endpoint, service = defaultService, options = {}) {
|
|
12
|
+
return OpenCode.make({
|
|
13
|
+
baseUrl: endpoint.url,
|
|
14
|
+
headers: service.headers(endpoint),
|
|
15
|
+
fetch: options.fetch,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export const defaultClientFactory = (endpoint, options) => createOpenCodeClient(endpoint, defaultService, options);
|
|
19
|
+
function throwIfAborted(signal) {
|
|
20
|
+
if (signal?.aborted) {
|
|
21
|
+
throw cancellationError();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function assertEndpoint(endpoint) {
|
|
25
|
+
if (typeof endpoint.url !== "string" || endpoint.url.trim().length === 0) {
|
|
26
|
+
throw new DomainError("invalid-data", "OpenCode service returned an empty URL");
|
|
27
|
+
}
|
|
28
|
+
let url;
|
|
29
|
+
try {
|
|
30
|
+
url = new URL(endpoint.url);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new DomainError("invalid-data", "OpenCode service returned an invalid URL", {
|
|
34
|
+
cause: error,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
38
|
+
throw new DomainError("invalid-data", `OpenCode service URL must use http or https, got ${url.protocol}`);
|
|
39
|
+
}
|
|
40
|
+
return { ...endpoint, url: url.toString() };
|
|
41
|
+
}
|
|
42
|
+
function isRecord(value) {
|
|
43
|
+
return typeof value === "object" && value !== null;
|
|
44
|
+
}
|
|
45
|
+
function readHealth(value, endpoint) {
|
|
46
|
+
if (!isRecord(value) || value.healthy !== true || typeof value.version !== "string") {
|
|
47
|
+
throw new DomainError("invalid-data", "OpenCode health response is missing healthy=true and a version");
|
|
48
|
+
}
|
|
49
|
+
const pid = value.pid;
|
|
50
|
+
if (pid !== undefined && pid !== null && (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid < 0)) {
|
|
51
|
+
throw new DomainError("invalid-data", "OpenCode health response has an invalid pid");
|
|
52
|
+
}
|
|
53
|
+
// Never hash or report the basic-auth password. The URL is the advertised
|
|
54
|
+
// endpoint, not the credential-bearing request header.
|
|
55
|
+
const fingerprintInput = `${endpoint.url}\u0000${value.version}\u0000${pid ?? ""}`;
|
|
56
|
+
const fingerprint = createHash("sha256").update(fingerprintInput).digest("hex").slice(0, 24);
|
|
57
|
+
return { version: value.version, fingerprint };
|
|
58
|
+
}
|
|
59
|
+
export function parseOpenCodeHealth(value, endpoint) {
|
|
60
|
+
return readHealth(value, endpoint);
|
|
61
|
+
}
|
|
62
|
+
function mergeDiscoveryOptions(options) {
|
|
63
|
+
return {
|
|
64
|
+
...options.discovery,
|
|
65
|
+
...(options.version === undefined ? {} : { version: options.version }),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function mergeEnsureOptions(options) {
|
|
69
|
+
return {
|
|
70
|
+
// The beta client's own default still says `opencode`; OC2Token targets
|
|
71
|
+
// the V2 executable explicitly unless the caller supplies a command.
|
|
72
|
+
command: ["opencode2", "serve", "--service"],
|
|
73
|
+
...options.ensureOptions,
|
|
74
|
+
...(options.version === undefined ? {} : { version: options.version }),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Discover a running service, optionally ensuring the V2 service exists. */
|
|
78
|
+
export async function connectOpenCode(options = {}) {
|
|
79
|
+
const service = options.service ?? defaultService;
|
|
80
|
+
const signal = options.signal;
|
|
81
|
+
throwIfAborted(signal);
|
|
82
|
+
let endpoint = await service.discover(mergeDiscoveryOptions(options));
|
|
83
|
+
throwIfAborted(signal);
|
|
84
|
+
if (endpoint === undefined) {
|
|
85
|
+
if (options.ensure === false) {
|
|
86
|
+
throw new DomainError("transport", "No healthy OpenCode 2 service was discovered");
|
|
87
|
+
}
|
|
88
|
+
endpoint = await service.ensure(mergeEnsureOptions(options));
|
|
89
|
+
throwIfAborted(signal);
|
|
90
|
+
}
|
|
91
|
+
const normalizedEndpoint = assertEndpoint(endpoint);
|
|
92
|
+
const client = options.client ?? (options.clientFactory ?? ((target, factoryOptions) => createOpenCodeClient(target, service, factoryOptions)))(normalizedEndpoint, {
|
|
93
|
+
fetch: options.fetch,
|
|
94
|
+
});
|
|
95
|
+
if (client.health === undefined || typeof client.health.get !== "function") {
|
|
96
|
+
throw new DomainError("invalid-data", "OpenCode client does not expose health.get");
|
|
97
|
+
}
|
|
98
|
+
const health = parseOpenCodeHealth(await client.health.get({ signal }), normalizedEndpoint);
|
|
99
|
+
throwIfAborted(signal);
|
|
100
|
+
return { endpoint: normalizedEndpoint, client, health };
|
|
101
|
+
}
|
|
102
|
+
/** A class facade is convenient for callers that need to reconnect later. */
|
|
103
|
+
export class OpenCodeConnectionManager {
|
|
104
|
+
options;
|
|
105
|
+
constructor(options = {}) {
|
|
106
|
+
this.options = { ...options };
|
|
107
|
+
}
|
|
108
|
+
discover() {
|
|
109
|
+
return (this.options.service ?? defaultService).discover(mergeDiscoveryOptions(this.options));
|
|
110
|
+
}
|
|
111
|
+
ensure() {
|
|
112
|
+
return (this.options.service ?? defaultService).ensure(mergeEnsureOptions(this.options));
|
|
113
|
+
}
|
|
114
|
+
connect() {
|
|
115
|
+
return connectOpenCode(this.options);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/opencode/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type OpenCodeTransport, type UsageWindow } from "../domain/index.js";
|
|
2
|
+
import { type ConnectionOptions, type OpenCodeConnection } from "./client.js";
|
|
3
|
+
export type DoctorCheckName = "service" | "health" | "stats-range" | "opencode" | "codex" | "antigravity";
|
|
4
|
+
export interface DoctorCheck {
|
|
5
|
+
readonly name: DoctorCheckName;
|
|
6
|
+
readonly ok: boolean;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
}
|
|
9
|
+
export interface DoctorReport {
|
|
10
|
+
readonly ok: boolean;
|
|
11
|
+
readonly checks: ReadonlyArray<DoctorCheck>;
|
|
12
|
+
readonly endpoint?: string;
|
|
13
|
+
readonly version?: string;
|
|
14
|
+
readonly fingerprint?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DoctorOptions extends ConnectionOptions {
|
|
17
|
+
readonly connection?: OpenCodeConnection;
|
|
18
|
+
readonly transport?: OpenCodeTransport;
|
|
19
|
+
/** If supplied, doctor also verifies the filtered stats range. */
|
|
20
|
+
readonly window?: UsageWindow;
|
|
21
|
+
readonly project?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Run non-mutating local diagnostics. By default it only discovers a running
|
|
25
|
+
* service; pass ensure:true when a caller explicitly wants service startup.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runOpenCodeDoctor(options?: DoctorOptions): Promise<DoctorReport>;
|
|
28
|
+
export declare const doctor: typeof runOpenCodeDoctor;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DomainError, } from "../domain/index.js";
|
|
2
|
+
import { connectOpenCode, } from "./client.js";
|
|
3
|
+
import { isStatsRangeMismatch, OpenCode2Transport } from "./transport.js";
|
|
4
|
+
function publicError(error) {
|
|
5
|
+
if (error instanceof DomainError)
|
|
6
|
+
return error.message;
|
|
7
|
+
if (error instanceof Error)
|
|
8
|
+
return error.message;
|
|
9
|
+
return String(error);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Run non-mutating local diagnostics. By default it only discovers a running
|
|
13
|
+
* service; pass ensure:true when a caller explicitly wants service startup.
|
|
14
|
+
*/
|
|
15
|
+
export async function runOpenCodeDoctor(options = {}) {
|
|
16
|
+
const checks = [];
|
|
17
|
+
let connection = options.connection;
|
|
18
|
+
let transport = options.transport;
|
|
19
|
+
if (connection === undefined && transport === undefined) {
|
|
20
|
+
try {
|
|
21
|
+
connection = await connectOpenCode({ ...options, ensure: options.ensure ?? false });
|
|
22
|
+
checks.push({ name: "service", ok: true, message: "OpenCode 2 service discovered" });
|
|
23
|
+
transport = new OpenCode2Transport({ client: connection.client });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
checks.push({ name: "service", ok: false, message: publicError(error) });
|
|
27
|
+
return { ok: false, checks };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
checks.push({ name: "service", ok: true, message: "Injected OpenCode transport is available" });
|
|
32
|
+
}
|
|
33
|
+
if (transport === undefined && connection !== undefined) {
|
|
34
|
+
transport = new OpenCode2Transport({ client: connection.client });
|
|
35
|
+
}
|
|
36
|
+
if (connection !== undefined) {
|
|
37
|
+
checks.push({
|
|
38
|
+
name: "health",
|
|
39
|
+
ok: true,
|
|
40
|
+
message: `healthy V2 service ${connection.health.version}`,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else if (transport !== undefined) {
|
|
44
|
+
try {
|
|
45
|
+
const health = await transport.getHealth({ signal: options.signal });
|
|
46
|
+
checks.push({ name: "health", ok: true, message: `healthy V2 service ${health.version}` });
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
checks.push({ name: "health", ok: false, message: publicError(error) });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (options.window !== undefined && transport !== undefined) {
|
|
53
|
+
try {
|
|
54
|
+
const statsOptions = {
|
|
55
|
+
project: options.project,
|
|
56
|
+
signal: options.signal,
|
|
57
|
+
};
|
|
58
|
+
await transport.getSessionStats(options.window, statsOptions);
|
|
59
|
+
checks.push({ name: "stats-range", ok: true, message: "filtered stats range is honored" });
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
checks.push({
|
|
63
|
+
name: "stats-range",
|
|
64
|
+
ok: false,
|
|
65
|
+
message: isStatsRangeMismatch(error)
|
|
66
|
+
? "filtered stats range is not honored; use paginated message fallback"
|
|
67
|
+
: publicError(error),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
ok: checks.every((check) => check.ok),
|
|
73
|
+
checks,
|
|
74
|
+
...(connection === undefined ? {} : {
|
|
75
|
+
endpoint: connection.endpoint.url,
|
|
76
|
+
version: connection.health.version,
|
|
77
|
+
fingerprint: connection.health.fingerprint,
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export const doctor = runOpenCodeDoctor;
|
|
82
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/opencode/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/opencode/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type CollectionRequest, type CollectionResult, type OpenCodeTransport, type UsageSource } from "../domain/index.js";
|
|
2
|
+
/** UsageSource implementation for a range-validated /api/session/stats path. */
|
|
3
|
+
export declare class OpenCodeStatsSource implements UsageSource {
|
|
4
|
+
readonly transport: OpenCodeTransport;
|
|
5
|
+
constructor(transport: OpenCodeTransport);
|
|
6
|
+
collect(request: CollectionRequest): Promise<CollectionResult>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createOpenCodeStatsSource(transport: OpenCodeTransport): OpenCodeStatsSource;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { DomainError, isCancellationError, createUsageTrendBuckets, } from "../domain/index.js";
|
|
2
|
+
function throwIfAborted(signal) {
|
|
3
|
+
if (signal?.aborted)
|
|
4
|
+
throw new DomainError("cancelled", "The operation was cancelled");
|
|
5
|
+
}
|
|
6
|
+
const completeStatsCoverage = {
|
|
7
|
+
complete: true,
|
|
8
|
+
sessionsDiscovered: 0,
|
|
9
|
+
sessionsScanned: 0,
|
|
10
|
+
sessionsSkipped: 0,
|
|
11
|
+
pagesRead: 0,
|
|
12
|
+
jobsRetried: 0,
|
|
13
|
+
provisionalMessages: 0,
|
|
14
|
+
errors: [],
|
|
15
|
+
};
|
|
16
|
+
const TREND_WORKERS = 4;
|
|
17
|
+
const PROJECT_WORKERS = 4;
|
|
18
|
+
async function collectProjectBreakdowns(transport, window, projects, signal) {
|
|
19
|
+
if (projects.length === 0)
|
|
20
|
+
return [];
|
|
21
|
+
const results = new Array(projects.length);
|
|
22
|
+
let nextIndex = 0;
|
|
23
|
+
async function worker() {
|
|
24
|
+
for (;;) {
|
|
25
|
+
throwIfAborted(signal);
|
|
26
|
+
const index = nextIndex;
|
|
27
|
+
nextIndex += 1;
|
|
28
|
+
if (index >= projects.length)
|
|
29
|
+
return;
|
|
30
|
+
const project = projects[index];
|
|
31
|
+
try {
|
|
32
|
+
const result = await transport.getSessionStats(window, { project: project.id, signal });
|
|
33
|
+
if (result.totals.recorded_total > 0) {
|
|
34
|
+
results[index] = { name: project.canonical, totals: result.totals };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (isCancellationError(error) || (error instanceof DomainError && error.code === "cancelled")) {
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
// Per-project failures are non-fatal; a single project's stats
|
|
42
|
+
// must not abort the whole refresh (range mismatch, 404, etc.)
|
|
43
|
+
results[index] = undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const workers = Math.min(PROJECT_WORKERS, projects.length);
|
|
48
|
+
await Promise.all(Array.from({ length: workers }, () => worker()));
|
|
49
|
+
throwIfAborted(signal);
|
|
50
|
+
return results
|
|
51
|
+
.filter((value) => value !== undefined)
|
|
52
|
+
.sort((a, b) => b.totals.recorded_total - a.totals.recorded_total || a.name.localeCompare(b.name));
|
|
53
|
+
}
|
|
54
|
+
async function collectTrendBuckets(transport, window, options) {
|
|
55
|
+
const buckets = createUsageTrendBuckets(window);
|
|
56
|
+
const results = new Array(buckets.length);
|
|
57
|
+
let nextIndex = 0;
|
|
58
|
+
async function worker() {
|
|
59
|
+
for (;;) {
|
|
60
|
+
throwIfAborted(options.signal);
|
|
61
|
+
const index = nextIndex;
|
|
62
|
+
nextIndex += 1;
|
|
63
|
+
if (index >= buckets.length)
|
|
64
|
+
return;
|
|
65
|
+
const bucket = buckets[index];
|
|
66
|
+
// Retain the parent window metadata for fakes and diagnostics while
|
|
67
|
+
// sending the bucket's exact range to the transport.
|
|
68
|
+
const query = {
|
|
69
|
+
...window,
|
|
70
|
+
from: new Date(bucket.from.getTime()),
|
|
71
|
+
to: new Date(bucket.to.getTime()),
|
|
72
|
+
label: bucket.label,
|
|
73
|
+
};
|
|
74
|
+
const result = await transport.getSessionStats(query, options);
|
|
75
|
+
results[index] = {
|
|
76
|
+
label: bucket.label,
|
|
77
|
+
from: new Date(bucket.from.getTime()),
|
|
78
|
+
to: new Date(bucket.to.getTime()),
|
|
79
|
+
totals: result.totals,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const workerCount = Math.min(TREND_WORKERS, buckets.length);
|
|
84
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
85
|
+
throwIfAborted(options.signal);
|
|
86
|
+
return results.filter((value) => value !== undefined);
|
|
87
|
+
}
|
|
88
|
+
/** UsageSource implementation for a range-validated /api/session/stats path. */
|
|
89
|
+
export class OpenCodeStatsSource {
|
|
90
|
+
transport;
|
|
91
|
+
constructor(transport) {
|
|
92
|
+
this.transport = transport;
|
|
93
|
+
}
|
|
94
|
+
async collect(request) {
|
|
95
|
+
throwIfAborted(request.signal);
|
|
96
|
+
const health = await this.transport.getHealth({ signal: request.signal });
|
|
97
|
+
const totalsByWindow = {};
|
|
98
|
+
const modelsByWindow = {};
|
|
99
|
+
const providersByWindow = {};
|
|
100
|
+
const projectsByWindow = {};
|
|
101
|
+
const trendsByWindow = {};
|
|
102
|
+
let models = undefined;
|
|
103
|
+
let providers = undefined;
|
|
104
|
+
let projects = undefined;
|
|
105
|
+
// Fetch project list once when not filtering to a single project.
|
|
106
|
+
// Failures are non-fatal: the stats total remains usable without per-project split.
|
|
107
|
+
let allProjects = [];
|
|
108
|
+
if (request.project === undefined && typeof this.transport.listProjects === "function") {
|
|
109
|
+
try {
|
|
110
|
+
const fetched = await this.transport.listProjects({ signal: request.signal });
|
|
111
|
+
// Filter obvious non-project entries (global root) and keep only git-backed projects with recent activity?
|
|
112
|
+
// We keep all and filter by recorded_total>0 later; but skip the global "/" which typically returns 0.
|
|
113
|
+
allProjects = fetched.filter((p) => p.canonical !== "/" && p.id !== "global");
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (isCancellationError(error) || (error instanceof DomainError && error.code === "cancelled"))
|
|
117
|
+
throw error;
|
|
118
|
+
allProjects = [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Keep each response associated with its immutable requested window. A
|
|
122
|
+
// stats total is never combined with a message-scan total by this source.
|
|
123
|
+
for (const window of request.windows) {
|
|
124
|
+
throwIfAborted(request.signal);
|
|
125
|
+
const options = {
|
|
126
|
+
project: request.project,
|
|
127
|
+
signal: request.signal,
|
|
128
|
+
};
|
|
129
|
+
const result = await this.transport.getSessionStats(window, options);
|
|
130
|
+
totalsByWindow[window.kind] = result.totals;
|
|
131
|
+
// Keep the widest requested window's breakdown for backwards-compatible
|
|
132
|
+
// global fields, while also retaining each response for the selected
|
|
133
|
+
// dashboard period.
|
|
134
|
+
if (result.models !== undefined) {
|
|
135
|
+
models = result.models;
|
|
136
|
+
modelsByWindow[window.kind] = result.models;
|
|
137
|
+
}
|
|
138
|
+
if (result.providers !== undefined) {
|
|
139
|
+
providers = result.providers;
|
|
140
|
+
providersByWindow[window.kind] = result.providers;
|
|
141
|
+
}
|
|
142
|
+
trendsByWindow[window.kind] = await collectTrendBuckets(this.transport, window, options);
|
|
143
|
+
if (allProjects.length > 0) {
|
|
144
|
+
const breakdowns = await collectProjectBreakdowns(this.transport, window, allProjects, request.signal);
|
|
145
|
+
if (breakdowns.length > 0) {
|
|
146
|
+
projects = breakdowns;
|
|
147
|
+
projectsByWindow[window.kind] = breakdowns;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
throwIfAborted(request.signal);
|
|
152
|
+
return {
|
|
153
|
+
capturedAt: new Date(request.capturedAt.getTime()),
|
|
154
|
+
windows: request.windows,
|
|
155
|
+
source: "stats",
|
|
156
|
+
records: [],
|
|
157
|
+
totalsByWindow,
|
|
158
|
+
...(models === undefined ? {} : { models }),
|
|
159
|
+
...(providers === undefined ? {} : { providers }),
|
|
160
|
+
...(projects === undefined ? {} : { projects }),
|
|
161
|
+
...(Object.keys(modelsByWindow).length === 0 ? {} : { modelsByWindow: modelsByWindow }),
|
|
162
|
+
...(Object.keys(providersByWindow).length === 0 ? {} : { providersByWindow: providersByWindow }),
|
|
163
|
+
...(Object.keys(projectsByWindow).length === 0 ? {} : { projectsByWindow: projectsByWindow }),
|
|
164
|
+
...(Object.keys(trendsByWindow).length === 0 ? {} : { trendsByWindow: trendsByWindow }),
|
|
165
|
+
coverage: completeStatsCoverage,
|
|
166
|
+
serverFingerprint: health.fingerprint,
|
|
167
|
+
serverVersion: health.version,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export function createOpenCodeStatsSource(transport) {
|
|
172
|
+
return new OpenCodeStatsSource(transport);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/opencode/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DomainError, type MessageListRequest, type MessagePage, type OpenCodeAssistantMessage, type OpenCodeHealth, type OpenCodeProject, type OpenCodeRange, type OpenCodeSession, type OpenCodeSessionStats, type OpenCodeTransport, type SessionListRequest, type SessionPage, type TransportRequestOptions, type UsageStatsRange } from "../domain/index.js";
|
|
2
|
+
import type { OpenCodeClientLike } from "./client.js";
|
|
3
|
+
export interface RetryPolicy {
|
|
4
|
+
/** Maximum number of attempts, including the first request. */
|
|
5
|
+
readonly maxAttempts?: number;
|
|
6
|
+
readonly baseDelayMs?: number;
|
|
7
|
+
readonly maxDelayMs?: number;
|
|
8
|
+
/** Fractional jitter around the exponential delay. Set to zero in tests. */
|
|
9
|
+
readonly jitter?: number;
|
|
10
|
+
readonly random?: () => number;
|
|
11
|
+
readonly sleep?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
12
|
+
/** Per-attempt request deadline. Set to zero to disable the deadline. */
|
|
13
|
+
readonly requestTimeoutMs?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface StatsRequestOptions extends TransportRequestOptions {
|
|
16
|
+
readonly project?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OpenCodeTransportOptions extends RetryPolicy {
|
|
19
|
+
readonly client: OpenCodeClientLike;
|
|
20
|
+
readonly pageSize?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function retryingRead<T>(operation: (signal: AbortSignal) => Promise<T>, options?: RetryPolicy & TransportRequestOptions): Promise<T>;
|
|
23
|
+
declare function parseStats(value: unknown, window: UsageStatsRange): OpenCodeSessionStats;
|
|
24
|
+
export declare const parseOpenCodeSessionStats: typeof parseStats;
|
|
25
|
+
export declare class StatsRangeMismatchError extends DomainError {
|
|
26
|
+
readonly requestedWindow: UsageStatsRange;
|
|
27
|
+
readonly reportedRange: OpenCodeRange;
|
|
28
|
+
readonly broader: boolean;
|
|
29
|
+
constructor(requestedWindow: UsageStatsRange, reportedRange: OpenCodeRange, broader: boolean);
|
|
30
|
+
}
|
|
31
|
+
export declare function isStatsRangeMismatch(error: unknown): error is StatsRangeMismatchError;
|
|
32
|
+
/**
|
|
33
|
+
* Read-only V2 transport. Response parsing happens after the retry boundary so
|
|
34
|
+
* malformed data is never retried and never mistaken for a transient outage.
|
|
35
|
+
*/
|
|
36
|
+
export declare class OpenCode2Transport implements OpenCodeTransport {
|
|
37
|
+
readonly client: OpenCodeClientLike;
|
|
38
|
+
readonly pageSize: number;
|
|
39
|
+
readonly retryPolicy: RetryPolicy;
|
|
40
|
+
constructor(options: OpenCodeTransportOptions);
|
|
41
|
+
getHealth(options?: TransportRequestOptions): Promise<OpenCodeHealth>;
|
|
42
|
+
getSessionStats(window: UsageStatsRange, options?: StatsRequestOptions): Promise<OpenCodeSessionStats>;
|
|
43
|
+
listSessions(request?: SessionListRequest): Promise<SessionPage>;
|
|
44
|
+
listMessages(request: MessageListRequest): Promise<MessagePage>;
|
|
45
|
+
listAllSessions(options?: SessionListRequest & {
|
|
46
|
+
readonly maxPages?: number;
|
|
47
|
+
}): Promise<ReadonlyArray<OpenCodeSession>>;
|
|
48
|
+
listAllMessages(options: MessageListRequest & {
|
|
49
|
+
readonly maxPages?: number;
|
|
50
|
+
}): Promise<ReadonlyArray<OpenCodeAssistantMessage>>;
|
|
51
|
+
listProjects(options?: TransportRequestOptions): Promise<ReadonlyArray<OpenCodeProject>>;
|
|
52
|
+
}
|
|
53
|
+
export declare function createOpenCodeTransport(options: OpenCodeTransportOptions): OpenCode2Transport;
|
|
54
|
+
export {};
|