@cookielab.io/oopst 0.1.0 → 0.3.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/dist/index.js +556 -89
- package/dist/index.js.map +1 -1
- package/package.json +47 -46
package/dist/index.js
CHANGED
|
@@ -21,9 +21,9 @@ var __commonJS = (cb, mod) => function __require2() {
|
|
|
21
21
|
};
|
|
22
22
|
var __copyProps = (to, from, except, desc) => {
|
|
23
23
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
24
|
-
for (let
|
|
25
|
-
if (!__hasOwnProp.call(to,
|
|
26
|
-
__defProp(to,
|
|
24
|
+
for (let key6 of __getOwnPropNames(from))
|
|
25
|
+
if (!__hasOwnProp.call(to, key6) && key6 !== except)
|
|
26
|
+
__defProp(to, key6, { get: () => from[key6], enumerable: !(desc = __getOwnPropDesc(from, key6)) || desc.enumerable });
|
|
27
27
|
}
|
|
28
28
|
return to;
|
|
29
29
|
};
|
|
@@ -1061,9 +1061,9 @@ var require_option = __commonJS({
|
|
|
1061
1061
|
this.positiveOptions.set(option.attributeName(), option);
|
|
1062
1062
|
}
|
|
1063
1063
|
});
|
|
1064
|
-
this.negativeOptions.forEach((value,
|
|
1065
|
-
if (this.positiveOptions.has(
|
|
1066
|
-
this.dualOptions.add(
|
|
1064
|
+
this.negativeOptions.forEach((value, key6) => {
|
|
1065
|
+
if (this.positiveOptions.has(key6)) {
|
|
1066
|
+
this.dualOptions.add(key6);
|
|
1067
1067
|
}
|
|
1068
1068
|
});
|
|
1069
1069
|
}
|
|
@@ -1998,11 +1998,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1998
1998
|
* @param {string} key
|
|
1999
1999
|
* @return {object} value
|
|
2000
2000
|
*/
|
|
2001
|
-
getOptionValue(
|
|
2001
|
+
getOptionValue(key6) {
|
|
2002
2002
|
if (this._storeOptionsAsProperties) {
|
|
2003
|
-
return this[
|
|
2003
|
+
return this[key6];
|
|
2004
2004
|
}
|
|
2005
|
-
return this._optionValues[
|
|
2005
|
+
return this._optionValues[key6];
|
|
2006
2006
|
}
|
|
2007
2007
|
/**
|
|
2008
2008
|
* Store option value.
|
|
@@ -2011,8 +2011,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2011
2011
|
* @param {object} value
|
|
2012
2012
|
* @return {Command} `this` command for chaining
|
|
2013
2013
|
*/
|
|
2014
|
-
setOptionValue(
|
|
2015
|
-
return this.setOptionValueWithSource(
|
|
2014
|
+
setOptionValue(key6, value) {
|
|
2015
|
+
return this.setOptionValueWithSource(key6, value, void 0);
|
|
2016
2016
|
}
|
|
2017
2017
|
/**
|
|
2018
2018
|
* Store option value and where the value came from.
|
|
@@ -2022,13 +2022,13 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2022
2022
|
* @param {string} source - expected values are default/config/env/cli/implied
|
|
2023
2023
|
* @return {Command} `this` command for chaining
|
|
2024
2024
|
*/
|
|
2025
|
-
setOptionValueWithSource(
|
|
2025
|
+
setOptionValueWithSource(key6, value, source) {
|
|
2026
2026
|
if (this._storeOptionsAsProperties) {
|
|
2027
|
-
this[
|
|
2027
|
+
this[key6] = value;
|
|
2028
2028
|
} else {
|
|
2029
|
-
this._optionValues[
|
|
2029
|
+
this._optionValues[key6] = value;
|
|
2030
2030
|
}
|
|
2031
|
-
this._optionValueSources[
|
|
2031
|
+
this._optionValueSources[key6] = source;
|
|
2032
2032
|
return this;
|
|
2033
2033
|
}
|
|
2034
2034
|
/**
|
|
@@ -2038,8 +2038,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2038
2038
|
* @param {string} key
|
|
2039
2039
|
* @return {string}
|
|
2040
2040
|
*/
|
|
2041
|
-
getOptionValueSource(
|
|
2042
|
-
return this._optionValueSources[
|
|
2041
|
+
getOptionValueSource(key6) {
|
|
2042
|
+
return this._optionValueSources[key6];
|
|
2043
2043
|
}
|
|
2044
2044
|
/**
|
|
2045
2045
|
* Get source of option value. See also .optsWithGlobals().
|
|
@@ -2048,11 +2048,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2048
2048
|
* @param {string} key
|
|
2049
2049
|
* @return {string}
|
|
2050
2050
|
*/
|
|
2051
|
-
getOptionValueSourceWithGlobals(
|
|
2051
|
+
getOptionValueSourceWithGlobals(key6) {
|
|
2052
2052
|
let source;
|
|
2053
2053
|
this._getCommandAndAncestors().forEach((cmd) => {
|
|
2054
|
-
if (cmd.getOptionValueSource(
|
|
2055
|
-
source = cmd.getOptionValueSource(
|
|
2054
|
+
if (cmd.getOptionValueSource(key6) !== void 0) {
|
|
2055
|
+
source = cmd.getOptionValueSource(key6);
|
|
2056
2056
|
}
|
|
2057
2057
|
});
|
|
2058
2058
|
return source;
|
|
@@ -2778,8 +2778,8 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2778
2778
|
const result = {};
|
|
2779
2779
|
const len = this.options.length;
|
|
2780
2780
|
for (let i = 0; i < len; i++) {
|
|
2781
|
-
const
|
|
2782
|
-
result[
|
|
2781
|
+
const key6 = this.options[i].attributeName();
|
|
2782
|
+
result[key6] = key6 === this._versionOptionName ? this._version : this[key6];
|
|
2783
2783
|
}
|
|
2784
2784
|
return result;
|
|
2785
2785
|
}
|
|
@@ -3524,7 +3524,9 @@ function readCliEnv() {
|
|
|
3524
3524
|
piAgentDir: runtimeEnv["PI_CODING_AGENT_DIR"],
|
|
3525
3525
|
piSessionDir: runtimeEnv["PI_CODING_AGENT_SESSION_DIR"],
|
|
3526
3526
|
hermesAgentDir: runtimeEnv["HERMES_CODING_AGENT_DIR"],
|
|
3527
|
-
hermesSessionDir: runtimeEnv["HERMES_CODING_AGENT_SESSION_DIR"]
|
|
3527
|
+
hermesSessionDir: runtimeEnv["HERMES_CODING_AGENT_SESSION_DIR"],
|
|
3528
|
+
opencodeDataDir: runtimeEnv["OPENCODE_DATA_DIR"],
|
|
3529
|
+
opencodeDbPath: runtimeEnv["OPENCODE_DB"]
|
|
3528
3530
|
};
|
|
3529
3531
|
}
|
|
3530
3532
|
|
|
@@ -3575,9 +3577,9 @@ function isNetworkError(err) {
|
|
|
3575
3577
|
|
|
3576
3578
|
// src/sync/parser-factory.ts
|
|
3577
3579
|
init_esm_shims();
|
|
3578
|
-
import { existsSync } from "fs";
|
|
3579
|
-
import { homedir as
|
|
3580
|
-
import { join as
|
|
3580
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
3581
|
+
import { homedir as homedir5 } from "os";
|
|
3582
|
+
import { isAbsolute as isAbsolute2, join as join6 } from "path";
|
|
3581
3583
|
|
|
3582
3584
|
// ../../packages/parsers/src/index.ts
|
|
3583
3585
|
init_esm_shims();
|
|
@@ -3612,6 +3614,14 @@ function readHermesSessionDir() {
|
|
|
3612
3614
|
const value = runtimeEnv2["HERMES_CODING_AGENT_SESSION_DIR"]?.trim();
|
|
3613
3615
|
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
3614
3616
|
}
|
|
3617
|
+
function readOpenCodeDataDir() {
|
|
3618
|
+
const value = runtimeEnv2["OPENCODE_DATA_DIR"]?.trim();
|
|
3619
|
+
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
3620
|
+
}
|
|
3621
|
+
function readOpenCodeDbPath() {
|
|
3622
|
+
const value = runtimeEnv2["OPENCODE_DB"]?.trim();
|
|
3623
|
+
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
3624
|
+
}
|
|
3615
3625
|
|
|
3616
3626
|
// ../../packages/parsers/src/types.ts
|
|
3617
3627
|
init_esm_shims();
|
|
@@ -4090,11 +4100,414 @@ async function* parseCodex(opts) {
|
|
|
4090
4100
|
}
|
|
4091
4101
|
}
|
|
4092
4102
|
|
|
4093
|
-
// ../../packages/parsers/src/
|
|
4103
|
+
// ../../packages/parsers/src/opencode/index.ts
|
|
4094
4104
|
init_esm_shims();
|
|
4095
|
-
import { stat as stat4 } from "fs/promises";
|
|
4105
|
+
import { readdir as readdir2, stat as stat4 } from "fs/promises";
|
|
4096
4106
|
import { homedir as homedir3 } from "os";
|
|
4097
|
-
import { join as join4 } from "path";
|
|
4107
|
+
import { basename, isAbsolute, join as join4 } from "path";
|
|
4108
|
+
|
|
4109
|
+
// ../../packages/parsers/src/opencode/bucketize.ts
|
|
4110
|
+
init_esm_shims();
|
|
4111
|
+
import { readFile } from "fs/promises";
|
|
4112
|
+
import { DatabaseSync } from "sqlite";
|
|
4113
|
+
|
|
4114
|
+
// ../../packages/parsers/src/opencode/events.ts
|
|
4115
|
+
init_esm_shims();
|
|
4116
|
+
function isObject3(value) {
|
|
4117
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4118
|
+
}
|
|
4119
|
+
function isFiniteNumber3(value) {
|
|
4120
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
4121
|
+
}
|
|
4122
|
+
function timestampMs(value) {
|
|
4123
|
+
if (isFiniteNumber3(value)) {
|
|
4124
|
+
return value;
|
|
4125
|
+
}
|
|
4126
|
+
if (typeof value !== "string") {
|
|
4127
|
+
return void 0;
|
|
4128
|
+
}
|
|
4129
|
+
const parsed = Date.parse(value);
|
|
4130
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
4131
|
+
}
|
|
4132
|
+
function isOpenCodeTokens(value) {
|
|
4133
|
+
if (!isObject3(value)) {
|
|
4134
|
+
return false;
|
|
4135
|
+
}
|
|
4136
|
+
const keys = ["input", "output", "reasoning"];
|
|
4137
|
+
for (const k of keys) {
|
|
4138
|
+
const v = value[k];
|
|
4139
|
+
if (v !== void 0 && !isFiniteNumber3(v)) {
|
|
4140
|
+
return false;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
const cache = value["cache"];
|
|
4144
|
+
if (cache !== void 0) {
|
|
4145
|
+
if (!isObject3(cache)) {
|
|
4146
|
+
return false;
|
|
4147
|
+
}
|
|
4148
|
+
for (const k of ["read", "write"]) {
|
|
4149
|
+
const v = cache[k];
|
|
4150
|
+
if (v !== void 0 && !isFiniteNumber3(v)) {
|
|
4151
|
+
return false;
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
return true;
|
|
4156
|
+
}
|
|
4157
|
+
function usageFromModernMessage(value, fallbackSessionId, fallbackTimestampMs) {
|
|
4158
|
+
const model = value["model"];
|
|
4159
|
+
if (!isObject3(model)) {
|
|
4160
|
+
return void 0;
|
|
4161
|
+
}
|
|
4162
|
+
const providerId = model["providerID"];
|
|
4163
|
+
const modelId3 = model["modelID"] ?? model["id"];
|
|
4164
|
+
if (typeof providerId !== "string" || typeof modelId3 !== "string") {
|
|
4165
|
+
return void 0;
|
|
4166
|
+
}
|
|
4167
|
+
const tokens = value["tokens"];
|
|
4168
|
+
if (!isOpenCodeTokens(tokens)) {
|
|
4169
|
+
return void 0;
|
|
4170
|
+
}
|
|
4171
|
+
const time = value["time"];
|
|
4172
|
+
const messageTimestampMs = isObject3(time) ? timestampMs(time["created"] ?? time["completed"]) : void 0;
|
|
4173
|
+
const sessionId = typeof value["sessionID"] === "string" ? value["sessionID"] : fallbackSessionId;
|
|
4174
|
+
const tsMs = messageTimestampMs ?? fallbackTimestampMs;
|
|
4175
|
+
if (sessionId === void 0 || tsMs === void 0) {
|
|
4176
|
+
return void 0;
|
|
4177
|
+
}
|
|
4178
|
+
return {
|
|
4179
|
+
sessionId,
|
|
4180
|
+
providerId,
|
|
4181
|
+
modelId: modelId3,
|
|
4182
|
+
timestampMs: tsMs,
|
|
4183
|
+
tokens
|
|
4184
|
+
};
|
|
4185
|
+
}
|
|
4186
|
+
function usageFromLegacyMessage(value, fallbackSessionId, fallbackTimestampMs) {
|
|
4187
|
+
if (value["role"] !== "assistant") {
|
|
4188
|
+
return void 0;
|
|
4189
|
+
}
|
|
4190
|
+
const providerId = value["providerID"];
|
|
4191
|
+
const modelId3 = value["modelID"];
|
|
4192
|
+
const tokens = value["tokens"];
|
|
4193
|
+
if (typeof providerId !== "string" || typeof modelId3 !== "string" || !isOpenCodeTokens(tokens)) {
|
|
4194
|
+
return void 0;
|
|
4195
|
+
}
|
|
4196
|
+
const time = value["time"];
|
|
4197
|
+
const messageTimestampMs = isObject3(time) ? timestampMs(time["created"] ?? time["completed"]) : void 0;
|
|
4198
|
+
const sessionId = typeof value["sessionID"] === "string" ? value["sessionID"] : fallbackSessionId;
|
|
4199
|
+
const tsMs = messageTimestampMs ?? fallbackTimestampMs;
|
|
4200
|
+
if (sessionId === void 0 || tsMs === void 0) {
|
|
4201
|
+
return void 0;
|
|
4202
|
+
}
|
|
4203
|
+
return {
|
|
4204
|
+
sessionId,
|
|
4205
|
+
providerId,
|
|
4206
|
+
modelId: modelId3,
|
|
4207
|
+
timestampMs: tsMs,
|
|
4208
|
+
tokens
|
|
4209
|
+
};
|
|
4210
|
+
}
|
|
4211
|
+
function usageFromMetadataMessage(value, fallbackSessionId, fallbackTimestampMs) {
|
|
4212
|
+
if (value["role"] !== "assistant") {
|
|
4213
|
+
return void 0;
|
|
4214
|
+
}
|
|
4215
|
+
const metadata = value["metadata"];
|
|
4216
|
+
if (!isObject3(metadata)) {
|
|
4217
|
+
return void 0;
|
|
4218
|
+
}
|
|
4219
|
+
const assistant = metadata["assistant"];
|
|
4220
|
+
if (!isObject3(assistant)) {
|
|
4221
|
+
return void 0;
|
|
4222
|
+
}
|
|
4223
|
+
const providerId = assistant["providerID"];
|
|
4224
|
+
const modelId3 = assistant["modelID"];
|
|
4225
|
+
const tokens = assistant["tokens"];
|
|
4226
|
+
if (typeof providerId !== "string" || typeof modelId3 !== "string" || !isOpenCodeTokens(tokens)) {
|
|
4227
|
+
return void 0;
|
|
4228
|
+
}
|
|
4229
|
+
const time = metadata["time"];
|
|
4230
|
+
const messageTimestampMs = isObject3(time) ? timestampMs(time["created"] ?? time["completed"]) : void 0;
|
|
4231
|
+
const sessionId = typeof metadata["sessionID"] === "string" ? metadata["sessionID"] : fallbackSessionId;
|
|
4232
|
+
const tsMs = messageTimestampMs ?? fallbackTimestampMs;
|
|
4233
|
+
if (sessionId === void 0 || tsMs === void 0) {
|
|
4234
|
+
return void 0;
|
|
4235
|
+
}
|
|
4236
|
+
return {
|
|
4237
|
+
sessionId,
|
|
4238
|
+
providerId,
|
|
4239
|
+
modelId: modelId3,
|
|
4240
|
+
timestampMs: tsMs,
|
|
4241
|
+
tokens
|
|
4242
|
+
};
|
|
4243
|
+
}
|
|
4244
|
+
function pickOpenCodeUsage(value, fallbackSessionId, fallbackTimestampMs) {
|
|
4245
|
+
if (!isObject3(value)) {
|
|
4246
|
+
return void 0;
|
|
4247
|
+
}
|
|
4248
|
+
return usageFromModernMessage(value, fallbackSessionId, fallbackTimestampMs) ?? usageFromLegacyMessage(value, fallbackSessionId, fallbackTimestampMs) ?? usageFromMetadataMessage(value, fallbackSessionId, fallbackTimestampMs);
|
|
4249
|
+
}
|
|
4250
|
+
|
|
4251
|
+
// ../../packages/parsers/src/opencode/bucketize.ts
|
|
4252
|
+
var MISSING_SESSION_MESSAGE_TABLE_PATTERN = /no such table: session_message/u;
|
|
4253
|
+
function key3(hourUtc, model, sessionId) {
|
|
4254
|
+
return `${hourUtc.toISOString()}|${model}|${sessionId}`;
|
|
4255
|
+
}
|
|
4256
|
+
function modelId(provider, model) {
|
|
4257
|
+
const trimmedProvider = provider.trim();
|
|
4258
|
+
const trimmedModel = model.trim();
|
|
4259
|
+
if (trimmedProvider.length === 0 || trimmedModel.length === 0) {
|
|
4260
|
+
return void 0;
|
|
4261
|
+
}
|
|
4262
|
+
return `${trimmedProvider}/${trimmedModel}`;
|
|
4263
|
+
}
|
|
4264
|
+
function finiteTimestampMs(value) {
|
|
4265
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4266
|
+
}
|
|
4267
|
+
function positive(value) {
|
|
4268
|
+
return Math.max(0, value ?? 0);
|
|
4269
|
+
}
|
|
4270
|
+
function addUsage(accumulators, usage) {
|
|
4271
|
+
const model = modelId(usage.providerId, usage.modelId);
|
|
4272
|
+
if (model === void 0) {
|
|
4273
|
+
return;
|
|
4274
|
+
}
|
|
4275
|
+
const inputTokens = positive(usage.tokens.input);
|
|
4276
|
+
const outputTokens = positive(usage.tokens.output) + positive(usage.tokens.reasoning);
|
|
4277
|
+
const cacheReadTokens = positive(usage.tokens.cache?.read);
|
|
4278
|
+
const cacheCreateTokens = positive(usage.tokens.cache?.write);
|
|
4279
|
+
if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheCreateTokens === 0) {
|
|
4280
|
+
return;
|
|
4281
|
+
}
|
|
4282
|
+
const eventAt = new Date(usage.timestampMs);
|
|
4283
|
+
const hourUtc = startOfUtcHour(eventAt);
|
|
4284
|
+
const sessionId = `opencode:${usage.sessionId}`;
|
|
4285
|
+
const accumulatorKey = key3(hourUtc, model, sessionId);
|
|
4286
|
+
const existing = accumulators.get(accumulatorKey);
|
|
4287
|
+
if (existing === void 0) {
|
|
4288
|
+
accumulators.set(accumulatorKey, {
|
|
4289
|
+
hourUtc,
|
|
4290
|
+
model,
|
|
4291
|
+
sessionId,
|
|
4292
|
+
inputTokens,
|
|
4293
|
+
outputTokens,
|
|
4294
|
+
cacheReadTokens,
|
|
4295
|
+
cacheCreateTokens,
|
|
4296
|
+
sessionStartedAt: eventAt,
|
|
4297
|
+
sessionLastSeenAt: eventAt
|
|
4298
|
+
});
|
|
4299
|
+
return;
|
|
4300
|
+
}
|
|
4301
|
+
existing.inputTokens += inputTokens;
|
|
4302
|
+
existing.outputTokens += outputTokens;
|
|
4303
|
+
existing.cacheReadTokens += cacheReadTokens;
|
|
4304
|
+
existing.cacheCreateTokens += cacheCreateTokens;
|
|
4305
|
+
if (eventAt.getTime() < existing.sessionStartedAt.getTime()) {
|
|
4306
|
+
existing.sessionStartedAt = eventAt;
|
|
4307
|
+
}
|
|
4308
|
+
if (eventAt.getTime() > existing.sessionLastSeenAt.getTime()) {
|
|
4309
|
+
existing.sessionLastSeenAt = eventAt;
|
|
4310
|
+
}
|
|
4311
|
+
}
|
|
4312
|
+
function* finalizedBuckets(accumulators) {
|
|
4313
|
+
for (const acc of accumulators.values()) {
|
|
4314
|
+
yield {
|
|
4315
|
+
harness: "opencode",
|
|
4316
|
+
model: acc.model,
|
|
4317
|
+
hourUtc: acc.hourUtc,
|
|
4318
|
+
inputTokens: acc.inputTokens,
|
|
4319
|
+
outputTokens: acc.outputTokens,
|
|
4320
|
+
cacheReadTokens: acc.cacheReadTokens,
|
|
4321
|
+
cacheCreateTokens: acc.cacheCreateTokens,
|
|
4322
|
+
sessionIds: /* @__PURE__ */ new Set([acc.sessionId]),
|
|
4323
|
+
sessionStartedAt: acc.sessionStartedAt,
|
|
4324
|
+
sessionLastSeenAt: acc.sessionLastSeenAt
|
|
4325
|
+
};
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
function parseJson(value) {
|
|
4329
|
+
return typeof value === "string" ? JSON.parse(value) : value;
|
|
4330
|
+
}
|
|
4331
|
+
function isMissingTableError(err) {
|
|
4332
|
+
return err instanceof Error && MISSING_SESSION_MESSAGE_TABLE_PATTERN.test(err.message);
|
|
4333
|
+
}
|
|
4334
|
+
function* readSessionMessageRows(db, cutoff) {
|
|
4335
|
+
const statement = db.prepare(`
|
|
4336
|
+
select session_id as "sessionId", time_created as "timeCreated", data
|
|
4337
|
+
from session_message
|
|
4338
|
+
where type = 'assistant' and time_created >= ?
|
|
4339
|
+
order by time_created asc, id asc
|
|
4340
|
+
`);
|
|
4341
|
+
yield* statement.all(cutoff.getTime());
|
|
4342
|
+
}
|
|
4343
|
+
async function* bucketizeOpenCodeDatabase(path2, cutoff, logger) {
|
|
4344
|
+
const accumulators = /* @__PURE__ */ new Map();
|
|
4345
|
+
let db;
|
|
4346
|
+
try {
|
|
4347
|
+
db = new DatabaseSync(path2, { readOnly: true, timeout: 1e3 });
|
|
4348
|
+
for (const row of readSessionMessageRows(db, cutoff)) {
|
|
4349
|
+
const sessionId = typeof row.sessionId === "string" ? row.sessionId : void 0;
|
|
4350
|
+
const fallbackTimestampMs = finiteTimestampMs(row.timeCreated);
|
|
4351
|
+
let parsed;
|
|
4352
|
+
try {
|
|
4353
|
+
parsed = parseJson(row.data);
|
|
4354
|
+
} catch {
|
|
4355
|
+
logger.warn("malformed opencode sqlite message", { path: path2 });
|
|
4356
|
+
continue;
|
|
4357
|
+
}
|
|
4358
|
+
const usage = pickOpenCodeUsage(parsed, sessionId, fallbackTimestampMs);
|
|
4359
|
+
if (usage !== void 0) {
|
|
4360
|
+
addUsage(accumulators, usage);
|
|
4361
|
+
}
|
|
4362
|
+
}
|
|
4363
|
+
} catch (err) {
|
|
4364
|
+
if (!isMissingTableError(err)) {
|
|
4365
|
+
logger.warn("failed to parse opencode sqlite database", { path: path2 });
|
|
4366
|
+
}
|
|
4367
|
+
} finally {
|
|
4368
|
+
db?.close();
|
|
4369
|
+
}
|
|
4370
|
+
yield* finalizedBuckets(accumulators);
|
|
4371
|
+
}
|
|
4372
|
+
async function* bucketizeOpenCodeJsonFile(path2, logger) {
|
|
4373
|
+
let parsed;
|
|
4374
|
+
try {
|
|
4375
|
+
parsed = JSON.parse(await readFile(path2, "utf8"));
|
|
4376
|
+
} catch {
|
|
4377
|
+
logger.warn("malformed opencode json file", { path: path2 });
|
|
4378
|
+
return;
|
|
4379
|
+
}
|
|
4380
|
+
const usage = pickOpenCodeUsage(parsed);
|
|
4381
|
+
if (usage === void 0) {
|
|
4382
|
+
return;
|
|
4383
|
+
}
|
|
4384
|
+
const accumulators = /* @__PURE__ */ new Map();
|
|
4385
|
+
addUsage(accumulators, usage);
|
|
4386
|
+
yield* finalizedBuckets(accumulators);
|
|
4387
|
+
}
|
|
4388
|
+
|
|
4389
|
+
// ../../packages/parsers/src/opencode/index.ts
|
|
4390
|
+
var OPENCODE_DB_FILE_PATTERN = /^opencode(?:-[^/]+)?\.db$/u;
|
|
4391
|
+
async function pathKind(path2) {
|
|
4392
|
+
try {
|
|
4393
|
+
const s = await stat4(path2);
|
|
4394
|
+
if (s.isFile()) {
|
|
4395
|
+
return "file";
|
|
4396
|
+
}
|
|
4397
|
+
if (s.isDirectory()) {
|
|
4398
|
+
return "directory";
|
|
4399
|
+
}
|
|
4400
|
+
return "missing";
|
|
4401
|
+
} catch {
|
|
4402
|
+
return "missing";
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
function defaultDataRoot() {
|
|
4406
|
+
return readOpenCodeDataDir() ?? join4(homedir3(), ".local", "share", "opencode");
|
|
4407
|
+
}
|
|
4408
|
+
function resolveDefaultRoot() {
|
|
4409
|
+
const dbPath = readOpenCodeDbPath();
|
|
4410
|
+
if (dbPath === void 0) {
|
|
4411
|
+
return defaultDataRoot();
|
|
4412
|
+
}
|
|
4413
|
+
if (dbPath === ":memory:") {
|
|
4414
|
+
return dbPath;
|
|
4415
|
+
}
|
|
4416
|
+
if (isAbsolute(dbPath)) {
|
|
4417
|
+
return dbPath;
|
|
4418
|
+
}
|
|
4419
|
+
return join4(defaultDataRoot(), dbPath);
|
|
4420
|
+
}
|
|
4421
|
+
async function listOpenCodeDatabases(root) {
|
|
4422
|
+
let entries;
|
|
4423
|
+
try {
|
|
4424
|
+
entries = await readdir2(root, { withFileTypes: true });
|
|
4425
|
+
} catch {
|
|
4426
|
+
return [];
|
|
4427
|
+
}
|
|
4428
|
+
return entries.filter((entry) => entry.isFile() && OPENCODE_DB_FILE_PATTERN.test(String(entry.name))).map((entry) => join4(root, String(entry.name)));
|
|
4429
|
+
}
|
|
4430
|
+
async function listProjectLegacyRoots(root) {
|
|
4431
|
+
const projectRoot = join4(root, "project");
|
|
4432
|
+
let entries;
|
|
4433
|
+
try {
|
|
4434
|
+
entries = await readdir2(projectRoot, { withFileTypes: true });
|
|
4435
|
+
} catch {
|
|
4436
|
+
return [];
|
|
4437
|
+
}
|
|
4438
|
+
return entries.filter((entry) => entry.isDirectory()).flatMap((entry) => [
|
|
4439
|
+
join4(projectRoot, String(entry.name), "storage", "message"),
|
|
4440
|
+
join4(projectRoot, String(entry.name), "storage", "session", "message")
|
|
4441
|
+
]);
|
|
4442
|
+
}
|
|
4443
|
+
async function legacyRoots(root) {
|
|
4444
|
+
return [
|
|
4445
|
+
join4(root, "storage", "message"),
|
|
4446
|
+
join4(root, "storage", "session", "message"),
|
|
4447
|
+
...await listProjectLegacyRoots(root)
|
|
4448
|
+
];
|
|
4449
|
+
}
|
|
4450
|
+
async function* walkJson(root, cutoff) {
|
|
4451
|
+
let entries;
|
|
4452
|
+
try {
|
|
4453
|
+
entries = await readdir2(root, { withFileTypes: true });
|
|
4454
|
+
} catch {
|
|
4455
|
+
return;
|
|
4456
|
+
}
|
|
4457
|
+
for (const entry of entries) {
|
|
4458
|
+
const full = join4(root, String(entry.name));
|
|
4459
|
+
if (entry.isDirectory()) {
|
|
4460
|
+
yield* walkJson(full, cutoff);
|
|
4461
|
+
continue;
|
|
4462
|
+
}
|
|
4463
|
+
if (!(entry.isFile() && entry.name.endsWith(".json"))) {
|
|
4464
|
+
continue;
|
|
4465
|
+
}
|
|
4466
|
+
let mtime;
|
|
4467
|
+
try {
|
|
4468
|
+
({ mtime } = await stat4(full));
|
|
4469
|
+
} catch {
|
|
4470
|
+
continue;
|
|
4471
|
+
}
|
|
4472
|
+
if (mtime.getTime() >= cutoff.getTime()) {
|
|
4473
|
+
yield full;
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
async function* parseOpenCode(opts) {
|
|
4478
|
+
const logger = opts.logger ?? consoleLogger;
|
|
4479
|
+
const root = opts.root ?? resolveDefaultRoot();
|
|
4480
|
+
const kind = await pathKind(root);
|
|
4481
|
+
if (kind === "missing") {
|
|
4482
|
+
return;
|
|
4483
|
+
}
|
|
4484
|
+
if (kind === "file") {
|
|
4485
|
+
if (basename(root).endsWith(".json")) {
|
|
4486
|
+
yield* bucketizeOpenCodeJsonFile(root, logger);
|
|
4487
|
+
return;
|
|
4488
|
+
}
|
|
4489
|
+
yield* bucketizeOpenCodeDatabase(root, opts.cutoff, logger);
|
|
4490
|
+
return;
|
|
4491
|
+
}
|
|
4492
|
+
const databases = await listOpenCodeDatabases(root);
|
|
4493
|
+
if (databases.length > 0) {
|
|
4494
|
+
for (const dbPath of databases) {
|
|
4495
|
+
yield* bucketizeOpenCodeDatabase(dbPath, opts.cutoff, logger);
|
|
4496
|
+
}
|
|
4497
|
+
return;
|
|
4498
|
+
}
|
|
4499
|
+
for (const legacyRoot of await legacyRoots(root)) {
|
|
4500
|
+
for await (const file of walkJson(legacyRoot, opts.cutoff)) {
|
|
4501
|
+
yield* bucketizeOpenCodeJsonFile(file, logger);
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4506
|
+
// ../../packages/parsers/src/pi/index.ts
|
|
4507
|
+
init_esm_shims();
|
|
4508
|
+
import { stat as stat5 } from "fs/promises";
|
|
4509
|
+
import { homedir as homedir4 } from "os";
|
|
4510
|
+
import { join as join5 } from "path";
|
|
4098
4511
|
|
|
4099
4512
|
// ../../packages/parsers/src/pi/bucketize.ts
|
|
4100
4513
|
init_esm_shims();
|
|
@@ -4103,27 +4516,27 @@ import { createInterface as createInterface3 } from "readline";
|
|
|
4103
4516
|
|
|
4104
4517
|
// ../../packages/parsers/src/pi/events.ts
|
|
4105
4518
|
init_esm_shims();
|
|
4106
|
-
function
|
|
4519
|
+
function isObject4(value) {
|
|
4107
4520
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4108
4521
|
}
|
|
4109
|
-
function
|
|
4522
|
+
function isFiniteNumber4(value) {
|
|
4110
4523
|
return typeof value === "number" && Number.isFinite(value);
|
|
4111
4524
|
}
|
|
4112
4525
|
function isPiUsage(value) {
|
|
4113
|
-
if (!
|
|
4526
|
+
if (!isObject4(value)) {
|
|
4114
4527
|
return false;
|
|
4115
4528
|
}
|
|
4116
4529
|
const keys = ["input", "output", "cacheRead", "cacheWrite"];
|
|
4117
4530
|
for (const k of keys) {
|
|
4118
4531
|
const v = value[k];
|
|
4119
|
-
if (v !== void 0 && !
|
|
4532
|
+
if (v !== void 0 && !isFiniteNumber4(v)) {
|
|
4120
4533
|
return false;
|
|
4121
4534
|
}
|
|
4122
4535
|
}
|
|
4123
4536
|
return true;
|
|
4124
4537
|
}
|
|
4125
4538
|
function isPiAssistantMessageEntry(value) {
|
|
4126
|
-
if (!
|
|
4539
|
+
if (!isObject4(value)) {
|
|
4127
4540
|
return false;
|
|
4128
4541
|
}
|
|
4129
4542
|
if (value["type"] !== "message") {
|
|
@@ -4133,7 +4546,7 @@ function isPiAssistantMessageEntry(value) {
|
|
|
4133
4546
|
return false;
|
|
4134
4547
|
}
|
|
4135
4548
|
const message = value["message"];
|
|
4136
|
-
if (!
|
|
4549
|
+
if (!isObject4(message)) {
|
|
4137
4550
|
return false;
|
|
4138
4551
|
}
|
|
4139
4552
|
if (message["role"] !== "assistant") {
|
|
@@ -4148,7 +4561,7 @@ function isPiAssistantMessageEntry(value) {
|
|
|
4148
4561
|
if (message["stopReason"] !== void 0 && typeof message["stopReason"] !== "string") {
|
|
4149
4562
|
return false;
|
|
4150
4563
|
}
|
|
4151
|
-
if (message["timestamp"] !== void 0 && !
|
|
4564
|
+
if (message["timestamp"] !== void 0 && !isFiniteNumber4(message["timestamp"])) {
|
|
4152
4565
|
return false;
|
|
4153
4566
|
}
|
|
4154
4567
|
if (!isPiUsage(message["usage"])) {
|
|
@@ -4158,7 +4571,7 @@ function isPiAssistantMessageEntry(value) {
|
|
|
4158
4571
|
}
|
|
4159
4572
|
|
|
4160
4573
|
// ../../packages/parsers/src/pi/bucketize.ts
|
|
4161
|
-
function
|
|
4574
|
+
function key4(hourUtc, model) {
|
|
4162
4575
|
return `${hourUtc.toISOString()}|${model}`;
|
|
4163
4576
|
}
|
|
4164
4577
|
function eventTimestampMs(entry) {
|
|
@@ -4167,7 +4580,7 @@ function eventTimestampMs(entry) {
|
|
|
4167
4580
|
}
|
|
4168
4581
|
return Date.parse(entry.timestamp);
|
|
4169
4582
|
}
|
|
4170
|
-
function
|
|
4583
|
+
function modelId2(provider, model) {
|
|
4171
4584
|
const trimmedProvider = provider.trim();
|
|
4172
4585
|
const trimmedModel = model.trim();
|
|
4173
4586
|
if (trimmedProvider.length === 0 || trimmedModel.length === 0) {
|
|
@@ -4206,7 +4619,7 @@ async function* bucketizePiStyleFile(path2, harness, logger) {
|
|
|
4206
4619
|
if (!Number.isFinite(tsMs)) {
|
|
4207
4620
|
continue;
|
|
4208
4621
|
}
|
|
4209
|
-
const model =
|
|
4622
|
+
const model = modelId2(parsed.message.provider, parsed.message.model);
|
|
4210
4623
|
if (model === void 0) {
|
|
4211
4624
|
continue;
|
|
4212
4625
|
}
|
|
@@ -4226,7 +4639,7 @@ async function* bucketizePiStyleFile(path2, harness, logger) {
|
|
|
4226
4639
|
sessionLastSeenAt = eventAt;
|
|
4227
4640
|
}
|
|
4228
4641
|
const hourUtc = startOfUtcHour(eventAt);
|
|
4229
|
-
const k =
|
|
4642
|
+
const k = key4(hourUtc, model);
|
|
4230
4643
|
const existing = buckets.get(k);
|
|
4231
4644
|
if (existing === void 0) {
|
|
4232
4645
|
buckets.set(k, {
|
|
@@ -4271,7 +4684,7 @@ async function* bucketizePiStyleFile(path2, harness, logger) {
|
|
|
4271
4684
|
// ../../packages/parsers/src/pi/index.ts
|
|
4272
4685
|
async function isFile3(path2) {
|
|
4273
4686
|
try {
|
|
4274
|
-
return (await
|
|
4687
|
+
return (await stat5(path2)).isFile();
|
|
4275
4688
|
} catch {
|
|
4276
4689
|
return false;
|
|
4277
4690
|
}
|
|
@@ -4281,14 +4694,14 @@ function defaultPiRoot() {
|
|
|
4281
4694
|
if (sessionDir !== void 0) {
|
|
4282
4695
|
return sessionDir;
|
|
4283
4696
|
}
|
|
4284
|
-
return
|
|
4697
|
+
return join5(readPiAgentDir() ?? join5(homedir4(), ".pi", "agent"), "sessions");
|
|
4285
4698
|
}
|
|
4286
4699
|
function defaultHermesRoot() {
|
|
4287
4700
|
const sessionDir = readHermesSessionDir();
|
|
4288
4701
|
if (sessionDir !== void 0) {
|
|
4289
4702
|
return sessionDir;
|
|
4290
4703
|
}
|
|
4291
|
-
return
|
|
4704
|
+
return join5(readHermesAgentDir() ?? join5(homedir4(), ".hermes", "agent"), "sessions");
|
|
4292
4705
|
}
|
|
4293
4706
|
async function* parsePiStyle(opts, harness, defaultRoot2) {
|
|
4294
4707
|
const logger = opts.logger ?? consoleLogger;
|
|
@@ -4309,29 +4722,69 @@ async function* parseHermes(opts) {
|
|
|
4309
4722
|
}
|
|
4310
4723
|
|
|
4311
4724
|
// src/sync/parser-factory.ts
|
|
4725
|
+
var OPENCODE_DB_FILE_PATTERN2 = /^opencode(?:-[^/]+)?\.db$/u;
|
|
4312
4726
|
function sessionsRoot(agentDir, sessionDir, fallbackAgentDir) {
|
|
4313
|
-
return sessionDir ??
|
|
4727
|
+
return sessionDir ?? join6(agentDir ?? fallbackAgentDir, "sessions");
|
|
4728
|
+
}
|
|
4729
|
+
function isFile4(path2) {
|
|
4730
|
+
try {
|
|
4731
|
+
return statSync(path2).isFile();
|
|
4732
|
+
} catch {
|
|
4733
|
+
return false;
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
function defaultOpenCodeDataRoot(home) {
|
|
4737
|
+
return join6(home, ".local", "share", "opencode");
|
|
4738
|
+
}
|
|
4739
|
+
function openCodeRoot(home, env) {
|
|
4740
|
+
const dataRoot = env.opencodeDataDir ?? defaultOpenCodeDataRoot(home);
|
|
4741
|
+
const dbPath = env.opencodeDbPath;
|
|
4742
|
+
if (dbPath === void 0 || dbPath === ":memory:") {
|
|
4743
|
+
return dbPath ?? dataRoot;
|
|
4744
|
+
}
|
|
4745
|
+
return isAbsolute2(dbPath) ? dbPath : join6(dataRoot, dbPath);
|
|
4746
|
+
}
|
|
4747
|
+
function hasOpenCodeDatabase(root) {
|
|
4748
|
+
let entries;
|
|
4749
|
+
try {
|
|
4750
|
+
entries = readdirSync(root);
|
|
4751
|
+
} catch {
|
|
4752
|
+
return false;
|
|
4753
|
+
}
|
|
4754
|
+
return entries.some((entry) => OPENCODE_DB_FILE_PATTERN2.test(entry) && isFile4(join6(root, entry)));
|
|
4755
|
+
}
|
|
4756
|
+
function openCodeSourceExists(root) {
|
|
4757
|
+
if (root === ":memory:") {
|
|
4758
|
+
return false;
|
|
4759
|
+
}
|
|
4760
|
+
if (isFile4(root)) {
|
|
4761
|
+
return true;
|
|
4762
|
+
}
|
|
4763
|
+
return hasOpenCodeDatabase(root) || existsSync(join6(root, "storage", "message")) || existsSync(join6(root, "storage", "session", "message")) || existsSync(join6(root, "project"));
|
|
4314
4764
|
}
|
|
4315
4765
|
function buildRealParserFactory() {
|
|
4316
4766
|
return (ctx) => {
|
|
4317
|
-
const home =
|
|
4767
|
+
const home = homedir5();
|
|
4318
4768
|
const env = readCliEnv();
|
|
4319
|
-
const codexSessionsRoot =
|
|
4320
|
-
const codexArchivedRoot =
|
|
4769
|
+
const codexSessionsRoot = join6(home, ".codex", "sessions");
|
|
4770
|
+
const codexArchivedRoot = join6(home, ".codex", "archived_sessions");
|
|
4321
4771
|
const codexExists = existsSync(codexSessionsRoot) || existsSync(codexArchivedRoot);
|
|
4322
4772
|
const envDir = env.claudeConfigDir;
|
|
4323
|
-
const claudeRoot = envDir == null ?
|
|
4773
|
+
const claudeRoot = envDir == null ? join6(home, ".claude", "projects") : join6(envDir, "projects");
|
|
4324
4774
|
const claudeExists = existsSync(claudeRoot);
|
|
4325
|
-
const piRoot = sessionsRoot(env.piAgentDir, env.piSessionDir,
|
|
4775
|
+
const piRoot = sessionsRoot(env.piAgentDir, env.piSessionDir, join6(home, ".pi", "agent"));
|
|
4326
4776
|
const piExists = existsSync(piRoot);
|
|
4327
|
-
const hermesRoot = sessionsRoot(env.hermesAgentDir, env.hermesSessionDir,
|
|
4777
|
+
const hermesRoot = sessionsRoot(env.hermesAgentDir, env.hermesSessionDir, join6(home, ".hermes", "agent"));
|
|
4328
4778
|
const hermesExists = existsSync(hermesRoot);
|
|
4779
|
+
const opencodeRoot = openCodeRoot(home, env);
|
|
4780
|
+
const opencodeExists = openCodeSourceExists(opencodeRoot);
|
|
4329
4781
|
return {
|
|
4330
|
-
anySourceExisted: codexExists || claudeExists || piExists || hermesExists,
|
|
4782
|
+
anySourceExisted: codexExists || claudeExists || piExists || hermesExists || opencodeExists,
|
|
4331
4783
|
codex: parseCodex({ cutoff: ctx.cutoff }),
|
|
4332
4784
|
claudeCode: parseClaude({ cutoff: ctx.cutoff, root: claudeRoot }),
|
|
4333
4785
|
pi: parsePi({ cutoff: ctx.cutoff, root: piRoot }),
|
|
4334
|
-
hermes: parseHermes({ cutoff: ctx.cutoff, root: hermesRoot })
|
|
4786
|
+
hermes: parseHermes({ cutoff: ctx.cutoff, root: hermesRoot }),
|
|
4787
|
+
opencode: parseOpenCode({ cutoff: ctx.cutoff, root: opencodeRoot })
|
|
4335
4788
|
};
|
|
4336
4789
|
};
|
|
4337
4790
|
}
|
|
@@ -4341,11 +4794,11 @@ init_esm_shims();
|
|
|
4341
4794
|
|
|
4342
4795
|
// src/sync/aggregate.ts
|
|
4343
4796
|
init_esm_shims();
|
|
4344
|
-
import {
|
|
4797
|
+
import { createHmac } from "crypto";
|
|
4345
4798
|
function toIso(hourUtc) {
|
|
4346
4799
|
return hourUtc instanceof Date ? hourUtc.toISOString() : hourUtc;
|
|
4347
4800
|
}
|
|
4348
|
-
function
|
|
4801
|
+
function key5(b) {
|
|
4349
4802
|
return `${b.harness} ${b.model} ${toIso(b.hourUtc)}`;
|
|
4350
4803
|
}
|
|
4351
4804
|
function finalize(acc) {
|
|
@@ -4360,8 +4813,12 @@ function finalize(acc) {
|
|
|
4360
4813
|
sessionCount: acc.sessionIds.size
|
|
4361
4814
|
};
|
|
4362
4815
|
}
|
|
4363
|
-
|
|
4364
|
-
|
|
4816
|
+
var SESSION_KEY_SALT_PATTERN = /^[a-f0-9]{64}$/u;
|
|
4817
|
+
function createSessionKey(harness, localSessionId, sessionKeySalt) {
|
|
4818
|
+
if (!SESSION_KEY_SALT_PATTERN.test(sessionKeySalt)) {
|
|
4819
|
+
throw new Error("invalid session key salt");
|
|
4820
|
+
}
|
|
4821
|
+
return createHmac("sha256", Buffer.from(sessionKeySalt, "hex")).update("oopst/session-key/v1").update("\0").update(harness).update("\0").update(localSessionId).digest("hex");
|
|
4365
4822
|
}
|
|
4366
4823
|
function sessionMapKey(harness, sessionKey) {
|
|
4367
4824
|
return `${harness} ${sessionKey}`;
|
|
@@ -4374,8 +4831,8 @@ function finalizeSession(acc) {
|
|
|
4374
4831
|
lastSeenAt: acc.lastSeenAt.toISOString()
|
|
4375
4832
|
};
|
|
4376
4833
|
}
|
|
4377
|
-
function addSessionAccumulator(sessionAccumulators, bucket, localSessionId) {
|
|
4378
|
-
const sessionKey = createSessionKey(bucket.harness, localSessionId);
|
|
4834
|
+
function addSessionAccumulator(sessionAccumulators, bucket, localSessionId, sessionKeySalt) {
|
|
4835
|
+
const sessionKey = createSessionKey(bucket.harness, localSessionId, sessionKeySalt);
|
|
4379
4836
|
const sessionAccumulatorKey = sessionMapKey(bucket.harness, sessionKey);
|
|
4380
4837
|
const existingSession = sessionAccumulators.get(sessionAccumulatorKey);
|
|
4381
4838
|
if (existingSession) {
|
|
@@ -4398,7 +4855,7 @@ async function* aggregateUsage(source, options) {
|
|
|
4398
4855
|
const accumulators = /* @__PURE__ */ new Map();
|
|
4399
4856
|
const sessionAccumulators = /* @__PURE__ */ new Map();
|
|
4400
4857
|
for await (const bucket of source) {
|
|
4401
|
-
const k =
|
|
4858
|
+
const k = key5(bucket);
|
|
4402
4859
|
let acc = accumulators.get(k);
|
|
4403
4860
|
if (!acc) {
|
|
4404
4861
|
acc = {
|
|
@@ -4419,7 +4876,7 @@ async function* aggregateUsage(source, options) {
|
|
|
4419
4876
|
acc.cacheCreateTokens += bucket.cacheCreateTokens;
|
|
4420
4877
|
for (const id of bucket.sessionIds) {
|
|
4421
4878
|
acc.sessionIds.add(id);
|
|
4422
|
-
addSessionAccumulator(sessionAccumulators, bucket, id);
|
|
4879
|
+
addSessionAccumulator(sessionAccumulators, bucket, id, options.sessionKeySalt);
|
|
4423
4880
|
}
|
|
4424
4881
|
}
|
|
4425
4882
|
const finalized = [];
|
|
@@ -4457,11 +4914,11 @@ var __commonJS2 = (cb, mod) => function() {
|
|
|
4457
4914
|
return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4458
4915
|
};
|
|
4459
4916
|
var __copyProps2 = (to, from, except, desc) => {
|
|
4460
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames2(from), i = 0, n = keys.length,
|
|
4461
|
-
|
|
4462
|
-
if (!__hasOwnProp2.call(to,
|
|
4463
|
-
get: ((k) => from[k]).bind(null,
|
|
4464
|
-
enumerable: !(desc = __getOwnPropDesc2(from,
|
|
4917
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames2(from), i = 0, n = keys.length, key6; i < n; i++) {
|
|
4918
|
+
key6 = keys[i];
|
|
4919
|
+
if (!__hasOwnProp2.call(to, key6) && key6 !== except) __defProp2(to, key6, {
|
|
4920
|
+
get: ((k) => from[k]).bind(null, key6),
|
|
4921
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key6)) || desc.enumerable
|
|
4465
4922
|
});
|
|
4466
4923
|
}
|
|
4467
4924
|
return to;
|
|
@@ -4736,7 +5193,7 @@ init_esm_shims();
|
|
|
4736
5193
|
|
|
4737
5194
|
// ../../node_modules/.pnpm/@trpc+server@11.17.0_typescript@6.0.3/node_modules/@trpc/server/dist/codes-DagpWZLc.mjs
|
|
4738
5195
|
init_esm_shims();
|
|
4739
|
-
function
|
|
5196
|
+
function isObject5(value) {
|
|
4740
5197
|
return !!value && !Array.isArray(value) && typeof value === "object";
|
|
4741
5198
|
}
|
|
4742
5199
|
function emptyObject() {
|
|
@@ -4783,11 +5240,11 @@ var __commonJS3 = (cb, mod) => function() {
|
|
|
4783
5240
|
return mod || (0, cb[__getOwnPropNames3(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4784
5241
|
};
|
|
4785
5242
|
var __copyProps3 = (to, from, except, desc) => {
|
|
4786
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames3(from), i = 0, n = keys.length,
|
|
4787
|
-
|
|
4788
|
-
if (!__hasOwnProp3.call(to,
|
|
4789
|
-
get: ((k) => from[k]).bind(null,
|
|
4790
|
-
enumerable: !(desc = __getOwnPropDesc3(from,
|
|
5243
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames3(from), i = 0, n = keys.length, key6; i < n; i++) {
|
|
5244
|
+
key6 = keys[i];
|
|
5245
|
+
if (!__hasOwnProp3.call(to, key6) && key6 !== except) __defProp3(to, key6, {
|
|
5246
|
+
get: ((k) => from[k]).bind(null, key6),
|
|
5247
|
+
enumerable: !(desc = __getOwnPropDesc3(from, key6)) || desc.enumerable
|
|
4791
5248
|
});
|
|
4792
5249
|
}
|
|
4793
5250
|
return to;
|
|
@@ -4805,9 +5262,9 @@ function createInnerProxy(callback, path2, memo) {
|
|
|
4805
5262
|
var _memo$cacheKey;
|
|
4806
5263
|
const cacheKey = path2.join(".");
|
|
4807
5264
|
(_memo$cacheKey = memo[cacheKey]) !== null && _memo$cacheKey !== void 0 || (memo[cacheKey] = new Proxy(noop, {
|
|
4808
|
-
get(_obj,
|
|
4809
|
-
if (typeof
|
|
4810
|
-
return createInnerProxy(callback, [...path2,
|
|
5265
|
+
get(_obj, key6) {
|
|
5266
|
+
if (typeof key6 !== "string" || key6 === "then") return void 0;
|
|
5267
|
+
return createInnerProxy(callback, [...path2, key6], memo);
|
|
4811
5268
|
},
|
|
4812
5269
|
apply(_1, _2, args) {
|
|
4813
5270
|
const lastOfPath = path2[path2.length - 1];
|
|
@@ -4947,8 +5404,8 @@ function transformResult(response, transformer) {
|
|
|
4947
5404
|
} catch (_unused) {
|
|
4948
5405
|
throw new TransformResultError();
|
|
4949
5406
|
}
|
|
4950
|
-
if (!result.ok && (!
|
|
4951
|
-
if (result.ok && !
|
|
5407
|
+
if (!result.ok && (!isObject5(result.error.error) || typeof result.error.error["code"] !== "number")) throw new TransformResultError();
|
|
5408
|
+
if (result.ok && !isObject5(result.result)) throw new TransformResultError();
|
|
4952
5409
|
return result;
|
|
4953
5410
|
}
|
|
4954
5411
|
var import_objectSpread22 = __toESM3(require_objectSpread22(), 1);
|
|
@@ -4960,11 +5417,11 @@ function isTRPCClientError(cause) {
|
|
|
4960
5417
|
return cause instanceof TRPCClientError;
|
|
4961
5418
|
}
|
|
4962
5419
|
function isTRPCErrorResponse(obj) {
|
|
4963
|
-
return
|
|
5420
|
+
return isObject5(obj) && isObject5(obj["error"]) && typeof obj["error"]["code"] === "number" && typeof obj["error"]["message"] === "string";
|
|
4964
5421
|
}
|
|
4965
5422
|
function getMessageFromUnknownError(err, fallback) {
|
|
4966
5423
|
if (typeof err === "string") return err;
|
|
4967
|
-
if (
|
|
5424
|
+
if (isObject5(err) && typeof err["message"] === "string") return err["message"];
|
|
4968
5425
|
return fallback;
|
|
4969
5426
|
}
|
|
4970
5427
|
var TRPCClientError = class TRPCClientError2 extends Error {
|
|
@@ -5209,11 +5666,11 @@ function dataLoader(batchLoader) {
|
|
|
5209
5666
|
});
|
|
5210
5667
|
}
|
|
5211
5668
|
}
|
|
5212
|
-
function load(
|
|
5669
|
+
function load(key6) {
|
|
5213
5670
|
var _dispatchTimer;
|
|
5214
5671
|
const item = {
|
|
5215
5672
|
aborted: false,
|
|
5216
|
-
key:
|
|
5673
|
+
key: key6,
|
|
5217
5674
|
batch: null,
|
|
5218
5675
|
resolve: throwFatalError,
|
|
5219
5676
|
reject: throwFatalError
|
|
@@ -5588,9 +6045,9 @@ function createTRPCClientProxy(client) {
|
|
|
5588
6045
|
const fullPath = pathCopy.join(".");
|
|
5589
6046
|
return client[procedureType](fullPath, ...args);
|
|
5590
6047
|
});
|
|
5591
|
-
return createFlatProxy((
|
|
5592
|
-
if (
|
|
5593
|
-
return proxy[
|
|
6048
|
+
return createFlatProxy((key6) => {
|
|
6049
|
+
if (key6 === untypedClientSymbol) return client;
|
|
6050
|
+
return proxy[key6];
|
|
5594
6051
|
});
|
|
5595
6052
|
}
|
|
5596
6053
|
function createTRPCClient(opts) {
|
|
@@ -5827,10 +6284,14 @@ async function runSync(options) {
|
|
|
5827
6284
|
const client = options.client ?? createClient({ token: options.token, serverUrl: options.serverUrl, fetch: options.fetch });
|
|
5828
6285
|
const color = options.color === true;
|
|
5829
6286
|
let watermark = null;
|
|
6287
|
+
let sessionKeySalt;
|
|
5830
6288
|
try {
|
|
5831
6289
|
options.logger.info(phase("Checking server sync point...", color));
|
|
5832
|
-
const
|
|
5833
|
-
|
|
6290
|
+
const { sessionKeySalt: returnedSessionKeySalt, watermarkHourUtc } = await client.sync.getWatermark.mutate({
|
|
6291
|
+
device: options.device
|
|
6292
|
+
});
|
|
6293
|
+
watermark = watermarkHourUtc ? new Date(watermarkHourUtc) : null;
|
|
6294
|
+
sessionKeySalt = returnedSessionKeySalt;
|
|
5834
6295
|
} catch (err) {
|
|
5835
6296
|
return failureFromTrpcError(err, options.logger);
|
|
5836
6297
|
}
|
|
@@ -5852,13 +6313,19 @@ async function runSync(options) {
|
|
|
5852
6313
|
if (options.harness === void 0 || options.harness === "hermes") {
|
|
5853
6314
|
sources.push({ label: "Hermes", source: parsers.hermes });
|
|
5854
6315
|
}
|
|
6316
|
+
if (options.harness === void 0 || options.harness === "opencode") {
|
|
6317
|
+
sources.push({ label: "OpenCode", source: parsers.opencode });
|
|
6318
|
+
}
|
|
5855
6319
|
let bucketsUploaded = 0;
|
|
5856
6320
|
let sessionsUploaded = 0;
|
|
5857
6321
|
let batchesUploaded = 0;
|
|
5858
6322
|
const batches = [];
|
|
5859
6323
|
try {
|
|
5860
6324
|
const progressSources = sources.map((source) => withScanProgress(source, options.logger, color));
|
|
5861
|
-
for await (const batch of aggregateUsage(merge(progressSources), {
|
|
6325
|
+
for await (const batch of aggregateUsage(merge(progressSources), {
|
|
6326
|
+
batchSize: SYNC_BATCH_SIZE,
|
|
6327
|
+
sessionKeySalt
|
|
6328
|
+
})) {
|
|
5862
6329
|
if (batch.buckets.length === 0 && batch.sessions.length === 0) {
|
|
5863
6330
|
continue;
|
|
5864
6331
|
}
|
|
@@ -5887,7 +6354,7 @@ async function runSync(options) {
|
|
|
5887
6354
|
options.logger.info(
|
|
5888
6355
|
`${dryRunPrefix(color)} ${usageRecordText(plannedBuckets)} from ${localSessionText(plannedSessions)} would be uploaded in ${uploadRequestText(batches.length)}.`
|
|
5889
6356
|
);
|
|
5890
|
-
options.logger.info(muted("No data was
|
|
6357
|
+
options.logger.info(muted("No usage data was uploaded.", color));
|
|
5891
6358
|
return {
|
|
5892
6359
|
exitCode: EXIT.success,
|
|
5893
6360
|
batchesUploaded: batches.length,
|
|
@@ -6023,7 +6490,7 @@ function readPackageVersion() {
|
|
|
6023
6490
|
return "0.0.0";
|
|
6024
6491
|
}
|
|
6025
6492
|
var VERSION = readPackageVersion();
|
|
6026
|
-
var SUPPORTED_HARNESSES = ["codex", "claude_code", "pi", "hermes"];
|
|
6493
|
+
var SUPPORTED_HARNESSES = ["codex", "claude_code", "pi", "hermes", "opencode"];
|
|
6027
6494
|
function writeStdoutLine(msg) {
|
|
6028
6495
|
process4.stdout.write(`${msg}
|
|
6029
6496
|
`);
|
|
@@ -6057,7 +6524,7 @@ function buildCli() {
|
|
|
6057
6524
|
const env = readCliEnv();
|
|
6058
6525
|
const program2 = new Command();
|
|
6059
6526
|
program2.name("oopst").description("OopsT \u2014 track AI coding token usage across users and devices").version(VERSION).exitOverride();
|
|
6060
|
-
program2.command("sync").description("Scan local
|
|
6527
|
+
program2.command("sync").description("Scan local AI coding harness logs and upload hourly usage records").option("--token <token>", "CLI API token (or OOPST_TOKEN env)").option("--device <name>", "Device name (or OOPST_DEVICE env)").option("--server <url>", "Server base URL", env.serverUrl).option("--lookback-days <days>", "Override watermark lookback", DEFAULT_LOOKBACK_DAYS).option("--harness <harness>", "Restrict to codex|claude_code|pi|hermes|opencode").option("--dry-run", "Parse and print without uploading", false).option("--verbose", "Verbose logs", false).action(
|
|
6061
6528
|
async (raw) => {
|
|
6062
6529
|
const token = raw.token ?? env.token;
|
|
6063
6530
|
const device = raw.device ?? env.device;
|