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.
Files changed (38) hide show
  1. package/agent-pane/backend/dist/index.js +424 -79
  2. package/agent-pane/backend/dist/server.js +424 -79
  3. package/agent-pane/frontend/dist/assets/{index-DlwZnsU3.css → index-BKDM-AC5.css} +1 -1
  4. package/agent-pane/frontend/dist/assets/index-BNyA-dQb.js +617 -0
  5. package/agent-pane/frontend/dist/index.html +2 -2
  6. package/backend/dist/src/core-entities/llm-call-log.entity.d.ts +2 -0
  7. package/backend/dist/src/core-entities/llm-call-log.entity.js +11 -0
  8. package/backend/dist/src/core-entities/llm-call-log.entity.js.map +1 -1
  9. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.d.ts +2 -0
  10. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js +6 -0
  11. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js.map +1 -1
  12. package/backend/dist/src/llm-call-logs/llm-call-logs.module.js +2 -1
  13. package/backend/dist/src/llm-call-logs/llm-call-logs.module.js.map +1 -1
  14. package/backend/dist/src/llm-call-logs/llm-call-logs.service.d.ts +3 -1
  15. package/backend/dist/src/llm-call-logs/llm-call-logs.service.js +8 -2
  16. package/backend/dist/src/llm-call-logs/llm-call-logs.service.js.map +1 -1
  17. package/backend/dist/src/llm-provider/alibaba-llm.provider.js +1 -0
  18. package/backend/dist/src/llm-provider/alibaba-llm.provider.js.map +1 -1
  19. package/backend/dist/src/llm-provider/ollama-llm.provider.js +1 -0
  20. package/backend/dist/src/llm-provider/ollama-llm.provider.js.map +1 -1
  21. package/backend/dist/src/llm-provider/openai-llm.provider.js +1 -0
  22. package/backend/dist/src/llm-provider/openai-llm.provider.js.map +1 -1
  23. package/backend/dist/src/llm-provider/openrouter-llm.provider.js +1 -0
  24. package/backend/dist/src/llm-provider/openrouter-llm.provider.js.map +1 -1
  25. package/backend/dist/src/llm-provider/zai-llm.provider.js +1 -0
  26. package/backend/dist/src/llm-provider/zai-llm.provider.js.map +1 -1
  27. package/backend/dist/src/usage-export/usage-export.module.d.ts +2 -0
  28. package/backend/dist/src/usage-export/usage-export.module.js +21 -0
  29. package/backend/dist/src/usage-export/usage-export.module.js.map +1 -0
  30. package/backend/dist/src/usage-export/usage-export.service.d.ts +6 -0
  31. package/backend/dist/src/usage-export/usage-export.service.js +54 -0
  32. package/backend/dist/src/usage-export/usage-export.service.js.map +1 -0
  33. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  34. package/package.json +1 -1
  35. package/tabtape/extension/dist/build-info.json +3 -3
  36. package/tabtape/extension/dist/manifest.json +1 -1
  37. package/tabtape/ui/dist/build-info.json +3 -3
  38. package/agent-pane/frontend/dist/assets/index-WRsdlJfD.js +0 -606
