repoburg 1.3.274 → 1.3.275
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/agent-pane/backend/dist/index.js +424 -79
- package/agent-pane/backend/dist/server.js +424 -79
- package/agent-pane/frontend/dist/assets/{index-DlwZnsU3.css → index-BKDM-AC5.css} +1 -1
- package/agent-pane/frontend/dist/assets/index-BNyA-dQb.js +617 -0
- package/agent-pane/frontend/dist/index.html +2 -2
- package/backend/dist/src/core-entities/llm-call-log.entity.d.ts +2 -0
- package/backend/dist/src/core-entities/llm-call-log.entity.js +11 -0
- package/backend/dist/src/core-entities/llm-call-log.entity.js.map +1 -1
- package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.d.ts +2 -0
- package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js +6 -0
- package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js.map +1 -1
- package/backend/dist/src/llm-call-logs/llm-call-logs.module.js +2 -1
- package/backend/dist/src/llm-call-logs/llm-call-logs.module.js.map +1 -1
- package/backend/dist/src/llm-call-logs/llm-call-logs.service.d.ts +3 -1
- package/backend/dist/src/llm-call-logs/llm-call-logs.service.js +8 -2
- package/backend/dist/src/llm-call-logs/llm-call-logs.service.js.map +1 -1
- package/backend/dist/src/llm-provider/alibaba-llm.provider.js +1 -0
- package/backend/dist/src/llm-provider/alibaba-llm.provider.js.map +1 -1
- package/backend/dist/src/llm-provider/ollama-llm.provider.js +1 -0
- package/backend/dist/src/llm-provider/ollama-llm.provider.js.map +1 -1
- package/backend/dist/src/llm-provider/openai-llm.provider.js +1 -0
- package/backend/dist/src/llm-provider/openai-llm.provider.js.map +1 -1
- package/backend/dist/src/llm-provider/openrouter-llm.provider.js +1 -0
- package/backend/dist/src/llm-provider/openrouter-llm.provider.js.map +1 -1
- package/backend/dist/src/llm-provider/zai-llm.provider.js +1 -0
- package/backend/dist/src/llm-provider/zai-llm.provider.js.map +1 -1
- package/backend/dist/src/usage-export/usage-export.module.d.ts +2 -0
- package/backend/dist/src/usage-export/usage-export.module.js +21 -0
- package/backend/dist/src/usage-export/usage-export.module.js.map +1 -0
- package/backend/dist/src/usage-export/usage-export.service.d.ts +6 -0
- package/backend/dist/src/usage-export/usage-export.service.js +54 -0
- package/backend/dist/src/usage-export/usage-export.service.js.map +1 -0
- package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/tabtape/extension/dist/build-info.json +3 -3
- package/tabtape/extension/dist/manifest.json +1 -1
- package/tabtape/ui/dist/build-info.json +3 -3
- package/agent-pane/frontend/dist/assets/index-WRsdlJfD.js +0 -606
|
@@ -372,26 +372,26 @@ var require_permessage_deflate = __commonJS({
|
|
|
372
372
|
value = value[0];
|
|
373
373
|
if (key === "client_max_window_bits") {
|
|
374
374
|
if (value !== true) {
|
|
375
|
-
const
|
|
376
|
-
if (!Number.isInteger(
|
|
375
|
+
const num2 = +value;
|
|
376
|
+
if (!Number.isInteger(num2) || num2 < 8 || num2 > 15) {
|
|
377
377
|
throw new TypeError(
|
|
378
378
|
`Invalid value for parameter "${key}": ${value}`
|
|
379
379
|
);
|
|
380
380
|
}
|
|
381
|
-
value =
|
|
381
|
+
value = num2;
|
|
382
382
|
} else if (!this._isServer) {
|
|
383
383
|
throw new TypeError(
|
|
384
384
|
`Invalid value for parameter "${key}": ${value}`
|
|
385
385
|
);
|
|
386
386
|
}
|
|
387
387
|
} else if (key === "server_max_window_bits") {
|
|
388
|
-
const
|
|
389
|
-
if (!Number.isInteger(
|
|
388
|
+
const num2 = +value;
|
|
389
|
+
if (!Number.isInteger(num2) || num2 < 8 || num2 > 15) {
|
|
390
390
|
throw new TypeError(
|
|
391
391
|
`Invalid value for parameter "${key}": ${value}`
|
|
392
392
|
);
|
|
393
393
|
}
|
|
394
|
-
value =
|
|
394
|
+
value = num2;
|
|
395
395
|
} else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") {
|
|
396
396
|
if (value !== true) {
|
|
397
397
|
throw new TypeError(
|
|
@@ -1105,8 +1105,8 @@ var require_receiver = __commonJS({
|
|
|
1105
1105
|
return;
|
|
1106
1106
|
}
|
|
1107
1107
|
const buf = this.consume(8);
|
|
1108
|
-
const
|
|
1109
|
-
if (
|
|
1108
|
+
const num2 = buf.readUInt32BE(0);
|
|
1109
|
+
if (num2 > Math.pow(2, 53 - 32) - 1) {
|
|
1110
1110
|
const error = this.createError(
|
|
1111
1111
|
RangeError,
|
|
1112
1112
|
"Unsupported WebSocket frame: payload length > 2^53 - 1",
|
|
@@ -1117,7 +1117,7 @@ var require_receiver = __commonJS({
|
|
|
1117
1117
|
cb(error);
|
|
1118
1118
|
return;
|
|
1119
1119
|
}
|
|
1120
|
-
this._payloadLength =
|
|
1120
|
+
this._payloadLength = num2 * Math.pow(2, 32) + buf.readUInt32BE(4);
|
|
1121
1121
|
this.haveLength(cb);
|
|
1122
1122
|
}
|
|
1123
1123
|
/**
|
|
@@ -11520,7 +11520,7 @@ var require_thread_stream = __commonJS({
|
|
|
11520
11520
|
var { version } = require_package();
|
|
11521
11521
|
var { EventEmitter: EventEmitter2 } = __require("events");
|
|
11522
11522
|
var { Worker } = __require("worker_threads");
|
|
11523
|
-
var { join:
|
|
11523
|
+
var { join: join5 } = __require("path");
|
|
11524
11524
|
var { pathToFileURL } = __require("url");
|
|
11525
11525
|
var { wait } = require_wait();
|
|
11526
11526
|
var {
|
|
@@ -11571,7 +11571,7 @@ var require_thread_stream = __commonJS({
|
|
|
11571
11571
|
function createWorker(stream, opts) {
|
|
11572
11572
|
const { filename, workerData } = opts;
|
|
11573
11573
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
11574
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
11574
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join5(__dirname, "lib", "worker.js");
|
|
11575
11575
|
const worker = new Worker(toExecute, {
|
|
11576
11576
|
...opts.workerOpts,
|
|
11577
11577
|
name: opts.workerOpts?.name || "thread-stream",
|
|
@@ -12039,7 +12039,7 @@ var require_transport = __commonJS({
|
|
|
12039
12039
|
var { createRequire } = __require("module");
|
|
12040
12040
|
var { existsSync: existsSync3 } = __require("node:fs");
|
|
12041
12041
|
var getCallers = require_caller();
|
|
12042
|
-
var { join:
|
|
12042
|
+
var { join: join5, isAbsolute, sep } = __require("node:path");
|
|
12043
12043
|
var { fileURLToPath: fileURLToPath3 } = __require("node:url");
|
|
12044
12044
|
var sleep = require_atomic_sleep();
|
|
12045
12045
|
var onExit = require_on_exit_leak_free();
|
|
@@ -12192,7 +12192,7 @@ var require_transport = __commonJS({
|
|
|
12192
12192
|
throw new Error("only one of target or targets can be specified");
|
|
12193
12193
|
}
|
|
12194
12194
|
if (targets) {
|
|
12195
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
12195
|
+
target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
|
|
12196
12196
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
12197
12197
|
return {
|
|
12198
12198
|
...dest,
|
|
@@ -12210,7 +12210,7 @@ var require_transport = __commonJS({
|
|
|
12210
12210
|
});
|
|
12211
12211
|
});
|
|
12212
12212
|
} else if (pipeline) {
|
|
12213
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
12213
|
+
target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
|
|
12214
12214
|
options.pipelines = [pipeline.map((dest) => {
|
|
12215
12215
|
return {
|
|
12216
12216
|
...dest,
|
|
@@ -12233,7 +12233,7 @@ var require_transport = __commonJS({
|
|
|
12233
12233
|
return origin;
|
|
12234
12234
|
}
|
|
12235
12235
|
if (origin === "pino/file") {
|
|
12236
|
-
return
|
|
12236
|
+
return join5(__dirname, "..", "file.js");
|
|
12237
12237
|
}
|
|
12238
12238
|
let fixTarget2;
|
|
12239
12239
|
for (const filePath of callers) {
|
|
@@ -12348,14 +12348,14 @@ var require_tools = __commonJS({
|
|
|
12348
12348
|
}
|
|
12349
12349
|
return point < 32 ? JSON.stringify(str) : '"' + result + '"';
|
|
12350
12350
|
}
|
|
12351
|
-
function asJson(obj, msg,
|
|
12351
|
+
function asJson(obj, msg, num2, time) {
|
|
12352
12352
|
if (asJsonChan.hasSubscribers === false) {
|
|
12353
|
-
return _asJson.call(this, obj, msg,
|
|
12353
|
+
return _asJson.call(this, obj, msg, num2, time);
|
|
12354
12354
|
}
|
|
12355
12355
|
const store = { instance: this, arguments };
|
|
12356
|
-
return asJsonChan.traceSync(_asJson, store, this, obj, msg,
|
|
12356
|
+
return asJsonChan.traceSync(_asJson, store, this, obj, msg, num2, time);
|
|
12357
12357
|
}
|
|
12358
|
-
function _asJson(obj, msg,
|
|
12358
|
+
function _asJson(obj, msg, num2, time) {
|
|
12359
12359
|
const stringify2 = this[stringifySym];
|
|
12360
12360
|
const stringifySafe = this[stringifySafeSym];
|
|
12361
12361
|
const stringifiers = this[stringifiersSym];
|
|
@@ -12365,7 +12365,7 @@ var require_tools = __commonJS({
|
|
|
12365
12365
|
const formatters = this[formattersSym];
|
|
12366
12366
|
const messageKey = this[messageKeySym];
|
|
12367
12367
|
const errorKey = this[errorKeySym];
|
|
12368
|
-
let data = this[lsCacheSym][
|
|
12368
|
+
let data = this[lsCacheSym][num2] + time;
|
|
12369
12369
|
data = data + chindings;
|
|
12370
12370
|
let value;
|
|
12371
12371
|
if (formatters.log) {
|
|
@@ -12990,7 +12990,7 @@ var require_proto = __commonJS({
|
|
|
12990
12990
|
function defaultMixinMergeStrategy(mergeObject, mixinObject) {
|
|
12991
12991
|
return Object.assign(mixinObject, mergeObject);
|
|
12992
12992
|
}
|
|
12993
|
-
function write(_obj, msg,
|
|
12993
|
+
function write(_obj, msg, num2) {
|
|
12994
12994
|
const t = this[timeSym]();
|
|
12995
12995
|
const mixin = this[mixinSym];
|
|
12996
12996
|
const errorKey = this[errorKeySym];
|
|
@@ -13012,12 +13012,12 @@ var require_proto = __commonJS({
|
|
|
13012
13012
|
}
|
|
13013
13013
|
}
|
|
13014
13014
|
if (mixin) {
|
|
13015
|
-
obj = mixinMergeStrategy(obj, mixin(obj,
|
|
13015
|
+
obj = mixinMergeStrategy(obj, mixin(obj, num2, this));
|
|
13016
13016
|
}
|
|
13017
|
-
const s = this[asJsonSym](obj, msg,
|
|
13017
|
+
const s = this[asJsonSym](obj, msg, num2, t);
|
|
13018
13018
|
const stream = this[streamSym];
|
|
13019
13019
|
if (stream[needsMetadataGsym] === true) {
|
|
13020
|
-
stream.lastLevel =
|
|
13020
|
+
stream.lastLevel = num2;
|
|
13021
13021
|
stream.lastObj = obj;
|
|
13022
13022
|
stream.lastMsg = msg;
|
|
13023
13023
|
stream.lastTime = t.slice(this[timeSliceIndexSym]);
|
|
@@ -13213,7 +13213,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
13213
13213
|
return circularValue;
|
|
13214
13214
|
}
|
|
13215
13215
|
let res = "";
|
|
13216
|
-
let
|
|
13216
|
+
let join5 = ",";
|
|
13217
13217
|
const originalIndentation = indentation;
|
|
13218
13218
|
if (Array.isArray(value)) {
|
|
13219
13219
|
if (value.length === 0) {
|
|
@@ -13227,7 +13227,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
13227
13227
|
indentation += spacer;
|
|
13228
13228
|
res += `
|
|
13229
13229
|
${indentation}`;
|
|
13230
|
-
|
|
13230
|
+
join5 = `,
|
|
13231
13231
|
${indentation}`;
|
|
13232
13232
|
}
|
|
13233
13233
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -13235,13 +13235,13 @@ ${indentation}`;
|
|
|
13235
13235
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13236
13236
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
13237
13237
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
13238
|
-
res +=
|
|
13238
|
+
res += join5;
|
|
13239
13239
|
}
|
|
13240
13240
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
13241
13241
|
res += tmp !== void 0 ? tmp : "null";
|
|
13242
13242
|
if (value.length - 1 > maximumBreadth) {
|
|
13243
13243
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13244
|
-
res += `${
|
|
13244
|
+
res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13245
13245
|
}
|
|
13246
13246
|
if (spacer !== "") {
|
|
13247
13247
|
res += `
|
|
@@ -13262,7 +13262,7 @@ ${originalIndentation}`;
|
|
|
13262
13262
|
let separator = "";
|
|
13263
13263
|
if (spacer !== "") {
|
|
13264
13264
|
indentation += spacer;
|
|
13265
|
-
|
|
13265
|
+
join5 = `,
|
|
13266
13266
|
${indentation}`;
|
|
13267
13267
|
whitespace = " ";
|
|
13268
13268
|
}
|
|
@@ -13276,13 +13276,13 @@ ${indentation}`;
|
|
|
13276
13276
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
13277
13277
|
if (tmp !== void 0) {
|
|
13278
13278
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
13279
|
-
separator =
|
|
13279
|
+
separator = join5;
|
|
13280
13280
|
}
|
|
13281
13281
|
}
|
|
13282
13282
|
if (keyLength > maximumBreadth) {
|
|
13283
13283
|
const removedKeys = keyLength - maximumBreadth;
|
|
13284
13284
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
13285
|
-
separator =
|
|
13285
|
+
separator = join5;
|
|
13286
13286
|
}
|
|
13287
13287
|
if (spacer !== "" && separator.length > 1) {
|
|
13288
13288
|
res = `
|
|
@@ -13323,7 +13323,7 @@ ${originalIndentation}`;
|
|
|
13323
13323
|
}
|
|
13324
13324
|
const originalIndentation = indentation;
|
|
13325
13325
|
let res = "";
|
|
13326
|
-
let
|
|
13326
|
+
let join5 = ",";
|
|
13327
13327
|
if (Array.isArray(value)) {
|
|
13328
13328
|
if (value.length === 0) {
|
|
13329
13329
|
return "[]";
|
|
@@ -13336,7 +13336,7 @@ ${originalIndentation}`;
|
|
|
13336
13336
|
indentation += spacer;
|
|
13337
13337
|
res += `
|
|
13338
13338
|
${indentation}`;
|
|
13339
|
-
|
|
13339
|
+
join5 = `,
|
|
13340
13340
|
${indentation}`;
|
|
13341
13341
|
}
|
|
13342
13342
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -13344,13 +13344,13 @@ ${indentation}`;
|
|
|
13344
13344
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13345
13345
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
13346
13346
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
13347
|
-
res +=
|
|
13347
|
+
res += join5;
|
|
13348
13348
|
}
|
|
13349
13349
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
13350
13350
|
res += tmp !== void 0 ? tmp : "null";
|
|
13351
13351
|
if (value.length - 1 > maximumBreadth) {
|
|
13352
13352
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13353
|
-
res += `${
|
|
13353
|
+
res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13354
13354
|
}
|
|
13355
13355
|
if (spacer !== "") {
|
|
13356
13356
|
res += `
|
|
@@ -13363,7 +13363,7 @@ ${originalIndentation}`;
|
|
|
13363
13363
|
let whitespace = "";
|
|
13364
13364
|
if (spacer !== "") {
|
|
13365
13365
|
indentation += spacer;
|
|
13366
|
-
|
|
13366
|
+
join5 = `,
|
|
13367
13367
|
${indentation}`;
|
|
13368
13368
|
whitespace = " ";
|
|
13369
13369
|
}
|
|
@@ -13372,7 +13372,7 @@ ${indentation}`;
|
|
|
13372
13372
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
13373
13373
|
if (tmp !== void 0) {
|
|
13374
13374
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
13375
|
-
separator =
|
|
13375
|
+
separator = join5;
|
|
13376
13376
|
}
|
|
13377
13377
|
}
|
|
13378
13378
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -13430,20 +13430,20 @@ ${originalIndentation}`;
|
|
|
13430
13430
|
indentation += spacer;
|
|
13431
13431
|
let res2 = `
|
|
13432
13432
|
${indentation}`;
|
|
13433
|
-
const
|
|
13433
|
+
const join6 = `,
|
|
13434
13434
|
${indentation}`;
|
|
13435
13435
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
13436
13436
|
let i = 0;
|
|
13437
13437
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
13438
13438
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
13439
13439
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
13440
|
-
res2 +=
|
|
13440
|
+
res2 += join6;
|
|
13441
13441
|
}
|
|
13442
13442
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
13443
13443
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
13444
13444
|
if (value.length - 1 > maximumBreadth) {
|
|
13445
13445
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
13446
|
-
res2 += `${
|
|
13446
|
+
res2 += `${join6}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
13447
13447
|
}
|
|
13448
13448
|
res2 += `
|
|
13449
13449
|
${originalIndentation}`;
|
|
@@ -13459,16 +13459,16 @@ ${originalIndentation}`;
|
|
|
13459
13459
|
return '"[Object]"';
|
|
13460
13460
|
}
|
|
13461
13461
|
indentation += spacer;
|
|
13462
|
-
const
|
|
13462
|
+
const join5 = `,
|
|
13463
13463
|
${indentation}`;
|
|
13464
13464
|
let res = "";
|
|
13465
13465
|
let separator = "";
|
|
13466
13466
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
13467
13467
|
if (isTypedArrayWithEntries(value)) {
|
|
13468
|
-
res += stringifyTypedArray(value,
|
|
13468
|
+
res += stringifyTypedArray(value, join5, maximumBreadth);
|
|
13469
13469
|
keys = keys.slice(value.length);
|
|
13470
13470
|
maximumPropertiesToStringify -= value.length;
|
|
13471
|
-
separator =
|
|
13471
|
+
separator = join5;
|
|
13472
13472
|
}
|
|
13473
13473
|
if (deterministic) {
|
|
13474
13474
|
keys = sort(keys, comparator);
|
|
@@ -13479,13 +13479,13 @@ ${indentation}`;
|
|
|
13479
13479
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
13480
13480
|
if (tmp !== void 0) {
|
|
13481
13481
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
13482
|
-
separator =
|
|
13482
|
+
separator = join5;
|
|
13483
13483
|
}
|
|
13484
13484
|
}
|
|
13485
13485
|
if (keyLength > maximumBreadth) {
|
|
13486
13486
|
const removedKeys = keyLength - maximumBreadth;
|
|
13487
13487
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
13488
|
-
separator =
|
|
13488
|
+
separator = join5;
|
|
13489
13489
|
}
|
|
13490
13490
|
if (separator !== "") {
|
|
13491
13491
|
res = `
|
|
@@ -14379,13 +14379,13 @@ var require_serializer = __commonJS({
|
|
|
14379
14379
|
return "" + integer;
|
|
14380
14380
|
}
|
|
14381
14381
|
asNumber(i) {
|
|
14382
|
-
const
|
|
14383
|
-
if (
|
|
14382
|
+
const num2 = Number(i);
|
|
14383
|
+
if (num2 !== num2) {
|
|
14384
14384
|
throw new Error(`The value "${i}" cannot be converted to a number.`);
|
|
14385
|
-
} else if (
|
|
14385
|
+
} else if (num2 === Infinity || num2 === -Infinity) {
|
|
14386
14386
|
return "null";
|
|
14387
14387
|
} else {
|
|
14388
|
-
return "" +
|
|
14388
|
+
return "" + num2;
|
|
14389
14389
|
}
|
|
14390
14390
|
}
|
|
14391
14391
|
asBoolean(bool) {
|
|
@@ -31796,9 +31796,9 @@ var require_semver = __commonJS({
|
|
|
31796
31796
|
} else {
|
|
31797
31797
|
this.prerelease = m[4].split(".").map((id) => {
|
|
31798
31798
|
if (/^[0-9]+$/.test(id)) {
|
|
31799
|
-
const
|
|
31800
|
-
if (
|
|
31801
|
-
return
|
|
31799
|
+
const num2 = +id;
|
|
31800
|
+
if (num2 >= 0 && num2 < MAX_SAFE_INTEGER) {
|
|
31801
|
+
return num2;
|
|
31802
31802
|
}
|
|
31803
31803
|
}
|
|
31804
31804
|
return id;
|
|
@@ -41789,6 +41789,25 @@ var import_cors = __toESM(require_cors(), 1);
|
|
|
41789
41789
|
// src/routes/sessions.ts
|
|
41790
41790
|
import path from "node:path";
|
|
41791
41791
|
|
|
41792
|
+
// src/db/item-trim.ts
|
|
41793
|
+
var TRIMMABLE_KEYS = ["aggregated_output", "output"];
|
|
41794
|
+
var MAX_ITEM_TEXT_BYTES = 64e3;
|
|
41795
|
+
function prunedMarker(maxBytes) {
|
|
41796
|
+
return `\u2026 [pruned: kept newest ${maxBytes} bytes]
|
|
41797
|
+
`;
|
|
41798
|
+
}
|
|
41799
|
+
function trimItemData(data, maxBytes = MAX_ITEM_TEXT_BYTES) {
|
|
41800
|
+
let trimmed = null;
|
|
41801
|
+
for (const key of TRIMMABLE_KEYS) {
|
|
41802
|
+
const value = data[key];
|
|
41803
|
+
if (typeof value === "string" && value.length > maxBytes) {
|
|
41804
|
+
if (!trimmed) trimmed = { ...data };
|
|
41805
|
+
trimmed[key] = prunedMarker(maxBytes) + value.slice(-maxBytes);
|
|
41806
|
+
}
|
|
41807
|
+
}
|
|
41808
|
+
return trimmed ?? data;
|
|
41809
|
+
}
|
|
41810
|
+
|
|
41792
41811
|
// src/routes/session-touch.ts
|
|
41793
41812
|
function markSessionTouched(db2, sessionId) {
|
|
41794
41813
|
const { changes } = db2.prepare("UPDATE sessions SET user_touched = 1 WHERE id = ? AND user_touched = 0").run(sessionId);
|
|
@@ -41819,7 +41838,7 @@ async function registerSessionRoutes(fastify) {
|
|
|
41819
41838
|
for (const row of itemRows) {
|
|
41820
41839
|
const item = {
|
|
41821
41840
|
...row,
|
|
41822
|
-
data: row.data ? JSON.parse(row.data) : null
|
|
41841
|
+
data: row.data ? trimItemData(JSON.parse(row.data)) : null
|
|
41823
41842
|
};
|
|
41824
41843
|
const list = itemsByTurn.get(item.turn_id) ?? [];
|
|
41825
41844
|
list.push(item);
|
|
@@ -43402,7 +43421,6 @@ async function registerPerfLogRoutes(fastify) {
|
|
|
43402
43421
|
}
|
|
43403
43422
|
|
|
43404
43423
|
// src/routes/maintenance.ts
|
|
43405
|
-
var TRIMMABLE_KEYS = ["aggregated_output", "output"];
|
|
43406
43424
|
async function registerMaintenanceRoutes(fastify) {
|
|
43407
43425
|
fastify.post(
|
|
43408
43426
|
"/api/maintenance/prune-items",
|
|
@@ -43435,17 +43453,9 @@ async function registerMaintenanceRoutes(fastify) {
|
|
|
43435
43453
|
} catch {
|
|
43436
43454
|
continue;
|
|
43437
43455
|
}
|
|
43438
|
-
|
|
43439
|
-
|
|
43440
|
-
|
|
43441
|
-
if (typeof v === "string" && v.length > maxBytes) {
|
|
43442
|
-
data[key] = `\u2026 [pruned: kept newest ${maxBytes} bytes]
|
|
43443
|
-
` + v.slice(-maxBytes);
|
|
43444
|
-
changed = true;
|
|
43445
|
-
}
|
|
43446
|
-
}
|
|
43447
|
-
if (!changed) continue;
|
|
43448
|
-
const next = JSON.stringify(data);
|
|
43456
|
+
const trimmed = trimItemData(data, maxBytes);
|
|
43457
|
+
if (trimmed === data) continue;
|
|
43458
|
+
const next = JSON.stringify(trimmed);
|
|
43449
43459
|
bytesBefore += row.data.length;
|
|
43450
43460
|
bytesAfter += next.length;
|
|
43451
43461
|
pruned++;
|
|
@@ -98293,6 +98303,7 @@ Icons come from ONE library: Lucide (https://lucide.dev/icons, ISC).
|
|
|
98293
98303
|
- createSession({ cwd, runtime_type, model, model_reasoning_effort, title }) - agent session owned by this app; model_reasoning_effort is the effort for its turns ("low" | "medium" | "high" | "xhigh" | "max" | "ultra", the levels the model supports), omitted = the runtime's default
|
|
98294
98304
|
- submitTurn(sessionId, prompt, { attachments }?) - send a prompt to a session; attachments (optional) are stored files (id, url or the uploadFile result) or inline Blobs / { name, type, data } sent with that turn only; the agent sees attached images (Claude and Codex)
|
|
98295
98305
|
- onTurnCompleted(callback) - callback(event, { turnId, response }) when a turn ends
|
|
98306
|
+
- onBackgroundTasks(callback) - callback({ sessionId, tasks }) when the live background-task set of one of the app's sessions changes (Monitor shells, backgrounded subagents); tasks is the CURRENT set, empty when none are left
|
|
98296
98307
|
- onToolCall(callback) - callback({ callId, name, tool, args }) when the AGENT calls one of the manifest tools (name and tool carry the same tool name); answer with resolveToolCall(callId, result)
|
|
98297
98308
|
- openSession(sessionId) - show that session in the pane (the view switches to its conversation); works only while the app is on screen, so call it from a click handler
|
|
98298
98309
|
- openUrl(url) - open an absolute http(s) URL in a new browser tab; call it from a click handler (popup blockers allow tabs opened by a click)
|
|
@@ -98577,6 +98588,10 @@ interface AgentPaneCreateSessionOptions {
|
|
|
98577
98588
|
interface AgentPaneTurnPayload { turnId?: string; response?: string | null; error?: string }
|
|
98578
98589
|
interface AgentPaneDeltaPayload { sessionId?: string; turnId?: string; itemId?: string; delta?: string }
|
|
98579
98590
|
interface AgentPaneToolCallPayload { callId: string; tool: string; name: string; args: Record<string, unknown> }
|
|
98591
|
+
/** Live background tasks of a session (Monitor shells, backgrounded subagents):
|
|
98592
|
+
* the CURRENT set, REPLACE semantics \u2014 an empty array means none are left. */
|
|
98593
|
+
interface AgentPaneBackgroundTasksPayload { sessionId?: string; tasks?: AgentPaneBackgroundTask[] }
|
|
98594
|
+
interface AgentPaneBackgroundTask { task_id: string; task_type: string; description: string }
|
|
98580
98595
|
/** A file the app stored with uploadFile (PNG, JPEG, GIF or WebP, max 5 MB). */
|
|
98581
98596
|
interface AgentPaneFile {
|
|
98582
98597
|
/** Content id "<sha256>.<ext>": the same bytes always get the same id. */
|
|
@@ -98614,6 +98629,9 @@ declare const AgentPane: {
|
|
|
98614
98629
|
onTurnDelta(cb: (payload: AgentPaneDeltaPayload) => void): void;
|
|
98615
98630
|
onToolCall(cb: (payload: AgentPaneToolCallPayload) => void): void;
|
|
98616
98631
|
onStateChanged(cb: (payload: unknown) => void): void;
|
|
98632
|
+
/** Fires when the live background-task set of one of the app's sessions
|
|
98633
|
+
* changes (also empty sets, when the last task ends). */
|
|
98634
|
+
onBackgroundTasks(cb: (payload: AgentPaneBackgroundTasksPayload | null) => void): void;
|
|
98617
98635
|
resolveToolCall(callId: string, result?: unknown): Promise<{ ok: boolean }>;
|
|
98618
98636
|
/** Show a session in the pane (switches the view to its conversation).
|
|
98619
98637
|
* Only works while the app is on screen: call it from a click handler. */
|
|
@@ -99062,6 +99080,8 @@ function getHeadlessToolHandler(appId, workspace = "") {
|
|
|
99062
99080
|
onTurnCompleted: () => {
|
|
99063
99081
|
},
|
|
99064
99082
|
onTurnDelta: () => {
|
|
99083
|
+
},
|
|
99084
|
+
onBackgroundTasks: () => {
|
|
99065
99085
|
}
|
|
99066
99086
|
};
|
|
99067
99087
|
const sandbox = {
|
|
@@ -99572,7 +99592,8 @@ async function registerAppRoutes(fastify, opts) {
|
|
|
99572
99592
|
if (!APP_ID_RE.test(id)) return reply.code(400).send({ error: "Invalid app id" });
|
|
99573
99593
|
if (!readManifest(id)) return reply.code(404).send({ error: "App not found" });
|
|
99574
99594
|
const rows = getDb().prepare("SELECT * FROM sessions WHERE origin_app_id = ? ORDER BY created_at DESC").all(id);
|
|
99575
|
-
|
|
99595
|
+
const tasks = listAllBackgroundTasks();
|
|
99596
|
+
return rows.map((row) => ({ ...row, background_tasks: tasks[row.id] ?? [] }));
|
|
99576
99597
|
});
|
|
99577
99598
|
fastify.post(
|
|
99578
99599
|
"/api/apps/:id/edit-session",
|
|
@@ -99748,6 +99769,329 @@ async function registerSidecarRoutes(fastify) {
|
|
|
99748
99769
|
);
|
|
99749
99770
|
}
|
|
99750
99771
|
|
|
99772
|
+
// src/usage/usage-service.ts
|
|
99773
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
99774
|
+
import { homedir as homedir3 } from "node:os";
|
|
99775
|
+
import { join as join3 } from "node:path";
|
|
99776
|
+
|
|
99777
|
+
// src/usage/usage-pricing.ts
|
|
99778
|
+
var PRICES = {
|
|
99779
|
+
// --- Z.AI GLM (cache writes are currently listed free) ---
|
|
99780
|
+
"glm-5.3-flashx": { input: 0.37, cachedInput: 0.075, cacheWrite: 0, output: 1.25 },
|
|
99781
|
+
"glm-5.3-flash": { input: 0.15, cachedInput: 0.03, cacheWrite: 0, output: 0.5 },
|
|
99782
|
+
"glm-5.3": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
|
|
99783
|
+
"glm-5.2": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
|
|
99784
|
+
"glm-5.1": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
|
|
99785
|
+
"glm-5": { input: 1, cachedInput: 0.2, cacheWrite: 0, output: 3.2 },
|
|
99786
|
+
"glm-4.7-flashx": { input: 0.07, cachedInput: 0.01, cacheWrite: 0, output: 0.4 },
|
|
99787
|
+
"glm-4.7": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
|
|
99788
|
+
"glm-4.6": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
|
|
99789
|
+
"glm-4.5-air": { input: 0.2, cachedInput: 0.03, cacheWrite: 0, output: 1.1 },
|
|
99790
|
+
"glm-4.5": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
|
|
99791
|
+
// --- OpenAI (no separate cache-write price; cached input only) ---
|
|
99792
|
+
"gpt-5.2-codex": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
|
|
99793
|
+
"gpt-5.3-codex": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
|
|
99794
|
+
"gpt-5.1-codex": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
|
|
99795
|
+
"gpt-5.2": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
|
|
99796
|
+
"gpt-5.1": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
|
|
99797
|
+
"gpt-5-mini": { input: 0.25, cachedInput: 0.025, cacheWrite: 0.25, output: 2 },
|
|
99798
|
+
"gpt-5-nano": { input: 0.05, cachedInput: 5e-3, cacheWrite: 0.05, output: 0.4 },
|
|
99799
|
+
"gpt-5": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
|
|
99800
|
+
"gpt-4.1-mini": { input: 0.4, cachedInput: 0.1, cacheWrite: 0.4, output: 1.6 },
|
|
99801
|
+
"gpt-4.1": { input: 2, cachedInput: 0.5, cacheWrite: 2, output: 8 },
|
|
99802
|
+
"gpt-4o-mini": { input: 0.15, cachedInput: 0.075, cacheWrite: 0.15, output: 0.6 },
|
|
99803
|
+
"gpt-4o": { input: 2.5, cachedInput: 1.25, cacheWrite: 2.5, output: 10 },
|
|
99804
|
+
// --- Anthropic Claude (5m cache writes; reads at 0.1x base) ---
|
|
99805
|
+
"claude-opus-5-5": { input: 4, cachedInput: 0.2, cacheWrite: 5, output: 20 },
|
|
99806
|
+
"claude-opus-4-5": { input: 5, cachedInput: 0.5, cacheWrite: 6.25, output: 25 },
|
|
99807
|
+
"claude-opus-4": { input: 15, cachedInput: 1.5, cacheWrite: 18.75, output: 75 },
|
|
99808
|
+
"claude-sonnet-5-5": { input: 2, cachedInput: 0.1, cacheWrite: 2.5, output: 10 },
|
|
99809
|
+
"claude-sonnet-5": { input: 2, cachedInput: 0.2, cacheWrite: 2.5, output: 10 },
|
|
99810
|
+
"claude-sonnet-4-5": { input: 3, cachedInput: 0.3, cacheWrite: 3.75, output: 15 },
|
|
99811
|
+
"claude-sonnet-4": { input: 3, cachedInput: 0.3, cacheWrite: 3.75, output: 15 },
|
|
99812
|
+
"claude-haiku-5-5": { input: 0.1, cachedInput: 0.01, cacheWrite: 0.125, output: 0.5 },
|
|
99813
|
+
"claude-haiku-4-5": { input: 1, cachedInput: 0.1, cacheWrite: 1.25, output: 5 }
|
|
99814
|
+
};
|
|
99815
|
+
var SORTED_KEYS = Object.keys(PRICES).sort((a, b) => b.length - a.length);
|
|
99816
|
+
function normalizeModelId(modelId) {
|
|
99817
|
+
const lastSegment = modelId.toLowerCase().split("/").pop() ?? "";
|
|
99818
|
+
const withoutTag = lastSegment.split(":")[0];
|
|
99819
|
+
return withoutTag.replace(/-(\d{8}|\d{4}-\d{2}-\d{2})$/, "");
|
|
99820
|
+
}
|
|
99821
|
+
function findModelPricing(modelId) {
|
|
99822
|
+
const normalized = normalizeModelId(modelId);
|
|
99823
|
+
for (const key of SORTED_KEYS) {
|
|
99824
|
+
if (normalized === key || normalized.startsWith(`${key}-`)) return PRICES[key];
|
|
99825
|
+
}
|
|
99826
|
+
return null;
|
|
99827
|
+
}
|
|
99828
|
+
function computeCost(modelId, usage, inputIncludesCached) {
|
|
99829
|
+
const pricing = findModelPricing(modelId);
|
|
99830
|
+
if (!pricing) return null;
|
|
99831
|
+
const m = 1e6;
|
|
99832
|
+
const { inputTokens, cachedInputTokens, cacheWriteInputTokens, outputTokens } = usage;
|
|
99833
|
+
const uncached = inputIncludesCached ? Math.max(0, inputTokens - cachedInputTokens - cacheWriteInputTokens) : inputTokens;
|
|
99834
|
+
return (uncached * pricing.input + cachedInputTokens * pricing.cachedInput + cacheWriteInputTokens * pricing.cacheWrite + outputTokens * pricing.output) / m;
|
|
99835
|
+
}
|
|
99836
|
+
|
|
99837
|
+
// src/usage/usage-service.ts
|
|
99838
|
+
function usageFilesDir() {
|
|
99839
|
+
return process.env.AGENT_PANE_USAGE_DIR ?? join3(homedir3(), ".repoburg", "usage");
|
|
99840
|
+
}
|
|
99841
|
+
function emptyBucket() {
|
|
99842
|
+
return { calls: 0, errors: 0, input: 0, cached: 0, cacheWrite: 0, output: 0, cost: 0 };
|
|
99843
|
+
}
|
|
99844
|
+
function newAggregator() {
|
|
99845
|
+
return {
|
|
99846
|
+
totals: emptyBucket(),
|
|
99847
|
+
unpricedModels: /* @__PURE__ */ new Set(),
|
|
99848
|
+
byRuntime: /* @__PURE__ */ new Map(),
|
|
99849
|
+
byModel: /* @__PURE__ */ new Map(),
|
|
99850
|
+
byDay: /* @__PURE__ */ new Map()
|
|
99851
|
+
};
|
|
99852
|
+
}
|
|
99853
|
+
var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
99854
|
+
function addEvent(agg, event) {
|
|
99855
|
+
const { runtimeType, provider, model, effort, day, isError, usage, inputIncludesCached } = event;
|
|
99856
|
+
const cost = usage ? computeCost(model, usage, inputIncludesCached) : null;
|
|
99857
|
+
if (usage && cost === null) agg.unpricedModels.add(model);
|
|
99858
|
+
const bump = (b) => {
|
|
99859
|
+
b.calls += 1;
|
|
99860
|
+
if (isError) b.errors += 1;
|
|
99861
|
+
if (usage) {
|
|
99862
|
+
b.input += usage.inputTokens;
|
|
99863
|
+
b.cached += usage.cachedInputTokens;
|
|
99864
|
+
b.cacheWrite += usage.cacheWriteInputTokens;
|
|
99865
|
+
b.output += usage.outputTokens;
|
|
99866
|
+
b.cost += cost ?? 0;
|
|
99867
|
+
}
|
|
99868
|
+
};
|
|
99869
|
+
bump(agg.totals);
|
|
99870
|
+
const runtimeBucket = agg.byRuntime.get(runtimeType) ?? emptyBucket();
|
|
99871
|
+
bump(runtimeBucket);
|
|
99872
|
+
agg.byRuntime.set(runtimeType, runtimeBucket);
|
|
99873
|
+
const dayBucket = agg.byDay.get(day) ?? emptyBucket();
|
|
99874
|
+
bump(dayBucket);
|
|
99875
|
+
agg.byDay.set(day, dayBucket);
|
|
99876
|
+
const key = `${runtimeType}|${provider ?? ""}|${model}|${effort ?? ""}`;
|
|
99877
|
+
const row = agg.byModel.get(key);
|
|
99878
|
+
if (row) {
|
|
99879
|
+
row.calls += 1;
|
|
99880
|
+
if (isError) row.errors += 1;
|
|
99881
|
+
if (usage) {
|
|
99882
|
+
row.input_tokens += usage.inputTokens;
|
|
99883
|
+
row.cached_input_tokens += usage.cachedInputTokens;
|
|
99884
|
+
row.cache_write_input_tokens += usage.cacheWriteInputTokens;
|
|
99885
|
+
row.output_tokens += usage.outputTokens;
|
|
99886
|
+
if (cost !== null) row.cost_usd = (row.cost_usd ?? 0) + cost;
|
|
99887
|
+
}
|
|
99888
|
+
} else {
|
|
99889
|
+
agg.byModel.set(key, {
|
|
99890
|
+
runtime_type: runtimeType,
|
|
99891
|
+
provider,
|
|
99892
|
+
model,
|
|
99893
|
+
reasoning_effort: effort,
|
|
99894
|
+
calls: 1,
|
|
99895
|
+
errors: isError ? 1 : 0,
|
|
99896
|
+
input_tokens: usage?.inputTokens ?? 0,
|
|
99897
|
+
cached_input_tokens: usage?.cachedInputTokens ?? 0,
|
|
99898
|
+
cache_write_input_tokens: usage?.cacheWriteInputTokens ?? 0,
|
|
99899
|
+
output_tokens: usage?.outputTokens ?? 0,
|
|
99900
|
+
cost_usd: cost,
|
|
99901
|
+
priced: cost !== null
|
|
99902
|
+
});
|
|
99903
|
+
}
|
|
99904
|
+
}
|
|
99905
|
+
function parseTokenUsage(raw) {
|
|
99906
|
+
if (!raw) return null;
|
|
99907
|
+
try {
|
|
99908
|
+
const parsed = JSON.parse(raw);
|
|
99909
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
99910
|
+
return {
|
|
99911
|
+
inputTokens: num(parsed.input_tokens),
|
|
99912
|
+
cachedInputTokens: num(parsed.cached_input_tokens),
|
|
99913
|
+
cacheWriteInputTokens: num(parsed.cache_write_input_tokens),
|
|
99914
|
+
outputTokens: num(parsed.output_tokens)
|
|
99915
|
+
};
|
|
99916
|
+
} catch {
|
|
99917
|
+
return null;
|
|
99918
|
+
}
|
|
99919
|
+
}
|
|
99920
|
+
function addPaneTurns(agg, sinceIso, untilIso) {
|
|
99921
|
+
const params = [];
|
|
99922
|
+
let where = "s.runtime_type IN ('claude','codex') AND t.status IN ('completed','failed','aborted')";
|
|
99923
|
+
if (sinceIso) {
|
|
99924
|
+
params.push(sinceIso);
|
|
99925
|
+
where += " AND t.created_at >= ?";
|
|
99926
|
+
}
|
|
99927
|
+
if (untilIso) {
|
|
99928
|
+
params.push(untilIso);
|
|
99929
|
+
where += " AND t.created_at < ?";
|
|
99930
|
+
}
|
|
99931
|
+
const rows = getDb().prepare(
|
|
99932
|
+
`SELECT s.runtime_type, s.model, s.model_reasoning_effort, t.token_usage, t.status, t.created_at
|
|
99933
|
+
FROM turns t JOIN sessions s ON s.id = t.session_id WHERE ${where}`
|
|
99934
|
+
).all(...params);
|
|
99935
|
+
for (const row of rows) {
|
|
99936
|
+
const day = row.created_at.slice(0, 10);
|
|
99937
|
+
addEvent(agg, {
|
|
99938
|
+
runtimeType: row.runtime_type,
|
|
99939
|
+
provider: null,
|
|
99940
|
+
model: row.model ?? "(default)",
|
|
99941
|
+
effort: row.model_reasoning_effort ?? null,
|
|
99942
|
+
day,
|
|
99943
|
+
isError: row.status === "failed",
|
|
99944
|
+
usage: parseTokenUsage(row.token_usage),
|
|
99945
|
+
// Anthropic reports input/cache-read/cache-write as disjoint buckets.
|
|
99946
|
+
inputIncludesCached: row.runtime_type !== "claude"
|
|
99947
|
+
});
|
|
99948
|
+
}
|
|
99949
|
+
}
|
|
99950
|
+
function addRepoburgExport(agg, sinceIso, untilIso) {
|
|
99951
|
+
let files;
|
|
99952
|
+
try {
|
|
99953
|
+
files = readdirSync2(usageFilesDir()).filter((f) => /^usage-\d{4}-\d{2}-\d{2}\.jsonl$/.test(f)).sort();
|
|
99954
|
+
} catch {
|
|
99955
|
+
return;
|
|
99956
|
+
}
|
|
99957
|
+
const sinceDay = sinceIso?.slice(0, 10) ?? null;
|
|
99958
|
+
const untilDay = untilIso ? untilIso.slice(0, 10) : null;
|
|
99959
|
+
for (const file of files) {
|
|
99960
|
+
const day = file.slice("usage-".length, file.length - ".jsonl".length);
|
|
99961
|
+
if (sinceDay && day < sinceDay) continue;
|
|
99962
|
+
if (untilDay && day > untilDay) continue;
|
|
99963
|
+
let content;
|
|
99964
|
+
try {
|
|
99965
|
+
content = readFileSync2(join3(usageFilesDir(), file), "utf-8");
|
|
99966
|
+
} catch {
|
|
99967
|
+
continue;
|
|
99968
|
+
}
|
|
99969
|
+
for (const line of content.split("\n")) {
|
|
99970
|
+
const trimmed = line.trim();
|
|
99971
|
+
if (!trimmed) continue;
|
|
99972
|
+
let record;
|
|
99973
|
+
try {
|
|
99974
|
+
record = JSON.parse(trimmed);
|
|
99975
|
+
} catch {
|
|
99976
|
+
continue;
|
|
99977
|
+
}
|
|
99978
|
+
if (sinceIso && record.ts < sinceIso) continue;
|
|
99979
|
+
if (untilIso && record.ts >= untilIso) continue;
|
|
99980
|
+
const status = record.status_code;
|
|
99981
|
+
addEvent(agg, {
|
|
99982
|
+
runtimeType: "repoburg",
|
|
99983
|
+
provider: record.provider ?? null,
|
|
99984
|
+
model: record.model_id ?? "(unknown)",
|
|
99985
|
+
effort: record.reasoning_effort ?? null,
|
|
99986
|
+
day: record.ts.slice(0, 10),
|
|
99987
|
+
isError: status === null || status < 200 || status >= 300,
|
|
99988
|
+
usage: {
|
|
99989
|
+
inputTokens: num(record.input_tokens),
|
|
99990
|
+
cachedInputTokens: num(record.cached_tokens),
|
|
99991
|
+
cacheWriteInputTokens: 0,
|
|
99992
|
+
outputTokens: num(record.output_tokens)
|
|
99993
|
+
},
|
|
99994
|
+
// OpenAI-compatible providers report cached tokens inside input.
|
|
99995
|
+
inputIncludesCached: true
|
|
99996
|
+
});
|
|
99997
|
+
}
|
|
99998
|
+
}
|
|
99999
|
+
}
|
|
100000
|
+
function getUsageSummary(sinceIso, untilIso) {
|
|
100001
|
+
const agg = newAggregator();
|
|
100002
|
+
addPaneTurns(agg, sinceIso, untilIso);
|
|
100003
|
+
addRepoburgExport(agg, sinceIso, untilIso);
|
|
100004
|
+
const byRuntime = [...agg.byRuntime.entries()].map(([runtimeType, b]) => ({
|
|
100005
|
+
runtime_type: runtimeType,
|
|
100006
|
+
calls: b.calls,
|
|
100007
|
+
errors: b.errors,
|
|
100008
|
+
input_tokens: b.input,
|
|
100009
|
+
cached_input_tokens: b.cached,
|
|
100010
|
+
cache_write_input_tokens: b.cacheWrite,
|
|
100011
|
+
output_tokens: b.output,
|
|
100012
|
+
cost_usd: b.cost
|
|
100013
|
+
})).sort((a, b) => a.runtime_type.localeCompare(b.runtime_type));
|
|
100014
|
+
const byModel = [...agg.byModel.values()].map((row) => ({
|
|
100015
|
+
runtime_type: row.runtime_type,
|
|
100016
|
+
provider: row.provider,
|
|
100017
|
+
model: row.model,
|
|
100018
|
+
reasoning_effort: row.reasoning_effort,
|
|
100019
|
+
calls: row.calls,
|
|
100020
|
+
errors: row.errors,
|
|
100021
|
+
input_tokens: row.input_tokens,
|
|
100022
|
+
cached_input_tokens: row.cached_input_tokens,
|
|
100023
|
+
cache_write_input_tokens: row.cache_write_input_tokens,
|
|
100024
|
+
output_tokens: row.output_tokens,
|
|
100025
|
+
// Unpriced models stay null; a priced row that also saw zero-token
|
|
100026
|
+
// error events keeps its exact sum.
|
|
100027
|
+
cost_usd: row.priced ? row.cost_usd ?? 0 : null
|
|
100028
|
+
})).sort((a, b) => (b.cost_usd ?? 0) - (a.cost_usd ?? 0) || b.calls - a.calls);
|
|
100029
|
+
const daily = [...agg.byDay.entries()].map(([date, b]) => ({
|
|
100030
|
+
date,
|
|
100031
|
+
calls: b.calls,
|
|
100032
|
+
input_tokens: b.input,
|
|
100033
|
+
cached_input_tokens: b.cached,
|
|
100034
|
+
cache_write_input_tokens: b.cacheWrite,
|
|
100035
|
+
output_tokens: b.output,
|
|
100036
|
+
cost_usd: b.cost
|
|
100037
|
+
})).sort((a, b) => a.date.localeCompare(b.date));
|
|
100038
|
+
return {
|
|
100039
|
+
window: { since: sinceIso, until: untilIso },
|
|
100040
|
+
totals: {
|
|
100041
|
+
calls: agg.totals.calls,
|
|
100042
|
+
errors: agg.totals.errors,
|
|
100043
|
+
input_tokens: agg.totals.input,
|
|
100044
|
+
cached_input_tokens: agg.totals.cached,
|
|
100045
|
+
cache_write_input_tokens: agg.totals.cacheWrite,
|
|
100046
|
+
output_tokens: agg.totals.output,
|
|
100047
|
+
total_tokens: agg.totals.input + agg.totals.cached + agg.totals.cacheWrite + agg.totals.output,
|
|
100048
|
+
cost_usd: agg.totals.cost,
|
|
100049
|
+
unpriced_models: [...agg.unpricedModels].sort()
|
|
100050
|
+
},
|
|
100051
|
+
by_runtime: byRuntime,
|
|
100052
|
+
by_model: byModel,
|
|
100053
|
+
daily
|
|
100054
|
+
};
|
|
100055
|
+
}
|
|
100056
|
+
|
|
100057
|
+
// src/routes/usage.ts
|
|
100058
|
+
function parseTimeParam(value) {
|
|
100059
|
+
if (typeof value !== "string" || value === "") return null;
|
|
100060
|
+
if (Number.isNaN(Date.parse(value))) {
|
|
100061
|
+
throw Object.assign(new Error(`Invalid timestamp: ${value}`), { statusCode: 400 });
|
|
100062
|
+
}
|
|
100063
|
+
return value;
|
|
100064
|
+
}
|
|
100065
|
+
async function registerUsageRoutes(fastify) {
|
|
100066
|
+
fastify.get(
|
|
100067
|
+
"/api/usage/summary",
|
|
100068
|
+
{
|
|
100069
|
+
schema: {
|
|
100070
|
+
querystring: {
|
|
100071
|
+
type: "object",
|
|
100072
|
+
properties: {
|
|
100073
|
+
since: { type: "string" },
|
|
100074
|
+
until: { type: "string" }
|
|
100075
|
+
}
|
|
100076
|
+
}
|
|
100077
|
+
}
|
|
100078
|
+
},
|
|
100079
|
+
async (request, reply) => {
|
|
100080
|
+
try {
|
|
100081
|
+
const since = parseTimeParam(request.query?.since);
|
|
100082
|
+
const until = parseTimeParam(request.query?.until);
|
|
100083
|
+
return getUsageSummary(since, until);
|
|
100084
|
+
} catch (err) {
|
|
100085
|
+
const e = err;
|
|
100086
|
+
if (e.statusCode === 400) {
|
|
100087
|
+
return reply.code(400).send({ error: e.message });
|
|
100088
|
+
}
|
|
100089
|
+
throw err;
|
|
100090
|
+
}
|
|
100091
|
+
}
|
|
100092
|
+
);
|
|
100093
|
+
}
|
|
100094
|
+
|
|
99751
100095
|
// src/codex/item-mapper.ts
|
|
99752
100096
|
function mapItemData(item) {
|
|
99753
100097
|
switch (item.type) {
|
|
@@ -100512,9 +100856,9 @@ var codexProvider = {
|
|
|
100512
100856
|
|
|
100513
100857
|
// src/claude/claude-provider.ts
|
|
100514
100858
|
import { query, forkSession as sdkForkSession } from "@anthropic-ai/claude-agent-sdk";
|
|
100515
|
-
import { readFileSync as
|
|
100859
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
100516
100860
|
import { tmpdir } from "os";
|
|
100517
|
-
import { join as
|
|
100861
|
+
import { join as join4 } from "path";
|
|
100518
100862
|
|
|
100519
100863
|
// src/claude/claude-message-mapper.ts
|
|
100520
100864
|
function mapAssistantContent(content, messageId, thinkingTexts) {
|
|
@@ -101034,7 +101378,8 @@ function handleLoopError(entry, sessionId, errMsg, db2) {
|
|
|
101034
101378
|
turn_id: row.turn_id,
|
|
101035
101379
|
external_item_id: row.external_item_id,
|
|
101036
101380
|
type: row.type,
|
|
101037
|
-
|
|
101381
|
+
// MUH-25 — re-broadcasts ship trimmed payloads too.
|
|
101382
|
+
data: row.data ? trimItemData(JSON.parse(row.data)) : {},
|
|
101038
101383
|
status: "failed",
|
|
101039
101384
|
created_at: row.created_at,
|
|
101040
101385
|
updated_at: now
|
|
@@ -101455,7 +101800,7 @@ function constructMonitorOutputPath(entry, taskId) {
|
|
|
101455
101800
|
if (!entry.sessionId) return "";
|
|
101456
101801
|
const uid = typeof process.getuid === "function" ? process.getuid() : 0;
|
|
101457
101802
|
const encodedCwd = entry.cwd.replace(/\//g, "-");
|
|
101458
|
-
return
|
|
101803
|
+
return join4(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
|
|
101459
101804
|
}
|
|
101460
101805
|
function handleTaskStarted(message, sessionId, turnId, entry, db2) {
|
|
101461
101806
|
const m = message;
|
|
@@ -101498,7 +101843,7 @@ function handleTaskProgress(message, sessionId, turnId, entry, db2) {
|
|
|
101498
101843
|
const outputPath = existing.output_file || constructMonitorOutputPath(entry, m.task_id);
|
|
101499
101844
|
if (outputPath) {
|
|
101500
101845
|
try {
|
|
101501
|
-
output =
|
|
101846
|
+
output = readFileSync3(outputPath, "utf-8");
|
|
101502
101847
|
} catch {
|
|
101503
101848
|
}
|
|
101504
101849
|
}
|
|
@@ -101547,13 +101892,11 @@ function handleTaskNotification(message, sessionId, turnId, entry, db2) {
|
|
|
101547
101892
|
if (!row) return;
|
|
101548
101893
|
const existing = row.data ? JSON.parse(row.data) : {};
|
|
101549
101894
|
const taskType = existing.task_type ?? "unknown";
|
|
101550
|
-
const
|
|
101551
|
-
const constructedPath = taskType === "local_bash" ? constructMonitorOutputPath(entry, m.task_id) : "";
|
|
101552
|
-
const outputPath = sdkOutputFile || constructedPath;
|
|
101895
|
+
const outputPath = taskType === "local_bash" ? m.output_file || constructMonitorOutputPath(entry, m.task_id) : null;
|
|
101553
101896
|
let output = "";
|
|
101554
101897
|
if (outputPath) {
|
|
101555
101898
|
try {
|
|
101556
|
-
output =
|
|
101899
|
+
output = readFileSync3(outputPath, "utf-8");
|
|
101557
101900
|
} catch {
|
|
101558
101901
|
}
|
|
101559
101902
|
}
|
|
@@ -101561,7 +101904,7 @@ function handleTaskNotification(message, sessionId, turnId, entry, db2) {
|
|
|
101561
101904
|
...existing,
|
|
101562
101905
|
status: m.status,
|
|
101563
101906
|
summary: m.summary,
|
|
101564
|
-
output_file: outputPath,
|
|
101907
|
+
output_file: m.output_file || outputPath || existing.output_file || null,
|
|
101565
101908
|
output,
|
|
101566
101909
|
token_count: m.usage?.total_tokens ?? existing.token_count ?? null
|
|
101567
101910
|
};
|
|
@@ -101632,7 +101975,8 @@ function completeTurn(db2, sessionId, turnId, usage) {
|
|
|
101632
101975
|
}
|
|
101633
101976
|
function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
|
|
101634
101977
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
101635
|
-
const
|
|
101978
|
+
const data = trimItemData(desc.data);
|
|
101979
|
+
const result = db2.prepare("UPDATE items SET data = ?, status = ?, updated_at = ? WHERE external_item_id = ? AND turn_id = ?").run(JSON.stringify(data), status, now, desc.externalId, turnId);
|
|
101636
101980
|
let itemId;
|
|
101637
101981
|
let createdAt;
|
|
101638
101982
|
if (result.changes === 0) {
|
|
@@ -101640,7 +101984,7 @@ function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
|
|
|
101640
101984
|
createdAt = now;
|
|
101641
101985
|
db2.prepare(
|
|
101642
101986
|
"INSERT INTO items (id, turn_id, external_item_id, type, data, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
|
101643
|
-
).run(itemId, turnId, desc.externalId, desc.type, JSON.stringify(
|
|
101987
|
+
).run(itemId, turnId, desc.externalId, desc.type, JSON.stringify(data), status, now, now);
|
|
101644
101988
|
} else {
|
|
101645
101989
|
const row = db2.prepare("SELECT id, created_at FROM items WHERE external_item_id = ? AND turn_id = ?").get(desc.externalId, turnId);
|
|
101646
101990
|
itemId = row.id;
|
|
@@ -101651,7 +101995,7 @@ function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
|
|
|
101651
101995
|
turn_id: turnId,
|
|
101652
101996
|
external_item_id: desc.externalId,
|
|
101653
101997
|
type: desc.type,
|
|
101654
|
-
data
|
|
101998
|
+
data,
|
|
101655
101999
|
status,
|
|
101656
102000
|
created_at: createdAt,
|
|
101657
102001
|
updated_at: now
|
|
@@ -103638,6 +103982,7 @@ async function createAgentPaneApp(dbPath) {
|
|
|
103638
103982
|
await registerVscodeWebRoutes(fastify);
|
|
103639
103983
|
await registerAppRoutes(fastify);
|
|
103640
103984
|
await registerSidecarRoutes(fastify);
|
|
103985
|
+
await registerUsageRoutes(fastify);
|
|
103641
103986
|
const wss2 = initWs();
|
|
103642
103987
|
wss2.on("connection", (ws) => {
|
|
103643
103988
|
ws.send(JSON.stringify({ event: "background_tasks:snapshot", data: { sessions: listAllBackgroundTasks() } }));
|