@@ -7850,7 +7850,7 @@ var require_thread_stream = __commonJS({
7850
7850
  var { version } = require_package();
7851
7851
  var { EventEmitter: EventEmitter2 } = __require("events");
7852
7852
  var { Worker } = __require("worker_threads");
7853
- var { join: join4 } = __require("path");
7853
+ var { join: join5 } = __require("path");
7854
7854
  var { pathToFileURL } = __require("url");
7855
7855
  var { wait } = require_wait();
7856
7856
  var {
@@ -7901,7 +7901,7 @@ var require_thread_stream = __commonJS({
7901
7901
  function createWorker(stream, opts) {
7902
7902
  const { filename, workerData } = opts;
7903
7903
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
7904
- const toExecute = bundlerOverrides["thread-stream-worker"] || join4(__dirname, "lib", "worker.js");
7904
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join5(__dirname, "lib", "worker.js");
7905
7905
  const worker = new Worker(toExecute, {
7906
7906
  ...opts.workerOpts,
7907
7907
  name: opts.workerOpts?.name || "thread-stream",
@@ -8369,7 +8369,7 @@ var require_transport = __commonJS({
8369
8369
  var { createRequire } = __require("module");
8370
8370
  var { existsSync: existsSync3 } = __require("node:fs");
8371
8371
  var getCallers = require_caller();
8372
- var { join: join4, isAbsolute, sep } = __require("node:path");
8372
+ var { join: join5, isAbsolute, sep } = __require("node:path");
8373
8373
  var { fileURLToPath: fileURLToPath3 } = __require("node:url");
8374
8374
  var sleep = require_atomic_sleep();
8375
8375
  var onExit = require_on_exit_leak_free();
@@ -8522,7 +8522,7 @@ var require_transport = __commonJS({
8522
8522
  throw new Error("only one of target or targets can be specified");
8523
8523
  }
8524
8524
  if (targets) {
8525
- target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8525
+ target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
8526
8526
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
8527
8527
  return {
8528
8528
  ...dest,
@@ -8540,7 +8540,7 @@ var require_transport = __commonJS({
8540
8540
  });
8541
8541
  });
8542
8542
  } else if (pipeline) {
8543
- target = bundlerOverrides["pino-worker"] || join4(__dirname, "worker.js");
8543
+ target = bundlerOverrides["pino-worker"] || join5(__dirname, "worker.js");
8544
8544
  options.pipelines = [pipeline.map((dest) => {
8545
8545
  return {
8546
8546
  ...dest,
@@ -8563,7 +8563,7 @@ var require_transport = __commonJS({
8563
8563
  return origin;
8564
8564
  }
8565
8565
  if (origin === "pino/file") {
8566
- return join4(__dirname, "..", "file.js");
8566
+ return join5(__dirname, "..", "file.js");
8567
8567
  }
8568
8568
  let fixTarget2;
8569
8569
  for (const filePath of callers) {
@@ -8678,14 +8678,14 @@ var require_tools = __commonJS({
8678
8678
  }
8679
8679
  return point < 32 ? JSON.stringify(str) : '"' + result + '"';
8680
8680
  }
8681
- function asJson(obj, msg, num, time) {
8681
+ function asJson(obj, msg, num2, time) {
8682
8682
  if (asJsonChan.hasSubscribers === false) {
8683
- return _asJson.call(this, obj, msg, num, time);
8683
+ return _asJson.call(this, obj, msg, num2, time);
8684
8684
  }
8685
8685
  const store = { instance: this, arguments };
8686
- return asJsonChan.traceSync(_asJson, store, this, obj, msg, num, time);
8686
+ return asJsonChan.traceSync(_asJson, store, this, obj, msg, num2, time);
8687
8687
  }
8688
- function _asJson(obj, msg, num, time) {
8688
+ function _asJson(obj, msg, num2, time) {
8689
8689
  const stringify2 = this[stringifySym];
8690
8690
  const stringifySafe = this[stringifySafeSym];
8691
8691
  const stringifiers = this[stringifiersSym];
@@ -8695,7 +8695,7 @@ var require_tools = __commonJS({
8695
8695
  const formatters = this[formattersSym];
8696
8696
  const messageKey = this[messageKeySym];
8697
8697
  const errorKey = this[errorKeySym];
8698
- let data = this[lsCacheSym][num] + time;
8698
+ let data = this[lsCacheSym][num2] + time;
8699
8699
  data = data + chindings;
8700
8700
  let value;
8701
8701
  if (formatters.log) {
@@ -9320,7 +9320,7 @@ var require_proto = __commonJS({
9320
9320
  function defaultMixinMergeStrategy(mergeObject, mixinObject) {
9321
9321
  return Object.assign(mixinObject, mergeObject);
9322
9322
  }
9323
- function write(_obj, msg, num) {
9323
+ function write(_obj, msg, num2) {
9324
9324
  const t = this[timeSym]();
9325
9325
  const mixin = this[mixinSym];
9326
9326
  const errorKey = this[errorKeySym];
@@ -9342,12 +9342,12 @@ var require_proto = __commonJS({
9342
9342
  }
9343
9343
  }
9344
9344
  if (mixin) {
9345
- obj = mixinMergeStrategy(obj, mixin(obj, num, this));
9345
+ obj = mixinMergeStrategy(obj, mixin(obj, num2, this));
9346
9346
  }
9347
- const s = this[asJsonSym](obj, msg, num, t);
9347
+ const s = this[asJsonSym](obj, msg, num2, t);
9348
9348
  const stream = this[streamSym];
9349
9349
  if (stream[needsMetadataGsym] === true) {
9350
- stream.lastLevel = num;
9350
+ stream.lastLevel = num2;
9351
9351
  stream.lastObj = obj;
9352
9352
  stream.lastMsg = msg;
9353
9353
  stream.lastTime = t.slice(this[timeSliceIndexSym]);
@@ -9543,7 +9543,7 @@ var require_safe_stable_stringify = __commonJS({
9543
9543
  return circularValue;
9544
9544
  }
9545
9545
  let res = "";
9546
- let join4 = ",";
9546
+ let join5 = ",";
9547
9547
  const originalIndentation = indentation;
9548
9548
  if (Array.isArray(value)) {
9549
9549
  if (value.length === 0) {
@@ -9557,7 +9557,7 @@ var require_safe_stable_stringify = __commonJS({
9557
9557
  indentation += spacer;
9558
9558
  res += `
9559
9559
  ${indentation}`;
9560
- join4 = `,
9560
+ join5 = `,
9561
9561
  ${indentation}`;
9562
9562
  }
9563
9563
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9565,13 +9565,13 @@ ${indentation}`;
9565
9565
  for (; i < maximumValuesToStringify - 1; i++) {
9566
9566
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9567
9567
  res += tmp2 !== void 0 ? tmp2 : "null";
9568
- res += join4;
9568
+ res += join5;
9569
9569
  }
9570
9570
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
9571
9571
  res += tmp !== void 0 ? tmp : "null";
9572
9572
  if (value.length - 1 > maximumBreadth) {
9573
9573
  const removedKeys = value.length - maximumBreadth - 1;
9574
- res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9574
+ res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9575
9575
  }
9576
9576
  if (spacer !== "") {
9577
9577
  res += `
@@ -9592,7 +9592,7 @@ ${originalIndentation}`;
9592
9592
  let separator = "";
9593
9593
  if (spacer !== "") {
9594
9594
  indentation += spacer;
9595
- join4 = `,
9595
+ join5 = `,
9596
9596
  ${indentation}`;
9597
9597
  whitespace = " ";
9598
9598
  }
@@ -9606,13 +9606,13 @@ ${indentation}`;
9606
9606
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
9607
9607
  if (tmp !== void 0) {
9608
9608
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9609
- separator = join4;
9609
+ separator = join5;
9610
9610
  }
9611
9611
  }
9612
9612
  if (keyLength > maximumBreadth) {
9613
9613
  const removedKeys = keyLength - maximumBreadth;
9614
9614
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
9615
- separator = join4;
9615
+ separator = join5;
9616
9616
  }
9617
9617
  if (spacer !== "" && separator.length > 1) {
9618
9618
  res = `
@@ -9653,7 +9653,7 @@ ${originalIndentation}`;
9653
9653
  }
9654
9654
  const originalIndentation = indentation;
9655
9655
  let res = "";
9656
- let join4 = ",";
9656
+ let join5 = ",";
9657
9657
  if (Array.isArray(value)) {
9658
9658
  if (value.length === 0) {
9659
9659
  return "[]";
@@ -9666,7 +9666,7 @@ ${originalIndentation}`;
9666
9666
  indentation += spacer;
9667
9667
  res += `
9668
9668
  ${indentation}`;
9669
- join4 = `,
9669
+ join5 = `,
9670
9670
  ${indentation}`;
9671
9671
  }
9672
9672
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -9674,13 +9674,13 @@ ${indentation}`;
9674
9674
  for (; i < maximumValuesToStringify - 1; i++) {
9675
9675
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9676
9676
  res += tmp2 !== void 0 ? tmp2 : "null";
9677
- res += join4;
9677
+ res += join5;
9678
9678
  }
9679
9679
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
9680
9680
  res += tmp !== void 0 ? tmp : "null";
9681
9681
  if (value.length - 1 > maximumBreadth) {
9682
9682
  const removedKeys = value.length - maximumBreadth - 1;
9683
- res += `${join4}"... ${getItemCount(removedKeys)} not stringified"`;
9683
+ res += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9684
9684
  }
9685
9685
  if (spacer !== "") {
9686
9686
  res += `
@@ -9693,7 +9693,7 @@ ${originalIndentation}`;
9693
9693
  let whitespace = "";
9694
9694
  if (spacer !== "") {
9695
9695
  indentation += spacer;
9696
- join4 = `,
9696
+ join5 = `,
9697
9697
  ${indentation}`;
9698
9698
  whitespace = " ";
9699
9699
  }
@@ -9702,7 +9702,7 @@ ${indentation}`;
9702
9702
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
9703
9703
  if (tmp !== void 0) {
9704
9704
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
9705
- separator = join4;
9705
+ separator = join5;
9706
9706
  }
9707
9707
  }
9708
9708
  if (spacer !== "" && separator.length > 1) {
@@ -9760,20 +9760,20 @@ ${originalIndentation}`;
9760
9760
  indentation += spacer;
9761
9761
  let res2 = `
9762
9762
  ${indentation}`;
9763
- const join5 = `,
9763
+ const join6 = `,
9764
9764
  ${indentation}`;
9765
9765
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
9766
9766
  let i = 0;
9767
9767
  for (; i < maximumValuesToStringify - 1; i++) {
9768
9768
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9769
9769
  res2 += tmp2 !== void 0 ? tmp2 : "null";
9770
- res2 += join5;
9770
+ res2 += join6;
9771
9771
  }
9772
9772
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
9773
9773
  res2 += tmp !== void 0 ? tmp : "null";
9774
9774
  if (value.length - 1 > maximumBreadth) {
9775
9775
  const removedKeys = value.length - maximumBreadth - 1;
9776
- res2 += `${join5}"... ${getItemCount(removedKeys)} not stringified"`;
9776
+ res2 += `${join6}"... ${getItemCount(removedKeys)} not stringified"`;
9777
9777
  }
9778
9778
  res2 += `
9779
9779
  ${originalIndentation}`;
@@ -9789,16 +9789,16 @@ ${originalIndentation}`;
9789
9789
  return '"[Object]"';
9790
9790
  }
9791
9791
  indentation += spacer;
9792
- const join4 = `,
9792
+ const join5 = `,
9793
9793
  ${indentation}`;
9794
9794
  let res = "";
9795
9795
  let separator = "";
9796
9796
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
9797
9797
  if (isTypedArrayWithEntries(value)) {
9798
- res += stringifyTypedArray(value, join4, maximumBreadth);
9798
+ res += stringifyTypedArray(value, join5, maximumBreadth);
9799
9799
  keys = keys.slice(value.length);
9800
9800
  maximumPropertiesToStringify -= value.length;
9801
- separator = join4;
9801
+ separator = join5;
9802
9802
  }
9803
9803
  if (deterministic) {
9804
9804
  keys = sort(keys, comparator);
@@ -9809,13 +9809,13 @@ ${indentation}`;
9809
9809
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
9810
9810
  if (tmp !== void 0) {
9811
9811
  res += `${separator}${strEscape(key2)}: ${tmp}`;
9812
- separator = join4;
9812
+ separator = join5;
9813
9813
  }
9814
9814
  }
9815
9815
  if (keyLength > maximumBreadth) {
9816
9816
  const removedKeys = keyLength - maximumBreadth;
9817
9817
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
9818
- separator = join4;
9818
+ separator = join5;
9819
9819
  }
9820
9820
  if (separator !== "") {
9821
9821
  res = `
@@ -10709,13 +10709,13 @@ var require_serializer = __commonJS({
10709
10709
  return "" + integer;
10710
10710
  }
10711
10711
  asNumber(i) {
10712
- const num = Number(i);
10713
- if (num !== num) {
10712
+ const num2 = Number(i);
10713
+ if (num2 !== num2) {
10714
10714
  throw new Error(`The value "${i}" cannot be converted to a number.`);
10715
- } else if (num === Infinity || num === -Infinity) {
10715
+ } else if (num2 === Infinity || num2 === -Infinity) {
10716
10716
  return "null";
10717
10717
  } else {
10718
- return "" + num;
10718
+ return "" + num2;
10719
10719
  }
10720
10720
  }
10721
10721
  asBoolean(bool) {
@@ -28126,9 +28126,9 @@ var require_semver = __commonJS({
28126
28126
  } else {
28127
28127
  this.prerelease = m[4].split(".").map((id) => {
28128
28128
  if (/^[0-9]+$/.test(id)) {
28129
- const num = +id;
28130
- if (num >= 0 && num < MAX_SAFE_INTEGER) {
28131
- return num;
28129
+ const num2 = +id;
28130
+ if (num2 >= 0 && num2 < MAX_SAFE_INTEGER) {
28131
+ return num2;
28132
28132
  }
28133
28133
  }
28134
28134
  return id;
@@ -37665,26 +37665,26 @@ var require_permessage_deflate = __commonJS({
37665
37665
  value = value[0];
37666
37666
  if (key === "client_max_window_bits") {
37667
37667
  if (value !== true) {
37668
- const num = +value;
37669
- if (!Number.isInteger(num) || num < 8 || num > 15) {
37668
+ const num2 = +value;
37669
+ if (!Number.isInteger(num2) || num2 < 8 || num2 > 15) {
37670
37670
  throw new TypeError(
37671
37671
  `Invalid value for parameter "${key}": ${value}`
37672
37672
  );
37673
37673
  }
37674
- value = num;
37674
+ value = num2;
37675
37675
  } else if (!this._isServer) {
37676
37676
  throw new TypeError(
37677
37677
  `Invalid value for parameter "${key}": ${value}`
37678
37678
  );
37679
37679
  }
37680
37680
  } else if (key === "server_max_window_bits") {
37681
- const num = +value;
37682
- if (!Number.isInteger(num) || num < 8 || num > 15) {
37681
+ const num2 = +value;
37682
+ if (!Number.isInteger(num2) || num2 < 8 || num2 > 15) {
37683
37683
  throw new TypeError(
37684
37684
  `Invalid value for parameter "${key}": ${value}`
37685
37685
  );
37686
37686
  }
37687
- value = num;
37687
+ value = num2;
37688
37688
  } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") {
37689
37689
  if (value !== true) {
37690
37690
  throw new TypeError(
@@ -38398,8 +38398,8 @@ var require_receiver = __commonJS({
38398
38398
  return;
38399
38399
  }
38400
38400
  const buf = this.consume(8);
38401
- const num = buf.readUInt32BE(0);
38402
- if (num > Math.pow(2, 53 - 32) - 1) {
38401
+ const num2 = buf.readUInt32BE(0);
38402
+ if (num2 > Math.pow(2, 53 - 32) - 1) {
38403
38403
  const error = this.createError(
38404
38404
  RangeError,
38405
38405
  "Unsupported WebSocket frame: payload length > 2^53 - 1",
@@ -38410,7 +38410,7 @@ var require_receiver = __commonJS({
38410
38410
  cb(error);
38411
38411
  return;
38412
38412
  }
38413
- this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
38413
+ this._payloadLength = num2 * Math.pow(2, 32) + buf.readUInt32BE(4);
38414
38414
  this.haveLength(cb);
38415
38415
  }
38416
38416
  /**
@@ -41330,6 +41330,25 @@ function v4(options, buf, offset) {
41330
41330
  }
41331
41331
  var v4_default = v4;
41332
41332
 
41333
+ // src/db/item-trim.ts
41334
+ var TRIMMABLE_KEYS = ["aggregated_output", "output"];
41335
+ var MAX_ITEM_TEXT_BYTES = 64e3;
41336
+ function prunedMarker(maxBytes) {
41337
+ return `\u2026 [pruned: kept newest ${maxBytes} bytes]
41338
+ `;
41339
+ }
41340
+ function trimItemData(data, maxBytes = MAX_ITEM_TEXT_BYTES) {
41341
+ let trimmed = null;
41342
+ for (const key of TRIMMABLE_KEYS) {
41343
+ const value = data[key];
41344
+ if (typeof value === "string" && value.length > maxBytes) {
41345
+ if (!trimmed) trimmed = { ...data };
41346
+ trimmed[key] = prunedMarker(maxBytes) + value.slice(-maxBytes);
41347
+ }
41348
+ }
41349
+ return trimmed ?? data;
41350
+ }
41351
+
41333
41352
  // src/providers/registry.ts
41334
41353
  var providers = /* @__PURE__ */ new Map();
41335
41354
  function registerProvider(id, provider) {
@@ -41390,7 +41409,7 @@ async function registerSessionRoutes(fastify) {
41390
41409
  for (const row of itemRows) {
41391
41410
  const item = {
41392
41411
  ...row,
41393
- data: row.data ? JSON.parse(row.data) : null
41412
+ data: row.data ? trimItemData(JSON.parse(row.data)) : null
41394
41413
  };
41395
41414
  const list = itemsByTurn.get(item.turn_id) ?? [];
41396
41415
  list.push(item);
@@ -43415,7 +43434,6 @@ async function registerPerfLogRoutes(fastify) {
43415
43434
  }
43416
43435
 
43417
43436
  // src/routes/maintenance.ts
43418
- var TRIMMABLE_KEYS = ["aggregated_output", "output"];
43419
43437
  async function registerMaintenanceRoutes(fastify) {
43420
43438
  fastify.post(
43421
43439
  "/api/maintenance/prune-items",
@@ -43448,17 +43466,9 @@ async function registerMaintenanceRoutes(fastify) {
43448
43466
  } catch {
43449
43467
  continue;
43450
43468
  }
43451
- let changed = false;
43452
- for (const key of TRIMMABLE_KEYS) {
43453
- const v = data[key];
43454
- if (typeof v === "string" && v.length > maxBytes) {
43455
- data[key] = `\u2026 [pruned: kept newest ${maxBytes} bytes]
43456
- ` + v.slice(-maxBytes);
43457
- changed = true;
43458
- }
43459
- }
43460
- if (!changed) continue;
43461
- const next = JSON.stringify(data);
43469
+ const trimmed = trimItemData(data, maxBytes);
43470
+ if (trimmed === data) continue;
43471
+ const next = JSON.stringify(trimmed);
43462
43472
  bytesBefore += row.data.length;
43463
43473
  bytesAfter += next.length;
43464
43474
  pruned++;
@@ -98306,6 +98316,7 @@ Icons come from ONE library: Lucide (https://lucide.dev/icons, ISC).
98306
98316
  - 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
98307
98317
  - 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)
98308
98318
  - onTurnCompleted(callback) - callback(event, { turnId, response }) when a turn ends
98319
+ - 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
98309
98320
  - 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)
98310
98321
  - 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
98311
98322
  - 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)
@@ -98590,6 +98601,10 @@ interface AgentPaneCreateSessionOptions {
98590
98601
  interface AgentPaneTurnPayload { turnId?: string; response?: string | null; error?: string }
98591
98602
  interface AgentPaneDeltaPayload { sessionId?: string; turnId?: string; itemId?: string; delta?: string }
98592
98603
  interface AgentPaneToolCallPayload { callId: string; tool: string; name: string; args: Record<string, unknown> }
98604
+ /** Live background tasks of a session (Monitor shells, backgrounded subagents):
98605
+ * the CURRENT set, REPLACE semantics \u2014 an empty array means none are left. */
98606
+ interface AgentPaneBackgroundTasksPayload { sessionId?: string; tasks?: AgentPaneBackgroundTask[] }
98607
+ interface AgentPaneBackgroundTask { task_id: string; task_type: string; description: string }
98593
98608
  /** A file the app stored with uploadFile (PNG, JPEG, GIF or WebP, max 5 MB). */
98594
98609
  interface AgentPaneFile {
98595
98610
  /** Content id "<sha256>.<ext>": the same bytes always get the same id. */
@@ -98627,6 +98642,9 @@ declare const AgentPane: {
98627
98642
  onTurnDelta(cb: (payload: AgentPaneDeltaPayload) => void): void;
98628
98643
  onToolCall(cb: (payload: AgentPaneToolCallPayload) => void): void;
98629
98644
  onStateChanged(cb: (payload: unknown) => void): void;
98645
+ /** Fires when the live background-task set of one of the app's sessions
98646
+ * changes (also empty sets, when the last task ends). */
98647
+ onBackgroundTasks(cb: (payload: AgentPaneBackgroundTasksPayload | null) => void): void;
98630
98648
  resolveToolCall(callId: string, result?: unknown): Promise<{ ok: boolean }>;
98631
98649
  /** Show a session in the pane (switches the view to its conversation).
98632
98650
  * Only works while the app is on screen: call it from a click handler. */
@@ -99075,6 +99093,8 @@ function getHeadlessToolHandler(appId, workspace = "") {
99075
99093
  onTurnCompleted: () => {
99076
99094
  },
99077
99095
  onTurnDelta: () => {
99096
+ },
99097
+ onBackgroundTasks: () => {
99078
99098
  }
99079
99099
  };
99080
99100
  const sandbox = {
@@ -99585,7 +99605,8 @@ async function registerAppRoutes(fastify, opts) {
99585
99605
  if (!APP_ID_RE.test(id)) return reply.code(400).send({ error: "Invalid app id" });
99586
99606
  if (!readManifest(id)) return reply.code(404).send({ error: "App not found" });
99587
99607
  const rows = getDb().prepare("SELECT * FROM sessions WHERE origin_app_id = ? ORDER BY created_at DESC").all(id);
99588
- return rows;
99608
+ const tasks = listAllBackgroundTasks();
99609
+ return rows.map((row) => ({ ...row, background_tasks: tasks[row.id] ?? [] }));
99589
99610
  });
99590
99611
  fastify.post(
99591
99612
  "/api/apps/:id/edit-session",
@@ -99761,6 +99782,329 @@ async function registerSidecarRoutes(fastify) {
99761
99782
  );
99762
99783
  }
99763
99784
 
99785
+ // src/usage/usage-service.ts
99786
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "node:fs";
99787
+ import { homedir as homedir3 } from "node:os";
99788
+ import { join as join3 } from "node:path";
99789
+
99790
+ // src/usage/usage-pricing.ts
99791
+ var PRICES = {
99792
+ // --- Z.AI GLM (cache writes are currently listed free) ---
99793
+ "glm-5.3-flashx": { input: 0.37, cachedInput: 0.075, cacheWrite: 0, output: 1.25 },
99794
+ "glm-5.3-flash": { input: 0.15, cachedInput: 0.03, cacheWrite: 0, output: 0.5 },
99795
+ "glm-5.3": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
99796
+ "glm-5.2": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
99797
+ "glm-5.1": { input: 1.4, cachedInput: 0.26, cacheWrite: 0, output: 4.4 },
99798
+ "glm-5": { input: 1, cachedInput: 0.2, cacheWrite: 0, output: 3.2 },
99799
+ "glm-4.7-flashx": { input: 0.07, cachedInput: 0.01, cacheWrite: 0, output: 0.4 },
99800
+ "glm-4.7": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
99801
+ "glm-4.6": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
99802
+ "glm-4.5-air": { input: 0.2, cachedInput: 0.03, cacheWrite: 0, output: 1.1 },
99803
+ "glm-4.5": { input: 0.6, cachedInput: 0.11, cacheWrite: 0, output: 2.2 },
99804
+ // --- OpenAI (no separate cache-write price; cached input only) ---
99805
+ "gpt-5.2-codex": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
99806
+ "gpt-5.3-codex": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
99807
+ "gpt-5.1-codex": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
99808
+ "gpt-5.2": { input: 1.75, cachedInput: 0.175, cacheWrite: 1.75, output: 14 },
99809
+ "gpt-5.1": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
99810
+ "gpt-5-mini": { input: 0.25, cachedInput: 0.025, cacheWrite: 0.25, output: 2 },
99811
+ "gpt-5-nano": { input: 0.05, cachedInput: 5e-3, cacheWrite: 0.05, output: 0.4 },
99812
+ "gpt-5": { input: 1.25, cachedInput: 0.125, cacheWrite: 1.25, output: 10 },
99813
+ "gpt-4.1-mini": { input: 0.4, cachedInput: 0.1, cacheWrite: 0.4, output: 1.6 },
99814
+ "gpt-4.1": { input: 2, cachedInput: 0.5, cacheWrite: 2, output: 8 },
99815
+ "gpt-4o-mini": { input: 0.15, cachedInput: 0.075, cacheWrite: 0.15, output: 0.6 },
99816
+ "gpt-4o": { input: 2.5, cachedInput: 1.25, cacheWrite: 2.5, output: 10 },
99817
+ // --- Anthropic Claude (5m cache writes; reads at 0.1x base) ---
99818
+ "claude-opus-5-5": { input: 4, cachedInput: 0.2, cacheWrite: 5, output: 20 },
99819
+ "claude-opus-4-5": { input: 5, cachedInput: 0.5, cacheWrite: 6.25, output: 25 },
99820
+ "claude-opus-4": { input: 15, cachedInput: 1.5, cacheWrite: 18.75, output: 75 },
99821
+ "claude-sonnet-5-5": { input: 2, cachedInput: 0.1, cacheWrite: 2.5, output: 10 },
99822
+ "claude-sonnet-5": { input: 2, cachedInput: 0.2, cacheWrite: 2.5, output: 10 },
99823
+ "claude-sonnet-4-5": { input: 3, cachedInput: 0.3, cacheWrite: 3.75, output: 15 },
99824
+ "claude-sonnet-4": { input: 3, cachedInput: 0.3, cacheWrite: 3.75, output: 15 },
99825
+ "claude-haiku-5-5": { input: 0.1, cachedInput: 0.01, cacheWrite: 0.125, output: 0.5 },
99826
+ "claude-haiku-4-5": { input: 1, cachedInput: 0.1, cacheWrite: 1.25, output: 5 }
99827
+ };
99828
+ var SORTED_KEYS = Object.keys(PRICES).sort((a, b) => b.length - a.length);
99829
+ function normalizeModelId(modelId) {
99830
+ const lastSegment = modelId.toLowerCase().split("/").pop() ?? "";
99831
+ const withoutTag = lastSegment.split(":")[0];
99832
+ return withoutTag.replace(/-(\d{8}|\d{4}-\d{2}-\d{2})$/, "");
99833
+ }
99834
+ function findModelPricing(modelId) {
99835
+ const normalized = normalizeModelId(modelId);
99836
+ for (const key of SORTED_KEYS) {
99837
+ if (normalized === key || normalized.startsWith(`${key}-`)) return PRICES[key];
99838
+ }
99839
+ return null;
99840
+ }
99841
+ function computeCost(modelId, usage, inputIncludesCached) {
99842
+ const pricing = findModelPricing(modelId);
99843
+ if (!pricing) return null;
99844
+ const m = 1e6;
99845
+ const { inputTokens, cachedInputTokens, cacheWriteInputTokens, outputTokens } = usage;
99846
+ const uncached = inputIncludesCached ? Math.max(0, inputTokens - cachedInputTokens - cacheWriteInputTokens) : inputTokens;
99847
+ return (uncached * pricing.input + cachedInputTokens * pricing.cachedInput + cacheWriteInputTokens * pricing.cacheWrite + outputTokens * pricing.output) / m;
99848
+ }
99849
+
99850
+ // src/usage/usage-service.ts
99851
+ function usageFilesDir() {
99852
+ return process.env.AGENT_PANE_USAGE_DIR ?? join3(homedir3(), ".repoburg", "usage");
99853
+ }
99854
+ function emptyBucket() {
99855
+ return { calls: 0, errors: 0, input: 0, cached: 0, cacheWrite: 0, output: 0, cost: 0 };
99856
+ }
99857
+ function newAggregator() {
99858
+ return {
99859
+ totals: emptyBucket(),
99860
+ unpricedModels: /* @__PURE__ */ new Set(),
99861
+ byRuntime: /* @__PURE__ */ new Map(),
99862
+ byModel: /* @__PURE__ */ new Map(),
99863
+ byDay: /* @__PURE__ */ new Map()
99864
+ };
99865
+ }
99866
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
99867
+ function addEvent(agg, event) {
99868
+ const { runtimeType, provider, model, effort, day, isError, usage, inputIncludesCached } = event;
99869
+ const cost = usage ? computeCost(model, usage, inputIncludesCached) : null;
99870
+ if (usage && cost === null) agg.unpricedModels.add(model);
99871
+ const bump = (b) => {
99872
+ b.calls += 1;
99873
+ if (isError) b.errors += 1;
99874
+ if (usage) {
99875
+ b.input += usage.inputTokens;
99876
+ b.cached += usage.cachedInputTokens;
99877
+ b.cacheWrite += usage.cacheWriteInputTokens;
99878
+ b.output += usage.outputTokens;
99879
+ b.cost += cost ?? 0;
99880
+ }
99881
+ };
99882
+ bump(agg.totals);
99883
+ const runtimeBucket = agg.byRuntime.get(runtimeType) ?? emptyBucket();
99884
+ bump(runtimeBucket);
99885
+ agg.byRuntime.set(runtimeType, runtimeBucket);
99886
+ const dayBucket = agg.byDay.get(day) ?? emptyBucket();
99887
+ bump(dayBucket);
99888
+ agg.byDay.set(day, dayBucket);
99889
+ const key = `${runtimeType}|${provider ?? ""}|${model}|${effort ?? ""}`;
99890
+ const row = agg.byModel.get(key);
99891
+ if (row) {
99892
+ row.calls += 1;
99893
+ if (isError) row.errors += 1;
99894
+ if (usage) {
99895
+ row.input_tokens += usage.inputTokens;
99896
+ row.cached_input_tokens += usage.cachedInputTokens;
99897
+ row.cache_write_input_tokens += usage.cacheWriteInputTokens;
99898
+ row.output_tokens += usage.outputTokens;
99899
+ if (cost !== null) row.cost_usd = (row.cost_usd ?? 0) + cost;
99900
+ }
99901
+ } else {
99902
+ agg.byModel.set(key, {
99903
+ runtime_type: runtimeType,
99904
+ provider,
99905
+ model,
99906
+ reasoning_effort: effort,
99907
+ calls: 1,
99908
+ errors: isError ? 1 : 0,
99909
+ input_tokens: usage?.inputTokens ?? 0,
99910
+ cached_input_tokens: usage?.cachedInputTokens ?? 0,
99911
+ cache_write_input_tokens: usage?.cacheWriteInputTokens ?? 0,
99912
+ output_tokens: usage?.outputTokens ?? 0,
99913
+ cost_usd: cost,
99914
+ priced: cost !== null
99915
+ });
99916
+ }
99917
+ }
99918
+ function parseTokenUsage(raw) {
99919
+ if (!raw) return null;
99920
+ try {
99921
+ const parsed = JSON.parse(raw);
99922
+ if (!parsed || typeof parsed !== "object") return null;
99923
+ return {
99924
+ inputTokens: num(parsed.input_tokens),
99925
+ cachedInputTokens: num(parsed.cached_input_tokens),
99926
+ cacheWriteInputTokens: num(parsed.cache_write_input_tokens),
99927
+ outputTokens: num(parsed.output_tokens)
99928
+ };
99929
+ } catch {
99930
+ return null;
99931
+ }
99932
+ }
99933
+ function addPaneTurns(agg, sinceIso, untilIso) {
99934
+ const params = [];
99935
+ let where = "s.runtime_type IN ('claude','codex') AND t.status IN ('completed','failed','aborted')";
99936
+ if (sinceIso) {
99937
+ params.push(sinceIso);
99938
+ where += " AND t.created_at >= ?";
99939
+ }
99940
+ if (untilIso) {
99941
+ params.push(untilIso);
99942
+ where += " AND t.created_at < ?";
99943
+ }
99944
+ const rows = getDb().prepare(
99945
+ `SELECT s.runtime_type, s.model, s.model_reasoning_effort, t.token_usage, t.status, t.created_at
99946
+ FROM turns t JOIN sessions s ON s.id = t.session_id WHERE ${where}`
99947
+ ).all(...params);
99948
+ for (const row of rows) {
99949
+ const day = row.created_at.slice(0, 10);
99950
+ addEvent(agg, {
99951
+ runtimeType: row.runtime_type,
99952
+ provider: null,
99953
+ model: row.model ?? "(default)",
99954
+ effort: row.model_reasoning_effort ?? null,
99955
+ day,
99956
+ isError: row.status === "failed",
99957
+ usage: parseTokenUsage(row.token_usage),
99958
+ // Anthropic reports input/cache-read/cache-write as disjoint buckets.
99959
+ inputIncludesCached: row.runtime_type !== "claude"
99960
+ });
99961
+ }
99962
+ }
99963
+ function addRepoburgExport(agg, sinceIso, untilIso) {
99964
+ let files;
99965
+ try {
99966
+ files = readdirSync2(usageFilesDir()).filter((f) => /^usage-\d{4}-\d{2}-\d{2}\.jsonl$/.test(f)).sort();
99967
+ } catch {
99968
+ return;
99969
+ }
99970
+ const sinceDay = sinceIso?.slice(0, 10) ?? null;
99971
+ const untilDay = untilIso ? untilIso.slice(0, 10) : null;
99972
+ for (const file of files) {
99973
+ const day = file.slice("usage-".length, file.length - ".jsonl".length);
99974
+ if (sinceDay && day < sinceDay) continue;
99975
+ if (untilDay && day > untilDay) continue;
99976
+ let content;
99977
+ try {
99978
+ content = readFileSync2(join3(usageFilesDir(), file), "utf-8");
99979
+ } catch {
99980
+ continue;
99981
+ }
99982
+ for (const line of content.split("\n")) {
99983
+ const trimmed = line.trim();
99984
+ if (!trimmed) continue;
99985
+ let record;
99986
+ try {
99987
+ record = JSON.parse(trimmed);
99988
+ } catch {
99989
+ continue;
99990
+ }
99991
+ if (sinceIso && record.ts < sinceIso) continue;
99992
+ if (untilIso && record.ts >= untilIso) continue;
99993
+ const status = record.status_code;
99994
+ addEvent(agg, {
99995
+ runtimeType: "repoburg",
99996
+ provider: record.provider ?? null,
99997
+ model: record.model_id ?? "(unknown)",
99998
+ effort: record.reasoning_effort ?? null,
99999
+ day: record.ts.slice(0, 10),
100000
+ isError: status === null || status < 200 || status >= 300,
100001
+ usage: {
100002
+ inputTokens: num(record.input_tokens),
100003
+ cachedInputTokens: num(record.cached_tokens),
100004
+ cacheWriteInputTokens: 0,
100005
+ outputTokens: num(record.output_tokens)
100006
+ },
100007
+ // OpenAI-compatible providers report cached tokens inside input.
100008
+ inputIncludesCached: true
100009
+ });
100010
+ }
100011
+ }
100012
+ }
100013
+ function getUsageSummary(sinceIso, untilIso) {
100014
+ const agg = newAggregator();
100015
+ addPaneTurns(agg, sinceIso, untilIso);
100016
+ addRepoburgExport(agg, sinceIso, untilIso);
100017
+ const byRuntime = [...agg.byRuntime.entries()].map(([runtimeType, b]) => ({
100018
+ runtime_type: runtimeType,
100019
+ calls: b.calls,
100020
+ errors: b.errors,
100021
+ input_tokens: b.input,
100022
+ cached_input_tokens: b.cached,
100023
+ cache_write_input_tokens: b.cacheWrite,
100024
+ output_tokens: b.output,
100025
+ cost_usd: b.cost
100026
+ })).sort((a, b) => a.runtime_type.localeCompare(b.runtime_type));
100027
+ const byModel = [...agg.byModel.values()].map((row) => ({
100028
+ runtime_type: row.runtime_type,
100029
+ provider: row.provider,
100030
+ model: row.model,
100031
+ reasoning_effort: row.reasoning_effort,
100032
+ calls: row.calls,
100033
+ errors: row.errors,
100034
+ input_tokens: row.input_tokens,
100035
+ cached_input_tokens: row.cached_input_tokens,
100036
+ cache_write_input_tokens: row.cache_write_input_tokens,
100037
+ output_tokens: row.output_tokens,
100038
+ // Unpriced models stay null; a priced row that also saw zero-token
100039
+ // error events keeps its exact sum.
100040
+ cost_usd: row.priced ? row.cost_usd ?? 0 : null
100041
+ })).sort((a, b) => (b.cost_usd ?? 0) - (a.cost_usd ?? 0) || b.calls - a.calls);
100042
+ const daily = [...agg.byDay.entries()].map(([date, b]) => ({
100043
+ date,
100044
+ calls: b.calls,
100045
+ input_tokens: b.input,
100046
+ cached_input_tokens: b.cached,
100047
+ cache_write_input_tokens: b.cacheWrite,
100048
+ output_tokens: b.output,
100049
+ cost_usd: b.cost
100050
+ })).sort((a, b) => a.date.localeCompare(b.date));
100051
+ return {
100052
+ window: { since: sinceIso, until: untilIso },
100053
+ totals: {
100054
+ calls: agg.totals.calls,
100055
+ errors: agg.totals.errors,
100056
+ input_tokens: agg.totals.input,
100057
+ cached_input_tokens: agg.totals.cached,
100058
+ cache_write_input_tokens: agg.totals.cacheWrite,
100059
+ output_tokens: agg.totals.output,
100060
+ total_tokens: agg.totals.input + agg.totals.cached + agg.totals.cacheWrite + agg.totals.output,
100061
+ cost_usd: agg.totals.cost,
100062
+ unpriced_models: [...agg.unpricedModels].sort()
100063
+ },
100064
+ by_runtime: byRuntime,
100065
+ by_model: byModel,
100066
+ daily
100067
+ };
100068
+ }
100069
+
100070
+ // src/routes/usage.ts
100071
+ function parseTimeParam(value) {
100072
+ if (typeof value !== "string" || value === "") return null;
100073
+ if (Number.isNaN(Date.parse(value))) {
100074
+ throw Object.assign(new Error(`Invalid timestamp: ${value}`), { statusCode: 400 });
100075
+ }
100076
+ return value;
100077
+ }
100078
+ async function registerUsageRoutes(fastify) {
100079
+ fastify.get(
100080
+ "/api/usage/summary",
100081
+ {
100082
+ schema: {
100083
+ querystring: {
100084
+ type: "object",
100085
+ properties: {
100086
+ since: { type: "string" },
100087
+ until: { type: "string" }
100088
+ }
100089
+ }
100090
+ }
100091
+ },
100092
+ async (request, reply) => {
100093
+ try {
100094
+ const since = parseTimeParam(request.query?.since);
100095
+ const until = parseTimeParam(request.query?.until);
100096
+ return getUsageSummary(since, until);
100097
+ } catch (err) {
100098
+ const e = err;
100099
+ if (e.statusCode === 400) {
100100
+ return reply.code(400).send({ error: e.message });
100101
+ }
100102
+ throw err;
100103
+ }
100104
+ }
100105
+ );
100106
+ }
100107
+
99764
100108
  // src/codex/item-mapper.ts
99765
100109
  function mapItemData(item) {
99766
100110
  switch (item.type) {
@@ -100525,9 +100869,9 @@ var codexProvider = {
100525
100869
 
100526
100870
  // src/claude/claude-provider.ts
100527
100871
  import { query, forkSession as sdkForkSession } from "@anthropic-ai/claude-agent-sdk";
100528
- import { readFileSync as readFileSync2 } from "fs";
100872
+ import { readFileSync as readFileSync3 } from "fs";
100529
100873
  import { tmpdir } from "os";
100530
- import { join as join3 } from "path";
100874
+ import { join as join4 } from "path";
100531
100875
 
100532
100876
  // src/claude/claude-message-mapper.ts
100533
100877
  function mapAssistantContent(content, messageId, thinkingTexts) {
@@ -101047,7 +101391,8 @@ function handleLoopError(entry, sessionId, errMsg, db2) {
101047
101391
  turn_id: row.turn_id,
101048
101392
  external_item_id: row.external_item_id,
101049
101393
  type: row.type,
101050
- data: row.data ? JSON.parse(row.data) : {},
101394
+ // MUH-25 — re-broadcasts ship trimmed payloads too.
101395
+ data: row.data ? trimItemData(JSON.parse(row.data)) : {},
101051
101396
  status: "failed",
101052
101397
  created_at: row.created_at,
101053
101398
  updated_at: now
@@ -101468,7 +101813,7 @@ function constructMonitorOutputPath(entry, taskId) {
101468
101813
  if (!entry.sessionId) return "";
101469
101814
  const uid = typeof process.getuid === "function" ? process.getuid() : 0;
101470
101815
  const encodedCwd = entry.cwd.replace(/\//g, "-");
101471
- return join3(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
101816
+ return join4(tmpdir(), `claude-${uid}`, encodedCwd, entry.sessionId, "tasks", `${taskId}.output`);
101472
101817
  }
101473
101818
  function handleTaskStarted(message, sessionId, turnId, entry, db2) {
101474
101819
  const m = message;
@@ -101511,7 +101856,7 @@ function handleTaskProgress(message, sessionId, turnId, entry, db2) {
101511
101856
  const outputPath = existing.output_file || constructMonitorOutputPath(entry, m.task_id);
101512
101857
  if (outputPath) {
101513
101858
  try {
101514
- output = readFileSync2(outputPath, "utf-8");
101859
+ output = readFileSync3(outputPath, "utf-8");
101515
101860
  } catch {
101516
101861
  }
101517
101862
  }
@@ -101560,13 +101905,11 @@ function handleTaskNotification(message, sessionId, turnId, entry, db2) {
101560
101905
  if (!row) return;
101561
101906
  const existing = row.data ? JSON.parse(row.data) : {};
101562
101907
  const taskType = existing.task_type ?? "unknown";
101563
- const sdkOutputFile = m.output_file || null;
101564
- const constructedPath = taskType === "local_bash" ? constructMonitorOutputPath(entry, m.task_id) : "";
101565
- const outputPath = sdkOutputFile || constructedPath;
101908
+ const outputPath = taskType === "local_bash" ? m.output_file || constructMonitorOutputPath(entry, m.task_id) : null;
101566
101909
  let output = "";
101567
101910
  if (outputPath) {
101568
101911
  try {
101569
- output = readFileSync2(outputPath, "utf-8");
101912
+ output = readFileSync3(outputPath, "utf-8");
101570
101913
  } catch {
101571
101914
  }
101572
101915
  }
@@ -101574,7 +101917,7 @@ function handleTaskNotification(message, sessionId, turnId, entry, db2) {
101574
101917
  ...existing,
101575
101918
  status: m.status,
101576
101919
  summary: m.summary,
101577
- output_file: outputPath,
101920
+ output_file: m.output_file || outputPath || existing.output_file || null,
101578
101921
  output,
101579
101922
  token_count: m.usage?.total_tokens ?? existing.token_count ?? null
101580
101923
  };
@@ -101645,7 +101988,8 @@ function completeTurn(db2, sessionId, turnId, usage) {
101645
101988
  }
101646
101989
  function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
101647
101990
  const now = (/* @__PURE__ */ new Date()).toISOString();
101648
- const result = db2.prepare("UPDATE items SET data = ?, status = ?, updated_at = ? WHERE external_item_id = ? AND turn_id = ?").run(JSON.stringify(desc.data), status, now, desc.externalId, turnId);
101991
+ const data = trimItemData(desc.data);
101992
+ 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);
101649
101993
  let itemId;
101650
101994
  let createdAt;
101651
101995
  if (result.changes === 0) {
@@ -101653,7 +101997,7 @@ function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
101653
101997
  createdAt = now;
101654
101998
  db2.prepare(
101655
101999
  "INSERT INTO items (id, turn_id, external_item_id, type, data, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
101656
- ).run(itemId, turnId, desc.externalId, desc.type, JSON.stringify(desc.data), status, now, now);
102000
+ ).run(itemId, turnId, desc.externalId, desc.type, JSON.stringify(data), status, now, now);
101657
102001
  } else {
101658
102002
  const row = db2.prepare("SELECT id, created_at FROM items WHERE external_item_id = ? AND turn_id = ?").get(desc.externalId, turnId);
101659
102003
  itemId = row.id;
@@ -101664,7 +102008,7 @@ function upsertItem(db2, desc, sessionId, turnId, status, broadcastEvent) {
101664
102008
  turn_id: turnId,
101665
102009
  external_item_id: desc.externalId,
101666
102010
  type: desc.type,
101667
- data: desc.data,
102011
+ data,
101668
102012
  status,
101669
102013
  created_at: createdAt,
101670
102014
  updated_at: now
@@ -103651,6 +103995,7 @@ async function createAgentPaneApp(dbPath) {
103651
103995
  await registerVscodeWebRoutes(fastify);
103652
103996
  await registerAppRoutes(fastify);
103653
103997
  await registerSidecarRoutes(fastify);
103998
+ await registerUsageRoutes(fastify);
103654
103999
  const wss2 = initWs();
103655
104000
  wss2.on("connection", (ws) => {
103656
104001
  ws.send(JSON.stringify({ event: "background_tasks:snapshot", data: { sessions: listAllBackgroundTasks() } }));