repoburg 1.3.199 → 1.3.201

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 (82) hide show
  1. package/agent-pane/backend/data.db +0 -0
  2. package/agent-pane/backend/data.db-shm +0 -0
  3. package/agent-pane/backend/data.db-wal +0 -0
  4. package/agent-pane/backend/dist/index.js +1425 -272
  5. package/agent-pane/backend/src/claude/claude-provider.test.ts +393 -3
  6. package/agent-pane/backend/src/claude/claude-provider.ts +53 -50
  7. package/agent-pane/backend/src/db/index.ts +6 -0
  8. package/agent-pane/backend/src/index.ts +5 -2
  9. package/agent-pane/backend/src/integration/threads-claude-fork.test.ts +241 -0
  10. package/agent-pane/backend/src/providers/index.ts +3 -1
  11. package/agent-pane/backend/src/repoburg/action-mapping.ts +216 -0
  12. package/agent-pane/backend/src/repoburg/agent-runtime-client.test.ts +271 -0
  13. package/agent-pane/backend/src/repoburg/agent-runtime-client.ts +262 -0
  14. package/agent-pane/backend/src/repoburg/backend-resolver.test.ts +271 -0
  15. package/agent-pane/backend/src/repoburg/backend-resolver.ts +246 -0
  16. package/agent-pane/backend/src/repoburg/repoburg-client.test.ts +159 -0
  17. package/agent-pane/backend/src/repoburg/repoburg-client.ts +181 -0
  18. package/agent-pane/backend/src/repoburg/repoburg-provider.test.ts +723 -0
  19. package/agent-pane/backend/src/repoburg/repoburg-provider.ts +422 -0
  20. package/agent-pane/backend/src/repoburg/turn-projector.test.ts +475 -0
  21. package/agent-pane/backend/src/repoburg/turn-projector.ts +537 -0
  22. package/agent-pane/backend/src/routes/providers.test.ts +18 -1
  23. package/agent-pane/backend/src/routes/providers.ts +19 -1
  24. package/agent-pane/backend/src/routes/sessions.ts +12 -0
  25. package/agent-pane/backend/src/routes/threads.ts +21 -6
  26. package/agent-pane/backend/src/routes/turns.test.ts +45 -1
  27. package/agent-pane/frontend/dist/assets/{index-Dwwhx7YN.css → index-34WaZYsW.css} +1 -1
  28. package/agent-pane/frontend/dist/assets/index-y7xlT86e.js +362 -0
  29. package/agent-pane/frontend/dist/index.html +2 -2
  30. package/agent-pane/frontend/src/components/CommentableText.test.tsx +196 -0
  31. package/agent-pane/frontend/src/components/CommentableText.tsx +109 -21
  32. package/agent-pane/frontend/src/components/IdeWorkspace.test.tsx +39 -0
  33. package/agent-pane/frontend/src/components/IdeWorkspace.tsx +28 -2
  34. package/agent-pane/frontend/src/components/ResizeHandle.tsx +29 -0
  35. package/agent-pane/frontend/src/components/panels/ThreadsPanel.tsx +35 -3
  36. package/agent-pane/frontend/src/constants/models.ts +37 -0
  37. package/agent-pane/frontend/src/hooks/useResizable.test.ts +97 -0
  38. package/agent-pane/frontend/src/hooks/useResizable.ts +75 -0
  39. package/agent-pane/frontend/src/store/store.test.ts +35 -0
  40. package/agent-pane/frontend/src/store/uiSlice.ts +50 -0
  41. package/agent-pane/frontend/src/styles/app.css +10 -1
  42. package/agent-pane/frontend/src/test/component-helpers.ts +2 -0
  43. package/agent-pane-bug-repro-no-agent-reply.png +0 -0
  44. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.d.ts +20 -0
  45. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.js +112 -0
  46. package/backend/dist/src/agent-runtime/agent-runtime-event-emitter.js.map +1 -0
  47. package/backend/dist/src/agent-runtime/agent-runtime.controller.d.ts +11 -0
  48. package/backend/dist/src/agent-runtime/agent-runtime.controller.js +91 -0
  49. package/backend/dist/src/agent-runtime/agent-runtime.controller.js.map +1 -0
  50. package/backend/dist/src/agent-runtime/agent-runtime.module.d.ts +2 -0
  51. package/backend/dist/src/agent-runtime/agent-runtime.module.js +26 -0
  52. package/backend/dist/src/agent-runtime/agent-runtime.module.js.map +1 -0
  53. package/backend/dist/src/agent-runtime/agent-runtime.types.d.ts +77 -0
  54. package/backend/dist/src/agent-runtime/agent-runtime.types.js +3 -0
  55. package/backend/dist/src/agent-runtime/agent-runtime.types.js.map +1 -0
  56. package/backend/dist/src/app.module.js +4 -0
  57. package/backend/dist/src/app.module.js.map +1 -1
  58. package/backend/dist/src/interactive-chat/chat.module.js +4 -0
  59. package/backend/dist/src/interactive-chat/chat.module.js.map +1 -1
  60. package/backend/dist/src/interactive-chat/chat.service.d.ts +3 -1
  61. package/backend/dist/src/interactive-chat/chat.service.js +33 -6
  62. package/backend/dist/src/interactive-chat/chat.service.js.map +1 -1
  63. package/backend/dist/src/llm-orchestration/hooks/frontend-notification.hook.d.ts +3 -1
  64. package/backend/dist/src/llm-orchestration/hooks/frontend-notification.hook.js +20 -2
  65. package/backend/dist/src/llm-orchestration/hooks/frontend-notification.hook.js.map +1 -1
  66. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js +2 -0
  67. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js.map +1 -1
  68. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.d.ts +4 -1
  69. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js +35 -2
  70. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js.map +1 -1
  71. package/backend/dist/src/llm-provider/ollama-llm.provider.d.ts +1 -0
  72. package/backend/dist/src/llm-provider/ollama-llm.provider.js +19 -1
  73. package/backend/dist/src/llm-provider/ollama-llm.provider.js.map +1 -1
  74. package/backend/dist/src/llm-responses/llm-responses.module.js +4 -0
  75. package/backend/dist/src/llm-responses/llm-responses.module.js.map +1 -1
  76. package/backend/dist/src/llm-responses/llm-responses.service.d.ts +4 -1
  77. package/backend/dist/src/llm-responses/llm-responses.service.js +52 -2
  78. package/backend/dist/src/llm-responses/llm-responses.service.js.map +1 -1
  79. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  80. package/daemon/dist/index.js +0 -0
  81. package/package.json +1 -1
  82. package/agent-pane/frontend/dist/assets/index-BYo-lnxm.js +0 -362
@@ -75,7 +75,7 @@ var require_queue = __commonJS({
75
75
  if (!(_concurrency >= 1)) {
76
76
  throw new Error("fastqueue concurrency must be equal to or greater than 1");
77
77
  }
78
- var cache = reusify(Task);
78
+ var cache2 = reusify(Task);
79
79
  var queueHead = null;
80
80
  var queueTail = null;
81
81
  var _running = 0;
@@ -154,7 +154,7 @@ var require_queue = __commonJS({
154
154
  return _running === 0 && self2.length() === 0;
155
155
  }
156
156
  function push(value, done) {
157
- var current = cache.get();
157
+ var current = cache2.get();
158
158
  current.context = context;
159
159
  current.release = release;
160
160
  current.value = value;
@@ -175,7 +175,7 @@ var require_queue = __commonJS({
175
175
  }
176
176
  }
177
177
  function unshift(value, done) {
178
- var current = cache.get();
178
+ var current = cache2.get();
179
179
  current.context = context;
180
180
  current.release = release;
181
181
  current.value = value;
@@ -197,7 +197,7 @@ var require_queue = __commonJS({
197
197
  }
198
198
  function release(holder) {
199
199
  if (holder) {
200
- cache.release(holder);
200
+ cache2.release(holder);
201
201
  }
202
202
  var next = queueHead;
203
203
  if (next && _running <= _concurrency) {
@@ -3984,7 +3984,7 @@ var require_content_type = __commonJS({
3984
3984
  var quotedPairReg = /\\([\t\u0020-\u00ff])/gu;
3985
3985
  var typeNameReg = /^[\w!#$%&'*+.^`|~-]+$/;
3986
3986
  var subtypeNameReg = /^[\w!#$%&'*+.^`|~-]+\s*$/;
3987
- var cache = new Lru(100);
3987
+ var cache2 = new Lru(100);
3988
3988
  var ContentType = class _ContentType {
3989
3989
  #valid = false;
3990
3990
  #empty = true;
@@ -3998,7 +3998,7 @@ var require_content_type = __commonJS({
3998
3998
  * @type {Lru<ContentType>}
3999
3999
  */
4000
4000
  static get cache() {
4001
- return cache;
4001
+ return cache2;
4002
4002
  }
4003
4003
  /**
4004
4004
  * Create a ContentType instance from a header value. If the value has been
@@ -4007,10 +4007,10 @@ var require_content_type = __commonJS({
4007
4007
  * @returns {ContentType | undefined}
4008
4008
  */
4009
4009
  static from(headerValue) {
4010
- let contentType = cache.get(headerValue);
4010
+ let contentType = cache2.get(headerValue);
4011
4011
  if (contentType !== void 0) return contentType;
4012
4012
  contentType = new _ContentType(headerValue);
4013
- cache.set(headerValue, contentType);
4013
+ cache2.set(headerValue, contentType);
4014
4014
  return contentType;
4015
4015
  }
4016
4016
  constructor(headerValue) {
@@ -6123,8 +6123,8 @@ var require_req = __commonJS({
6123
6123
  if (req.originalUrl) {
6124
6124
  _req.url = req.originalUrl;
6125
6125
  } else {
6126
- const path = req.path;
6127
- _req.url = typeof path === "string" ? path : req.url ? req.url.path || req.url : void 0;
6126
+ const path2 = req.path;
6127
+ _req.url = typeof path2 === "string" ? path2 : req.url ? req.url.path || req.url : void 0;
6128
6128
  }
6129
6129
  if (req.query) {
6130
6130
  _req.query = req.query;
@@ -6289,14 +6289,14 @@ var require_redact = __commonJS({
6289
6289
  }
6290
6290
  return obj;
6291
6291
  }
6292
- function parsePath(path) {
6292
+ function parsePath(path2) {
6293
6293
  const parts = [];
6294
6294
  let current = "";
6295
6295
  let inBrackets = false;
6296
6296
  let inQuotes = false;
6297
6297
  let quoteChar = "";
6298
- for (let i = 0; i < path.length; i++) {
6299
- const char = path[i];
6298
+ for (let i = 0; i < path2.length; i++) {
6299
+ const char = path2[i];
6300
6300
  if (!inBrackets && char === ".") {
6301
6301
  if (current) {
6302
6302
  parts.push(current);
@@ -6427,10 +6427,10 @@ var require_redact = __commonJS({
6427
6427
  return current;
6428
6428
  }
6429
6429
  function redactPaths(obj, paths, censor, remove = false) {
6430
- for (const path of paths) {
6431
- const parts = parsePath(path);
6430
+ for (const path2 of paths) {
6431
+ const parts = parsePath(path2);
6432
6432
  if (parts.includes("*")) {
6433
- redactWildcardPath(obj, parts, censor, path, remove);
6433
+ redactWildcardPath(obj, parts, censor, path2, remove);
6434
6434
  } else {
6435
6435
  if (remove) {
6436
6436
  removeKey(obj, parts);
@@ -6515,8 +6515,8 @@ var require_redact = __commonJS({
6515
6515
  }
6516
6516
  } else {
6517
6517
  if (afterWildcard.includes("*")) {
6518
- const wrappedCensor = typeof censor === "function" ? (value, path) => {
6519
- const fullPath = [...pathArray.slice(0, pathLength), ...path];
6518
+ const wrappedCensor = typeof censor === "function" ? (value, path2) => {
6519
+ const fullPath = [...pathArray.slice(0, pathLength), ...path2];
6520
6520
  return censor(value, fullPath);
6521
6521
  } : censor;
6522
6522
  redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
@@ -6551,8 +6551,8 @@ var require_redact = __commonJS({
6551
6551
  return null;
6552
6552
  }
6553
6553
  const pathStructure = /* @__PURE__ */ new Map();
6554
- for (const path of pathsToClone) {
6555
- const parts = parsePath(path);
6554
+ for (const path2 of pathsToClone) {
6555
+ const parts = parsePath(path2);
6556
6556
  let current = pathStructure;
6557
6557
  for (let i = 0; i < parts.length; i++) {
6558
6558
  const part = parts[i];
@@ -6604,24 +6604,24 @@ var require_redact = __commonJS({
6604
6604
  }
6605
6605
  return cloneSelectively(obj, pathStructure);
6606
6606
  }
6607
- function validatePath(path) {
6608
- if (typeof path !== "string") {
6607
+ function validatePath(path2) {
6608
+ if (typeof path2 !== "string") {
6609
6609
  throw new Error("Paths must be (non-empty) strings");
6610
6610
  }
6611
- if (path === "") {
6611
+ if (path2 === "") {
6612
6612
  throw new Error("Invalid redaction path ()");
6613
6613
  }
6614
- if (path.includes("..")) {
6615
- throw new Error(`Invalid redaction path (${path})`);
6614
+ if (path2.includes("..")) {
6615
+ throw new Error(`Invalid redaction path (${path2})`);
6616
6616
  }
6617
- if (path.includes(",")) {
6618
- throw new Error(`Invalid redaction path (${path})`);
6617
+ if (path2.includes(",")) {
6618
+ throw new Error(`Invalid redaction path (${path2})`);
6619
6619
  }
6620
6620
  let bracketCount = 0;
6621
6621
  let inQuotes = false;
6622
6622
  let quoteChar = "";
6623
- for (let i = 0; i < path.length; i++) {
6624
- const char = path[i];
6623
+ for (let i = 0; i < path2.length; i++) {
6624
+ const char = path2[i];
6625
6625
  if ((char === '"' || char === "'") && bracketCount > 0) {
6626
6626
  if (!inQuotes) {
6627
6627
  inQuotes = true;
@@ -6635,20 +6635,20 @@ var require_redact = __commonJS({
6635
6635
  } else if (char === "]" && !inQuotes) {
6636
6636
  bracketCount--;
6637
6637
  if (bracketCount < 0) {
6638
- throw new Error(`Invalid redaction path (${path})`);
6638
+ throw new Error(`Invalid redaction path (${path2})`);
6639
6639
  }
6640
6640
  }
6641
6641
  }
6642
6642
  if (bracketCount !== 0) {
6643
- throw new Error(`Invalid redaction path (${path})`);
6643
+ throw new Error(`Invalid redaction path (${path2})`);
6644
6644
  }
6645
6645
  }
6646
6646
  function validatePaths(paths) {
6647
6647
  if (!Array.isArray(paths)) {
6648
6648
  throw new TypeError("paths must be an array");
6649
6649
  }
6650
- for (const path of paths) {
6651
- validatePath(path);
6650
+ for (const path2 of paths) {
6651
+ validatePath(path2);
6652
6652
  }
6653
6653
  }
6654
6654
  function slowRedact(options = {}) {
@@ -6816,8 +6816,8 @@ var require_redaction = __commonJS({
6816
6816
  if (shape[k2] === null) {
6817
6817
  o[k2] = (value) => topCensor(value, [k2]);
6818
6818
  } else {
6819
- const wrappedCensor = typeof censor === "function" ? (value, path) => {
6820
- return censor(value, [k2, ...path]);
6819
+ const wrappedCensor = typeof censor === "function" ? (value, path2) => {
6820
+ return censor(value, [k2, ...path2]);
6821
6821
  } : censor;
6822
6822
  o[k2] = Redact({
6823
6823
  paths: shape[k2],
@@ -7038,7 +7038,7 @@ var require_sonic_boom = __commonJS({
7038
7038
  var fs = __require("fs");
7039
7039
  var EventEmitter2 = __require("events");
7040
7040
  var inherits = __require("util").inherits;
7041
- var path = __require("path");
7041
+ var path2 = __require("path");
7042
7042
  var sleep = require_atomic_sleep();
7043
7043
  var assert = __require("assert");
7044
7044
  var BUSY_WRITE_TIMEOUT = 100;
@@ -7092,7 +7092,7 @@ var require_sonic_boom = __commonJS({
7092
7092
  const mode = sonic.mode;
7093
7093
  if (sonic.sync) {
7094
7094
  try {
7095
- if (sonic.mkdir) fs.mkdirSync(path.dirname(file), { recursive: true });
7095
+ if (sonic.mkdir) fs.mkdirSync(path2.dirname(file), { recursive: true });
7096
7096
  const fd2 = fs.openSync(file, flags, mode);
7097
7097
  fileOpened(null, fd2);
7098
7098
  } catch (err) {
@@ -7100,7 +7100,7 @@ var require_sonic_boom = __commonJS({
7100
7100
  throw err;
7101
7101
  }
7102
7102
  } else if (sonic.mkdir) {
7103
- fs.mkdir(path.dirname(file), { recursive: true }, (err) => {
7103
+ fs.mkdir(path2.dirname(file), { recursive: true }, (err) => {
7104
7104
  if (err) return fileOpened(err);
7105
7105
  fs.open(file, flags, mode, fileOpened);
7106
7106
  });
@@ -8432,15 +8432,15 @@ var require_transport = __commonJS({
8432
8432
  if (!unquoted) {
8433
8433
  return false;
8434
8434
  }
8435
- let path = unquoted;
8436
- if (path.startsWith("file://")) {
8435
+ let path2 = unquoted;
8436
+ if (path2.startsWith("file://")) {
8437
8437
  try {
8438
- path = fileURLToPath(path);
8438
+ path2 = fileURLToPath(path2);
8439
8439
  } catch {
8440
8440
  return false;
8441
8441
  }
8442
8442
  }
8443
- return isAbsolute4(path) && !existsSync2(path);
8443
+ return isAbsolute4(path2) && !existsSync2(path2);
8444
8444
  }
8445
8445
  function stripQuotes(value) {
8446
8446
  const first = value[0];
@@ -8981,12 +8981,12 @@ var require_levels = __commonJS({
8981
8981
  function genLsCache(instance) {
8982
8982
  const formatter = instance[formattersSym].level;
8983
8983
  const { labels } = instance.levels;
8984
- const cache = {};
8984
+ const cache2 = {};
8985
8985
  for (const label in labels) {
8986
8986
  const level = formatter(labels[label], Number(label));
8987
- cache[label] = JSON.stringify(level).slice(0, -1);
8987
+ cache2[label] = JSON.stringify(level).slice(0, -1);
8988
8988
  }
8989
- instance[lsCacheSym] = cache;
8989
+ instance[lsCacheSym] = cache2;
8990
8990
  return instance;
8991
8991
  }
8992
8992
  function isStandardLevel(level, useOnlyCustomLevels) {
@@ -17116,8 +17116,8 @@ var require_utils = __commonJS({
17116
17116
  }
17117
17117
  return ind;
17118
17118
  }
17119
- function removeDotSegments(path) {
17120
- let input = path;
17119
+ function removeDotSegments(path2) {
17120
+ let input = path2;
17121
17121
  const output = [];
17122
17122
  let nextSlash = -1;
17123
17123
  let len = 0;
@@ -17369,8 +17369,8 @@ var require_schemes = __commonJS({
17369
17369
  wsComponent.secure = void 0;
17370
17370
  }
17371
17371
  if (wsComponent.resourceName) {
17372
- const [path, query] = wsComponent.resourceName.split("?");
17373
- wsComponent.path = path && path !== "/" ? path : void 0;
17372
+ const [path2, query] = wsComponent.resourceName.split("?");
17373
+ wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
17374
17374
  wsComponent.query = query;
17375
17375
  wsComponent.resourceName = void 0;
17376
17376
  }
@@ -22307,8 +22307,8 @@ var require_utils2 = __commonJS({
22307
22307
  }
22308
22308
  return ind;
22309
22309
  }
22310
- function removeDotSegments(path) {
22311
- let input = path;
22310
+ function removeDotSegments(path2) {
22311
+ let input = path2;
22312
22312
  const output = [];
22313
22313
  let nextSlash = -1;
22314
22314
  let len = 0;
@@ -22653,8 +22653,8 @@ var require_schemes2 = __commonJS({
22653
22653
  wsComponent.secure = void 0;
22654
22654
  }
22655
22655
  if (wsComponent.resourceName) {
22656
- const [path, query] = wsComponent.resourceName.split("?");
22657
- wsComponent.path = path && path !== "/" ? path : void 0;
22656
+ const [path2, query] = wsComponent.resourceName.split("?");
22657
+ wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
22658
22658
  wsComponent.query = query;
22659
22659
  wsComponent.resourceName = void 0;
22660
22660
  }
@@ -24138,8 +24138,8 @@ var require_utils3 = __commonJS({
24138
24138
  }
24139
24139
  return ind;
24140
24140
  }
24141
- function removeDotSegments(path) {
24142
- let input = path;
24141
+ function removeDotSegments(path2) {
24142
+ let input = path2;
24143
24143
  const output = [];
24144
24144
  let nextSlash = -1;
24145
24145
  let len = 0;
@@ -24484,8 +24484,8 @@ var require_schemes3 = __commonJS({
24484
24484
  wsComponent.secure = void 0;
24485
24485
  }
24486
24486
  if (wsComponent.resourceName) {
24487
- const [path, query] = wsComponent.resourceName.split("?");
24488
- wsComponent.path = path && path !== "/" ? path : void 0;
24487
+ const [path2, query] = wsComponent.resourceName.split("?");
24488
+ wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
24489
24489
  wsComponent.query = query;
24490
24490
  wsComponent.resourceName = void 0;
24491
24491
  }
@@ -28884,7 +28884,7 @@ var require_range = __commonJS({
28884
28884
  range = range.replace(BUILDSTRIPRE, "");
28885
28885
  const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
28886
28886
  const memoKey = memoOpts + ":" + range;
28887
- const cached = cache.get(memoKey);
28887
+ const cached = cache2.get(memoKey);
28888
28888
  if (cached) {
28889
28889
  return cached;
28890
28890
  }
@@ -28918,7 +28918,7 @@ var require_range = __commonJS({
28918
28918
  rangeMap.delete("");
28919
28919
  }
28920
28920
  const result = [...rangeMap.values()];
28921
- cache.set(memoKey, result);
28921
+ cache2.set(memoKey, result);
28922
28922
  return result;
28923
28923
  }
28924
28924
  intersects(range, options) {
@@ -28957,7 +28957,7 @@ var require_range = __commonJS({
28957
28957
  };
28958
28958
  module.exports = Range;
28959
28959
  var LRU = require_lrucache();
28960
- var cache = new LRU();
28960
+ var cache2 = new LRU();
28961
28961
  var parseOptions = require_parse_options();
28962
28962
  var Comparator = require_comparator();
28963
28963
  var debug = require_debug2();
@@ -29907,12 +29907,12 @@ var require_plugin_utils = __commonJS({
29907
29907
  if (display) {
29908
29908
  return display;
29909
29909
  }
29910
- const cache = __require.cache;
29911
- if (cache) {
29912
- const keys = Object.keys(cache);
29910
+ const cache2 = __require.cache;
29911
+ if (cache2) {
29912
+ const keys = Object.keys(cache2);
29913
29913
  for (let i = 0; i < keys.length; i++) {
29914
29914
  const key = keys[i];
29915
- if (cache[key].exports === func) {
29915
+ if (cache2[key].exports === func) {
29916
29916
  return key;
29917
29917
  }
29918
29918
  }
@@ -32002,13 +32002,13 @@ var require_node = __commonJS({
32002
32002
  this.staticChildrenNodes[index] = node;
32003
32003
  }
32004
32004
  }
32005
- findStaticMatchingChild(path, pathIndex) {
32006
- const charCode = path.charCodeAt(pathIndex);
32005
+ findStaticMatchingChild(path2, pathIndex) {
32006
+ const charCode = path2.charCodeAt(pathIndex);
32007
32007
  const charCodes = this.staticChildrenCharCodes;
32008
32008
  for (let i = 0; i < charCodes.length; i++) {
32009
32009
  if (charCodes[i] === charCode) {
32010
32010
  const staticChild = this.staticChildrenNodes[i];
32011
- if (staticChild.matchPrefix(path, pathIndex)) {
32011
+ if (staticChild.matchPrefix(path2, pathIndex)) {
32012
32012
  return staticChild;
32013
32013
  }
32014
32014
  return null;
@@ -32016,34 +32016,34 @@ var require_node = __commonJS({
32016
32016
  }
32017
32017
  return null;
32018
32018
  }
32019
- getStaticChild(path, pathIndex = 0) {
32020
- if (path.length === pathIndex) {
32019
+ getStaticChild(path2, pathIndex = 0) {
32020
+ if (path2.length === pathIndex) {
32021
32021
  return this;
32022
32022
  }
32023
- const staticChild = this.findStaticMatchingChild(path, pathIndex);
32023
+ const staticChild = this.findStaticMatchingChild(path2, pathIndex);
32024
32024
  if (staticChild) {
32025
- return staticChild.getStaticChild(path, pathIndex + staticChild.prefix.length);
32025
+ return staticChild.getStaticChild(path2, pathIndex + staticChild.prefix.length);
32026
32026
  }
32027
32027
  return null;
32028
32028
  }
32029
- createStaticChild(path) {
32030
- if (path.length === 0) {
32029
+ createStaticChild(path2) {
32030
+ if (path2.length === 0) {
32031
32031
  return this;
32032
32032
  }
32033
- const childIndex = this.staticChildrenCharCodes.indexOf(path.charCodeAt(0));
32033
+ const childIndex = this.staticChildrenCharCodes.indexOf(path2.charCodeAt(0));
32034
32034
  let staticChild = childIndex === -1 ? void 0 : this.staticChildrenNodes[childIndex];
32035
32035
  if (staticChild) {
32036
32036
  let i = 1;
32037
32037
  for (; i < staticChild.prefix.length; i++) {
32038
- if (path.charCodeAt(i) !== staticChild.prefix.charCodeAt(i)) {
32038
+ if (path2.charCodeAt(i) !== staticChild.prefix.charCodeAt(i)) {
32039
32039
  staticChild = staticChild.split(this, i);
32040
32040
  break;
32041
32041
  }
32042
32042
  }
32043
- return staticChild.createStaticChild(path.slice(i));
32043
+ return staticChild.createStaticChild(path2.slice(i));
32044
32044
  }
32045
- const node = new StaticNode(path);
32046
- this.setStaticChild(path.charAt(0), node);
32045
+ const node = new StaticNode(path2);
32046
+ this.setStaticChild(path2.charAt(0), node);
32047
32047
  return node;
32048
32048
  }
32049
32049
  };
@@ -32103,8 +32103,8 @@ var require_node = __commonJS({
32103
32103
  parentNode.setStaticChild(parentPrefix.charAt(0), staticNode);
32104
32104
  return staticNode;
32105
32105
  }
32106
- getNextNode(path, pathIndex, nodeStack, paramsCount) {
32107
- let node = this.findStaticMatchingChild(path, pathIndex);
32106
+ getNextNode(path2, pathIndex, nodeStack, paramsCount) {
32107
+ let node = this.findStaticMatchingChild(path2, pathIndex);
32108
32108
  let parametricBrotherNodeIndex = 0;
32109
32109
  if (node === null) {
32110
32110
  if (this.parametricChildren.length === 0) {
@@ -32151,8 +32151,8 @@ var require_node = __commonJS({
32151
32151
  this.kind = NODE_TYPES.PARAMETRIC;
32152
32152
  this.nodePaths = /* @__PURE__ */ new Set([nodePath]);
32153
32153
  }
32154
- getNextNode(path, pathIndex) {
32155
- return this.findStaticMatchingChild(path, pathIndex);
32154
+ getNextNode(path2, pathIndex) {
32155
+ return this.findStaticMatchingChild(path2, pathIndex);
32156
32156
  }
32157
32157
  };
32158
32158
  var WildcardNode = class extends Node {
@@ -32508,81 +32508,81 @@ var require_url_sanitizer = __commonJS({
32508
32508
  return String.fromCharCode(charCode);
32509
32509
  }
32510
32510
  var MIN_NATIVE_SCAN_LENGTH = 12;
32511
- function safeDecodeURI(path, useSemicolonDelimiter) {
32512
- if (path.length >= MIN_NATIVE_SCAN_LENGTH) {
32513
- return safeDecodeURINativeScan(path, useSemicolonDelimiter);
32511
+ function safeDecodeURI(path2, useSemicolonDelimiter) {
32512
+ if (path2.length >= MIN_NATIVE_SCAN_LENGTH) {
32513
+ return safeDecodeURINativeScan(path2, useSemicolonDelimiter);
32514
32514
  }
32515
- return safeDecodeURICharScan(path, useSemicolonDelimiter, 1);
32515
+ return safeDecodeURICharScan(path2, useSemicolonDelimiter, 1);
32516
32516
  }
32517
- function safeDecodeURINativeScan(path, useSemicolonDelimiter) {
32518
- const percentIndex = path.indexOf("%", 1);
32519
- let delimIndex = path.indexOf("?", 1);
32520
- const hashIndex = path.indexOf("#", 1);
32517
+ function safeDecodeURINativeScan(path2, useSemicolonDelimiter) {
32518
+ const percentIndex = path2.indexOf("%", 1);
32519
+ let delimIndex = path2.indexOf("?", 1);
32520
+ const hashIndex = path2.indexOf("#", 1);
32521
32521
  if (hashIndex !== -1 && (delimIndex === -1 || hashIndex < delimIndex)) {
32522
32522
  delimIndex = hashIndex;
32523
32523
  }
32524
32524
  if (useSemicolonDelimiter) {
32525
- const semicolonIndex = path.indexOf(";", 1);
32525
+ const semicolonIndex = path2.indexOf(";", 1);
32526
32526
  if (semicolonIndex !== -1 && (delimIndex === -1 || semicolonIndex < delimIndex)) {
32527
32527
  delimIndex = semicolonIndex;
32528
32528
  }
32529
32529
  }
32530
32530
  if (percentIndex === -1 || delimIndex !== -1 && percentIndex > delimIndex) {
32531
32531
  if (delimIndex === -1) {
32532
- return { path, querystring: "", shouldDecodeParam: false };
32532
+ return { path: path2, querystring: "", shouldDecodeParam: false };
32533
32533
  }
32534
32534
  return {
32535
- path: path.slice(0, delimIndex),
32536
- querystring: path.slice(delimIndex + 1),
32535
+ path: path2.slice(0, delimIndex),
32536
+ querystring: path2.slice(delimIndex + 1),
32537
32537
  shouldDecodeParam: false
32538
32538
  };
32539
32539
  }
32540
- return safeDecodeURIPercentScan(path, useSemicolonDelimiter, percentIndex);
32540
+ return safeDecodeURIPercentScan(path2, useSemicolonDelimiter, percentIndex);
32541
32541
  }
32542
- function safeDecodeURICharScan(path, useSemicolonDelimiter, startIndex) {
32543
- for (let i = startIndex; i < path.length; i++) {
32544
- const charCode = path.charCodeAt(i);
32542
+ function safeDecodeURICharScan(path2, useSemicolonDelimiter, startIndex) {
32543
+ for (let i = startIndex; i < path2.length; i++) {
32544
+ const charCode = path2.charCodeAt(i);
32545
32545
  if (charCode === 37) {
32546
- return safeDecodeURIPercentScan(path, useSemicolonDelimiter, i);
32546
+ return safeDecodeURIPercentScan(path2, useSemicolonDelimiter, i);
32547
32547
  } else if (charCode === 63 || charCode === 35 || charCode === 59 && useSemicolonDelimiter) {
32548
32548
  return {
32549
- path: path.slice(0, i),
32550
- querystring: path.slice(i + 1),
32549
+ path: path2.slice(0, i),
32550
+ querystring: path2.slice(i + 1),
32551
32551
  shouldDecodeParam: false
32552
32552
  };
32553
32553
  }
32554
32554
  }
32555
- return { path, querystring: "", shouldDecodeParam: false };
32555
+ return { path: path2, querystring: "", shouldDecodeParam: false };
32556
32556
  }
32557
- function reencodePercentChar(path, index) {
32558
- return path.slice(0, index + 1) + "25" + path.slice(index + 1);
32557
+ function reencodePercentChar(path2, index) {
32558
+ return path2.slice(0, index + 1) + "25" + path2.slice(index + 1);
32559
32559
  }
32560
- function safeDecodeURIPercentScan(path, useSemicolonDelimiter, startIndex) {
32560
+ function safeDecodeURIPercentScan(path2, useSemicolonDelimiter, startIndex) {
32561
32561
  let shouldDecode = false;
32562
32562
  let shouldDecodeParam = false;
32563
32563
  let querystring = "";
32564
- for (let i = startIndex; i < path.length; i++) {
32565
- const charCode = path.charCodeAt(i);
32564
+ for (let i = startIndex; i < path2.length; i++) {
32565
+ const charCode = path2.charCodeAt(i);
32566
32566
  if (charCode === 37) {
32567
- const componentCharCode = decodeComponentCharCode(path.charCodeAt(i + 1), path.charCodeAt(i + 2));
32567
+ const componentCharCode = decodeComponentCharCode(path2.charCodeAt(i + 1), path2.charCodeAt(i + 2));
32568
32568
  if (componentCharCode === 0) {
32569
32569
  shouldDecode = true;
32570
32570
  } else {
32571
32571
  shouldDecodeParam = true;
32572
32572
  if (componentCharCode === 37) {
32573
32573
  shouldDecode = true;
32574
- path = reencodePercentChar(path, i);
32574
+ path2 = reencodePercentChar(path2, i);
32575
32575
  i += 2;
32576
32576
  }
32577
32577
  i += 2;
32578
32578
  }
32579
32579
  } else if (charCode === 63 || charCode === 35 || charCode === 59 && useSemicolonDelimiter) {
32580
- querystring = path.slice(i + 1);
32581
- path = path.slice(0, i);
32580
+ querystring = path2.slice(i + 1);
32581
+ path2 = path2.slice(0, i);
32582
32582
  break;
32583
32583
  }
32584
32584
  }
32585
- const decodedPath = shouldDecode ? decodeURI(path) : path;
32585
+ const decodedPath = shouldDecode ? decodeURI(path2) : path2;
32586
32586
  return { path: decodedPath, querystring, shouldDecodeParam };
32587
32587
  }
32588
32588
  function safeDecodeURIComponent(uriComponent) {
@@ -32677,7 +32677,7 @@ var require_find_my_way = __commonJS({
32677
32677
  this.trees = /* @__PURE__ */ Object.create(null);
32678
32678
  this._treeGET = null;
32679
32679
  }
32680
- Router.prototype.on = function on2(method, path, opts, handler, store) {
32680
+ Router.prototype.on = function on2(method, path2, opts, handler, store) {
32681
32681
  if (typeof opts === "function") {
32682
32682
  if (handler !== void 0) {
32683
32683
  store = handler;
@@ -32685,34 +32685,34 @@ var require_find_my_way = __commonJS({
32685
32685
  handler = opts;
32686
32686
  opts = {};
32687
32687
  }
32688
- assert(typeof path === "string", "Path should be a string");
32689
- assert(path.length > 0, "The path could not be empty");
32690
- assert(path[0] === "/" || path[0] === "*", "The first character of a path should be `/` or `*`");
32688
+ assert(typeof path2 === "string", "Path should be a string");
32689
+ assert(path2.length > 0, "The path could not be empty");
32690
+ assert(path2[0] === "/" || path2[0] === "*", "The first character of a path should be `/` or `*`");
32691
32691
  assert(typeof handler === "function", "Handler should be a function");
32692
- const optionalParamMatch = path.match(OPTIONAL_PARAM_REGEXP);
32692
+ const optionalParamMatch = path2.match(OPTIONAL_PARAM_REGEXP);
32693
32693
  if (optionalParamMatch) {
32694
- assert(path.length === optionalParamMatch.index + optionalParamMatch[0].length, "Optional Parameter needs to be the last parameter of the path");
32695
- const pathFull = path.replace(OPTIONAL_PARAM_REGEXP, "$1$2");
32696
- const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, "$2") || "/";
32694
+ assert(path2.length === optionalParamMatch.index + optionalParamMatch[0].length, "Optional Parameter needs to be the last parameter of the path");
32695
+ const pathFull = path2.replace(OPTIONAL_PARAM_REGEXP, "$1$2");
32696
+ const pathOptional = path2.replace(OPTIONAL_PARAM_REGEXP, "$2") || "/";
32697
32697
  this.on(method, pathFull, opts, handler, store);
32698
32698
  this.on(method, pathOptional, opts, handler, store);
32699
32699
  return;
32700
32700
  }
32701
- const route = path;
32701
+ const route = path2;
32702
32702
  if (this.ignoreDuplicateSlashes) {
32703
- path = removeDuplicateSlashes(path);
32703
+ path2 = removeDuplicateSlashes(path2);
32704
32704
  }
32705
32705
  if (this.ignoreTrailingSlash) {
32706
- path = trimLastSlash(path);
32706
+ path2 = trimLastSlash(path2);
32707
32707
  }
32708
32708
  const methods = Array.isArray(method) ? method : [method];
32709
32709
  for (const method2 of methods) {
32710
32710
  assert(typeof method2 === "string", "Method should be a string");
32711
32711
  assert(httpMethods.includes(method2), `Method '${method2}' is not an http method.`);
32712
- this._on(method2, path, opts, handler, store, route);
32712
+ this._on(method2, path2, opts, handler, store, route);
32713
32713
  }
32714
32714
  };
32715
- Router.prototype._on = function _on(method, path, opts, handler, store) {
32715
+ Router.prototype._on = function _on(method, path2, opts, handler, store) {
32716
32716
  let constraints = {};
32717
32717
  if (opts.constraints !== void 0) {
32718
32718
  assert(typeof opts.constraints === "object" && opts.constraints !== null, "Constraints should be an object");
@@ -32725,7 +32725,7 @@ var require_find_my_way = __commonJS({
32725
32725
  if (this.trees[method] === void 0) {
32726
32726
  this.trees[method] = new StaticNode("/");
32727
32727
  }
32728
- let pattern = path;
32728
+ let pattern = path2;
32729
32729
  if (pattern === "*" && this.trees[method].prefix.length !== 0) {
32730
32730
  const currentRoot = this.trees[method];
32731
32731
  this.trees[method] = new StaticNode("");
@@ -32833,19 +32833,19 @@ var require_find_my_way = __commonJS({
32833
32833
  throw new Error(`Method '${method}' already declared for route '${pattern}' with constraints '${JSON.stringify(constraints)}'`);
32834
32834
  }
32835
32835
  }
32836
- const route = { method, path, pattern, params, opts, handler, store };
32836
+ const route = { method, path: path2, pattern, params, opts, handler, store };
32837
32837
  this.routes.push(route);
32838
32838
  currentNode.addRoute(route, this.constrainer);
32839
32839
  };
32840
- Router.prototype.hasRoute = function hasRoute(method, path, constraints) {
32841
- const route = this.findRoute(method, path, constraints);
32840
+ Router.prototype.hasRoute = function hasRoute(method, path2, constraints) {
32841
+ const route = this.findRoute(method, path2, constraints);
32842
32842
  return route !== null;
32843
32843
  };
32844
- Router.prototype.findRoute = function findNode(method, path, constraints = {}) {
32844
+ Router.prototype.findRoute = function findNode(method, path2, constraints = {}) {
32845
32845
  if (this.trees[method] === void 0) {
32846
32846
  return null;
32847
32847
  }
32848
- let pattern = path;
32848
+ let pattern = path2;
32849
32849
  let currentNode = this.trees[method];
32850
32850
  let parentNodePathIndex = currentNode.prefix.length;
32851
32851
  const params = [];
@@ -32966,39 +32966,39 @@ var require_find_my_way = __commonJS({
32966
32966
  this._treeGET = null;
32967
32967
  this.routes = [];
32968
32968
  };
32969
- Router.prototype.off = function off(method, path, constraints) {
32970
- assert(typeof path === "string", "Path should be a string");
32971
- assert(path.length > 0, "The path could not be empty");
32972
- assert(path[0] === "/" || path[0] === "*", "The first character of a path should be `/` or `*`");
32969
+ Router.prototype.off = function off(method, path2, constraints) {
32970
+ assert(typeof path2 === "string", "Path should be a string");
32971
+ assert(path2.length > 0, "The path could not be empty");
32972
+ assert(path2[0] === "/" || path2[0] === "*", "The first character of a path should be `/` or `*`");
32973
32973
  assert(
32974
32974
  typeof constraints === "undefined" || typeof constraints === "object" && !Array.isArray(constraints) && constraints !== null,
32975
32975
  "Constraints should be an object or undefined."
32976
32976
  );
32977
- const optionalParamMatch = path.match(OPTIONAL_PARAM_REGEXP);
32977
+ const optionalParamMatch = path2.match(OPTIONAL_PARAM_REGEXP);
32978
32978
  if (optionalParamMatch) {
32979
- assert(path.length === optionalParamMatch.index + optionalParamMatch[0].length, "Optional Parameter needs to be the last parameter of the path");
32980
- const pathFull = path.replace(OPTIONAL_PARAM_REGEXP, "$1$2");
32981
- const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, "$2") || "/";
32979
+ assert(path2.length === optionalParamMatch.index + optionalParamMatch[0].length, "Optional Parameter needs to be the last parameter of the path");
32980
+ const pathFull = path2.replace(OPTIONAL_PARAM_REGEXP, "$1$2");
32981
+ const pathOptional = path2.replace(OPTIONAL_PARAM_REGEXP, "$2") || "/";
32982
32982
  this.off(method, pathFull, constraints);
32983
32983
  this.off(method, pathOptional, constraints);
32984
32984
  return;
32985
32985
  }
32986
32986
  if (this.ignoreDuplicateSlashes) {
32987
- path = removeDuplicateSlashes(path);
32987
+ path2 = removeDuplicateSlashes(path2);
32988
32988
  }
32989
32989
  if (this.ignoreTrailingSlash) {
32990
- path = trimLastSlash(path);
32990
+ path2 = trimLastSlash(path2);
32991
32991
  }
32992
32992
  const methods = Array.isArray(method) ? method : [method];
32993
32993
  for (const method2 of methods) {
32994
- this._off(method2, path, constraints);
32994
+ this._off(method2, path2, constraints);
32995
32995
  }
32996
32996
  };
32997
- Router.prototype._off = function _off(method, path, constraints) {
32997
+ Router.prototype._off = function _off(method, path2, constraints) {
32998
32998
  assert(typeof method === "string", "Method should be a string");
32999
32999
  assert(httpMethods.includes(method), `Method '${method}' is not an http method.`);
33000
33000
  function matcherWithoutConstraints(route) {
33001
- return method !== route.method || path !== route.path;
33001
+ return method !== route.method || path2 !== route.path;
33002
33002
  }
33003
33003
  function matcherWithConstraints(route) {
33004
33004
  return matcherWithoutConstraints(route) || !deepEqual(constraints, route.opts.constraints || {});
@@ -33035,37 +33035,37 @@ var require_find_my_way = __commonJS({
33035
33035
  if (handle === null) return this._defaultRoute(req, res, ctx);
33036
33036
  return ctx === void 0 ? handle.handler(req, res, handle.params, handle.store, handle.searchParams) : handle.handler.call(ctx, req, res, handle.params, handle.store, handle.searchParams);
33037
33037
  };
33038
- Router.prototype.find = function find(method, path, derivedConstraints) {
33038
+ Router.prototype.find = function find(method, path2, derivedConstraints) {
33039
33039
  let currentNode = method === "GET" ? this._treeGET : this.trees[method];
33040
33040
  if (currentNode == null) return null;
33041
- if (path.charCodeAt(0) !== 47) {
33042
- path = path.replace(FULL_PATH_REGEXP, "/");
33041
+ if (path2.charCodeAt(0) !== 47) {
33042
+ path2 = path2.replace(FULL_PATH_REGEXP, "/");
33043
33043
  }
33044
33044
  if (this.ignoreDuplicateSlashes) {
33045
- path = removeDuplicateSlashes(path);
33045
+ path2 = removeDuplicateSlashes(path2);
33046
33046
  }
33047
33047
  let sanitizedUrl;
33048
33048
  let querystring2;
33049
33049
  let shouldDecodeParam;
33050
33050
  try {
33051
- sanitizedUrl = path.length >= MIN_NATIVE_SCAN_LENGTH ? safeDecodeURINativeScan(path, this.useSemicolonDelimiter) : safeDecodeURICharScan(path, this.useSemicolonDelimiter, 1);
33052
- path = sanitizedUrl.path;
33051
+ sanitizedUrl = path2.length >= MIN_NATIVE_SCAN_LENGTH ? safeDecodeURINativeScan(path2, this.useSemicolonDelimiter) : safeDecodeURICharScan(path2, this.useSemicolonDelimiter, 1);
33052
+ path2 = sanitizedUrl.path;
33053
33053
  querystring2 = sanitizedUrl.querystring;
33054
33054
  shouldDecodeParam = sanitizedUrl.shouldDecodeParam;
33055
33055
  } catch (error) {
33056
- return this._onBadUrl(path);
33056
+ return this._onBadUrl(path2);
33057
33057
  }
33058
33058
  if (this.ignoreTrailingSlash) {
33059
- path = trimLastSlash(path);
33059
+ path2 = trimLastSlash(path2);
33060
33060
  }
33061
- const originPath = path;
33061
+ const originPath = path2;
33062
33062
  if (this.caseSensitive === false) {
33063
- path = path.toLowerCase();
33063
+ path2 = path2.toLowerCase();
33064
33064
  }
33065
33065
  const maxParamLength = this.maxParamLength;
33066
33066
  let pathIndex = currentNode.prefix.length;
33067
33067
  const params = [];
33068
- const pathLen = path.length;
33068
+ const pathLen = path2.length;
33069
33069
  const brothersNodesStack = [];
33070
33070
  let maxParamLengthExceeded = false;
33071
33071
  while (true) {
@@ -33080,7 +33080,7 @@ var require_find_my_way = __commonJS({
33080
33080
  };
33081
33081
  }
33082
33082
  }
33083
- let node = currentNode.getNextNode(path, pathIndex, brothersNodesStack, params.length);
33083
+ let node = currentNode.getNextNode(path2, pathIndex, brothersNodesStack, params.length);
33084
33084
  if (node === null) {
33085
33085
  if (brothersNodesStack.length === 0) {
33086
33086
  if (maxParamLengthExceeded && this.onMaxParamLength) {
@@ -33181,8 +33181,8 @@ var require_find_my_way = __commonJS({
33181
33181
  Router.prototype._rebuild = function(routes) {
33182
33182
  this.reset();
33183
33183
  for (const route of routes) {
33184
- const { method, path, opts, handler, store } = route;
33185
- this._on(method, path, opts, handler, store);
33184
+ const { method, path: path2, opts, handler, store } = route;
33185
+ this._on(method, path2, opts, handler, store);
33186
33186
  }
33187
33187
  };
33188
33188
  Router.prototype._defaultRoute = function(req, res, ctx) {
@@ -33193,24 +33193,24 @@ var require_find_my_way = __commonJS({
33193
33193
  res.end();
33194
33194
  }
33195
33195
  };
33196
- Router.prototype._onBadUrl = function(path) {
33196
+ Router.prototype._onBadUrl = function(path2) {
33197
33197
  if (this.onBadUrl === null) {
33198
33198
  return null;
33199
33199
  }
33200
33200
  const onBadUrl = this.onBadUrl;
33201
33201
  return {
33202
- handler: (req, res, ctx) => onBadUrl(path, req, res),
33202
+ handler: (req, res, ctx) => onBadUrl(path2, req, res),
33203
33203
  params: {},
33204
33204
  store: null
33205
33205
  };
33206
33206
  };
33207
- Router.prototype._onMaxParamLength = function(path) {
33207
+ Router.prototype._onMaxParamLength = function(path2) {
33208
33208
  if (this.onMaxParamLength === null) {
33209
33209
  return null;
33210
33210
  }
33211
33211
  const onMaxParamLength = this.onMaxParamLength;
33212
33212
  return {
33213
- handler: (req, res, ctx) => onMaxParamLength(path, req, res),
33213
+ handler: (req, res, ctx) => onMaxParamLength(path2, req, res),
33214
33214
  params: {},
33215
33215
  store: null
33216
33216
  };
@@ -33242,12 +33242,12 @@ var require_find_my_way = __commonJS({
33242
33242
  if (!httpMethods.hasOwnProperty(i)) continue;
33243
33243
  const m = httpMethods[i];
33244
33244
  const methodName = m.toLowerCase();
33245
- Router.prototype[methodName] = function(path, handler, store) {
33246
- return this.on(m, path, handler, store);
33245
+ Router.prototype[methodName] = function(path2, handler, store) {
33246
+ return this.on(m, path2, handler, store);
33247
33247
  };
33248
33248
  }
33249
- Router.prototype.all = function(path, handler, store) {
33250
- this.on(httpMethods, path, handler, store);
33249
+ Router.prototype.all = function(path2, handler, store) {
33250
+ this.on(httpMethods, path2, handler, store);
33251
33251
  };
33252
33252
  Router.sanitizeUrlPath = function sanitizeUrlPath(url, useSemicolonDelimiter) {
33253
33253
  const decoded = safeDecodeURI(url, useSemicolonDelimiter);
@@ -33262,14 +33262,14 @@ var require_find_my_way = __commonJS({
33262
33262
  function escapeRegExp(string) {
33263
33263
  return string.replace(ESCAPE_REGEXP, "\\$&");
33264
33264
  }
33265
- function removeDuplicateSlashes(path) {
33266
- return path.indexOf("//") !== -1 ? path.replace(REMOVE_DUPLICATE_SLASHES_REGEXP, "/") : path;
33265
+ function removeDuplicateSlashes(path2) {
33266
+ return path2.indexOf("//") !== -1 ? path2.replace(REMOVE_DUPLICATE_SLASHES_REGEXP, "/") : path2;
33267
33267
  }
33268
- function trimLastSlash(path) {
33269
- if (path.length > 1 && path.charCodeAt(path.length - 1) === 47) {
33270
- return path.slice(0, -1);
33268
+ function trimLastSlash(path2) {
33269
+ if (path2.length > 1 && path2.charCodeAt(path2.length - 1) === 47) {
33270
+ return path2.slice(0, -1);
33271
33271
  }
33272
- return path;
33272
+ return path2;
33273
33273
  }
33274
33274
  function trimRegExpStartAndEnd(regexString) {
33275
33275
  if (regexString.charCodeAt(1) === 94) {
@@ -33280,22 +33280,22 @@ var require_find_my_way = __commonJS({
33280
33280
  }
33281
33281
  return regexString;
33282
33282
  }
33283
- function getClosingParenthensePosition(path, idx) {
33283
+ function getClosingParenthensePosition(path2, idx) {
33284
33284
  let parentheses = 1;
33285
- while (idx < path.length) {
33285
+ while (idx < path2.length) {
33286
33286
  idx++;
33287
- if (path.charCodeAt(idx) === 92) {
33287
+ if (path2.charCodeAt(idx) === 92) {
33288
33288
  idx++;
33289
33289
  continue;
33290
33290
  }
33291
- if (path.charCodeAt(idx) === 41) {
33291
+ if (path2.charCodeAt(idx) === 41) {
33292
33292
  parentheses--;
33293
- } else if (path.charCodeAt(idx) === 40) {
33293
+ } else if (path2.charCodeAt(idx) === 40) {
33294
33294
  parentheses++;
33295
33295
  }
33296
33296
  if (!parentheses) return idx;
33297
33297
  }
33298
- throw new TypeError('Invalid regexp expression in "' + path + '"');
33298
+ throw new TypeError('Invalid regexp expression in "' + path2 + '"');
33299
33299
  }
33300
33300
  function defaultBuildPrettyMeta(route) {
33301
33301
  if (!route) return {};
@@ -33528,12 +33528,12 @@ var require_route = __commonJS({
33528
33528
  function route({ options: options2, isFastify }) {
33529
33529
  throwIfAlreadyStarted("Cannot add route!");
33530
33530
  const opts = { ...options2 };
33531
- const path = opts.url || opts.path || "";
33531
+ const path2 = opts.url || opts.path || "";
33532
33532
  if (!opts.handler) {
33533
- throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path);
33533
+ throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path2);
33534
33534
  }
33535
33535
  if (opts.errorHandler !== void 0 && typeof opts.errorHandler !== "function") {
33536
- throw new FST_ERR_ROUTE_HANDLER_NOT_FN(opts.method, path);
33536
+ throw new FST_ERR_ROUTE_HANDLER_NOT_FN(opts.method, path2);
33537
33537
  }
33538
33538
  validateBodyLimitOption(opts.bodyLimit);
33539
33539
  validateHandlerTimeoutOption(opts.handlerTimeout);
@@ -33543,22 +33543,22 @@ var require_route = __commonJS({
33543
33543
  if (Array.isArray(opts.method)) {
33544
33544
  for (let i = 0; i < opts.method.length; ++i) {
33545
33545
  opts.method[i] = normalizeAndValidateMethod.call(this, opts.method[i]);
33546
- validateSchemaBodyOption.call(this, opts.method[i], path, opts.schema);
33546
+ validateSchemaBodyOption.call(this, opts.method[i], path2, opts.schema);
33547
33547
  isGetRoute = opts.method.includes("GET");
33548
33548
  isHeadRoute = opts.method.includes("HEAD");
33549
33549
  }
33550
33550
  } else {
33551
33551
  opts.method = normalizeAndValidateMethod.call(this, opts.method);
33552
- validateSchemaBodyOption.call(this, opts.method, path, opts.schema);
33552
+ validateSchemaBodyOption.call(this, opts.method, path2, opts.schema);
33553
33553
  isGetRoute = opts.method === "GET";
33554
33554
  isHeadRoute = opts.method === "HEAD";
33555
33555
  }
33556
33556
  const headOpts = shouldExposeHead && isGetRoute ? { ...options2 } : null;
33557
33557
  const prefix = this[kRoutePrefix];
33558
- if (path === "/" && prefix.length > 0 && opts.method !== "HEAD") {
33558
+ if (path2 === "/" && prefix.length > 0 && opts.method !== "HEAD") {
33559
33559
  switch (opts.prefixTrailingSlash) {
33560
33560
  case "slash":
33561
- addNewRoute.call(this, { path, isFastify });
33561
+ addNewRoute.call(this, { path: path2, isFastify });
33562
33562
  break;
33563
33563
  case "no-slash":
33564
33564
  addNewRoute.call(this, { path: "", isFastify });
@@ -33567,20 +33567,20 @@ var require_route = __commonJS({
33567
33567
  default:
33568
33568
  addNewRoute.call(this, { path: "", isFastify });
33569
33569
  if (ignoreTrailingSlash !== true && (ignoreDuplicateSlashes !== true || !prefix.endsWith("/"))) {
33570
- addNewRoute.call(this, { path, prefixing: true, isFastify });
33570
+ addNewRoute.call(this, { path: path2, prefixing: true, isFastify });
33571
33571
  }
33572
33572
  }
33573
- } else if (path[0] === "/" && prefix.endsWith("/")) {
33574
- addNewRoute.call(this, { path: path.slice(1), isFastify });
33573
+ } else if (path2[0] === "/" && prefix.endsWith("/")) {
33574
+ addNewRoute.call(this, { path: path2.slice(1), isFastify });
33575
33575
  } else {
33576
- addNewRoute.call(this, { path, isFastify });
33576
+ addNewRoute.call(this, { path: path2, isFastify });
33577
33577
  }
33578
33578
  return this;
33579
- function addNewRoute({ path: path2, prefixing = false, isFastify: isFastify2 = false }) {
33580
- const url = prefix + path2;
33579
+ function addNewRoute({ path: path3, prefixing = false, isFastify: isFastify2 = false }) {
33580
+ const url = prefix + path3;
33581
33581
  opts.url = url;
33582
33582
  opts.path = url;
33583
- opts.routePath = path2;
33583
+ opts.routePath = path3;
33584
33584
  opts.prefix = prefix;
33585
33585
  opts.logLevel = opts.logLevel || this[kLogLevel];
33586
33586
  validateLogLevelOption(opts.logLevel, opts.method, opts.url, logger);
@@ -33712,7 +33712,7 @@ var require_route = __commonJS({
33712
33712
  });
33713
33713
  if (shouldExposeHead && isGetRoute && !isHeadRoute && !hasHEADHandler) {
33714
33714
  const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend);
33715
- prepareRoute.call(this, { method: "HEAD", url: path2, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true });
33715
+ prepareRoute.call(this, { method: "HEAD", url: path3, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true });
33716
33716
  }
33717
33717
  }
33718
33718
  }
@@ -33836,9 +33836,9 @@ var require_route = __commonJS({
33836
33836
  }
33837
33837
  return method;
33838
33838
  }
33839
- function validateSchemaBodyOption(method, path, schema) {
33839
+ function validateSchemaBodyOption(method, path2, schema) {
33840
33840
  if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {
33841
- throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path);
33841
+ throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path2);
33842
33842
  }
33843
33843
  }
33844
33844
  function validateBodyLimitOption(bodyLimit) {
@@ -33853,11 +33853,11 @@ var require_route = __commonJS({
33853
33853
  throw new FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT(handlerTimeout);
33854
33854
  }
33855
33855
  }
33856
- function validateLogLevelOption(logLevel, method, path, logger) {
33856
+ function validateLogLevelOption(logLevel, method, path2, logger) {
33857
33857
  if (logLevel == null || logLevel === "") return;
33858
33858
  if (logger?.levels?.values == null) return;
33859
33859
  if (typeof logLevel !== "string" || logger.levels.values[logLevel] === void 0) {
33860
- throw new FST_ERR_ROUTE_LOG_LEVEL_INVALID(method, path, logLevel);
33860
+ throw new FST_ERR_ROUTE_LOG_LEVEL_INVALID(method, path2, logLevel);
33861
33861
  }
33862
33862
  }
33863
33863
  function runPreParsing(err, request, reply) {
@@ -33946,7 +33946,7 @@ var require_four_oh_four = __commonJS({
33946
33946
  });
33947
33947
  }
33948
33948
  function createRouteEventHandler() {
33949
- return function onRouteEvent(path, req, res) {
33949
+ return function onRouteEvent(path2, req, res) {
33950
33950
  const fourOhFourContext = this[kFourOhFourLevelInstance][kFourOhFourContext];
33951
33951
  const id2 = getGenReqId(fourOhFourContext.server, req);
33952
33952
  const childLogger = createChildLogger(fourOhFourContext, logger, req, id2);
@@ -36617,19 +36617,19 @@ var require_fastify = __commonJS({
36617
36617
  }
36618
36618
  fourOhFour.router.lookup(req, res);
36619
36619
  }
36620
- function onBadUrl(path, req, res) {
36620
+ function onBadUrl(path2, req, res) {
36621
36621
  if (options.frameworkErrors) {
36622
36622
  const id2 = getGenReqId(routeEventContext.server, req);
36623
36623
  const childLogger = createChildLogger(routeEventContext, options.logger, req, id2);
36624
36624
  const request = new Request(id2, null, req, null, childLogger, routeEventContext);
36625
36625
  const reply = new Reply(res, request, childLogger);
36626
36626
  routeEventContext.server[kLogController].incomingRequest(request, reply);
36627
- return options.frameworkErrors(new FST_ERR_BAD_URL(path), request, reply);
36627
+ return options.frameworkErrors(new FST_ERR_BAD_URL(path2), request, reply);
36628
36628
  }
36629
36629
  const body = JSON.stringify({
36630
36630
  error: "Bad Request",
36631
36631
  code: "FST_ERR_BAD_URL",
36632
- message: `'${path}' is not a valid url component`,
36632
+ message: `'${path2}' is not a valid url component`,
36633
36633
  statusCode: 400
36634
36634
  });
36635
36635
  res.writeHead(400, {
@@ -36638,19 +36638,19 @@ var require_fastify = __commonJS({
36638
36638
  });
36639
36639
  res.end(body);
36640
36640
  }
36641
- function onMaxParamLength(path, req, res) {
36641
+ function onMaxParamLength(path2, req, res) {
36642
36642
  if (options.frameworkErrors) {
36643
36643
  const id2 = getGenReqId(routeEventContext.server, req);
36644
36644
  const childLogger = createChildLogger(routeEventContext, options.logger, req, id2);
36645
36645
  const request = new Request(id2, null, req, null, childLogger, routeEventContext);
36646
36646
  const reply = new Reply(res, request, childLogger);
36647
36647
  routeEventContext.server[kLogController].incomingRequest(request, reply);
36648
- return options.frameworkErrors(new FST_ERR_MAX_PARAM_LENGTH(path), request, reply);
36648
+ return options.frameworkErrors(new FST_ERR_MAX_PARAM_LENGTH(path2), request, reply);
36649
36649
  }
36650
36650
  const body = JSON.stringify({
36651
36651
  error: "Bad Request",
36652
36652
  code: "FST_ERR_MAX_PARAM_LENGTH",
36653
- message: `'${path}' is exceeding the max param length`,
36653
+ message: `'${path2}' is exceeding the max param length`,
36654
36654
  statusCode: 414
36655
36655
  });
36656
36656
  res.writeHead(414, {
@@ -37376,20 +37376,20 @@ var require_file_uri_to_path = __commonJS({
37376
37376
  var rest = decodeURI(uri.substring(7));
37377
37377
  var firstSlash = rest.indexOf("/");
37378
37378
  var host = rest.substring(0, firstSlash);
37379
- var path = rest.substring(firstSlash + 1);
37379
+ var path2 = rest.substring(firstSlash + 1);
37380
37380
  if ("localhost" == host) host = "";
37381
37381
  if (host) {
37382
37382
  host = sep5 + sep5 + host;
37383
37383
  }
37384
- path = path.replace(/^(.+)\|/, "$1:");
37384
+ path2 = path2.replace(/^(.+)\|/, "$1:");
37385
37385
  if (sep5 == "\\") {
37386
- path = path.replace(/\//g, "\\");
37386
+ path2 = path2.replace(/\//g, "\\");
37387
37387
  }
37388
- if (/^.+\:/.test(path)) {
37388
+ if (/^.+\:/.test(path2)) {
37389
37389
  } else {
37390
- path = sep5 + path;
37390
+ path2 = sep5 + path2;
37391
37391
  }
37392
- return host + path;
37392
+ return host + path2;
37393
37393
  }
37394
37394
  }
37395
37395
  });
@@ -37398,18 +37398,18 @@ var require_file_uri_to_path = __commonJS({
37398
37398
  var require_bindings = __commonJS({
37399
37399
  "node_modules/bindings/bindings.js"(exports, module) {
37400
37400
  var fs = __require("fs");
37401
- var path = __require("path");
37401
+ var path2 = __require("path");
37402
37402
  var fileURLToPath = require_file_uri_to_path();
37403
- var join6 = path.join;
37404
- var dirname4 = path.dirname;
37405
- var exists = fs.accessSync && function(path2) {
37403
+ var join6 = path2.join;
37404
+ var dirname4 = path2.dirname;
37405
+ var exists = fs.accessSync && function(path3) {
37406
37406
  try {
37407
- fs.accessSync(path2);
37407
+ fs.accessSync(path3);
37408
37408
  } catch (e) {
37409
37409
  return false;
37410
37410
  }
37411
37411
  return true;
37412
- } || fs.existsSync || path.existsSync;
37412
+ } || fs.existsSync || path2.existsSync;
37413
37413
  var defaults = {
37414
37414
  arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
37415
37415
  compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
@@ -37454,7 +37454,7 @@ var require_bindings = __commonJS({
37454
37454
  if (!opts.module_root) {
37455
37455
  opts.module_root = exports.getRoot(exports.getFileName());
37456
37456
  }
37457
- if (path.extname(opts.bindings) != ".node") {
37457
+ if (path2.extname(opts.bindings) != ".node") {
37458
37458
  opts.bindings += ".node";
37459
37459
  }
37460
37460
  var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
@@ -37693,7 +37693,7 @@ var require_backup = __commonJS({
37693
37693
  "node_modules/better-sqlite3/lib/methods/backup.js"(exports, module) {
37694
37694
  "use strict";
37695
37695
  var fs = __require("fs");
37696
- var path = __require("path");
37696
+ var path2 = __require("path");
37697
37697
  var { promisify: promisify2 } = __require("util");
37698
37698
  var { cppdb } = require_util3();
37699
37699
  var fsAccess = promisify2(fs.access);
@@ -37709,7 +37709,7 @@ var require_backup = __commonJS({
37709
37709
  if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
37710
37710
  if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
37711
37711
  if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
37712
- await fsAccess(path.dirname(filename)).catch(() => {
37712
+ await fsAccess(path2.dirname(filename)).catch(() => {
37713
37713
  throw new TypeError("Cannot save backup because the directory does not exist");
37714
37714
  });
37715
37715
  const isNewFile = await fsAccess(filename).then(() => false, () => true);
@@ -38015,7 +38015,7 @@ var require_database = __commonJS({
38015
38015
  "node_modules/better-sqlite3/lib/database.js"(exports, module) {
38016
38016
  "use strict";
38017
38017
  var fs = __require("fs");
38018
- var path = __require("path");
38018
+ var path2 = __require("path");
38019
38019
  var util = require_util3();
38020
38020
  var SqliteError = require_sqlite_error();
38021
38021
  var DEFAULT_ADDON;
@@ -38051,7 +38051,7 @@ var require_database = __commonJS({
38051
38051
  addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
38052
38052
  } else if (typeof nativeBinding === "string") {
38053
38053
  const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
38054
- addon = requireFunc(path.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
38054
+ addon = requireFunc(path2.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
38055
38055
  } else {
38056
38056
  addon = nativeBinding;
38057
38057
  }
@@ -38059,7 +38059,7 @@ var require_database = __commonJS({
38059
38059
  addon.setErrorConstructor(SqliteError);
38060
38060
  addon.isInitialized = true;
38061
38061
  }
38062
- if (!anonymous && !fs.existsSync(path.dirname(filename))) {
38062
+ if (!anonymous && !fs.existsSync(path2.dirname(filename))) {
38063
38063
  throw new TypeError("Cannot open database because the directory does not exist");
38064
38064
  }
38065
38065
  Object.defineProperties(this, {
@@ -41772,8 +41772,8 @@ var import_cors = __toESM(require_cors(), 1);
41772
41772
  // src/db/index.ts
41773
41773
  var import_better_sqlite3 = __toESM(require_lib2(), 1);
41774
41774
  var db;
41775
- function initDb(path = "data.db") {
41776
- db = new import_better_sqlite3.default(path);
41775
+ function initDb(path2 = "data.db") {
41776
+ db = new import_better_sqlite3.default(path2);
41777
41777
  db.pragma("journal_mode = WAL");
41778
41778
  db.pragma("foreign_keys = ON");
41779
41779
  createTables(db);
@@ -41891,6 +41891,9 @@ function createTables(database) {
41891
41891
  if (!sessColumns.some((c) => c.name === "pre_rewind_thread_id")) {
41892
41892
  database.exec("ALTER TABLE sessions ADD COLUMN pre_rewind_thread_id TEXT");
41893
41893
  }
41894
+ if (!sessColumns.some((c) => c.name === "context_usage")) {
41895
+ database.exec("ALTER TABLE sessions ADD COLUMN context_usage TEXT");
41896
+ }
41894
41897
  const turnColumns = database.prepare("PRAGMA table_info(turns)").all();
41895
41898
  if (!turnColumns.some((c) => c.name === "thread_id")) {
41896
41899
  database.exec("ALTER TABLE turns ADD COLUMN thread_id TEXT");
@@ -42082,6 +42085,13 @@ async function registerSessionRoutes(fastify) {
42082
42085
  turns: detail.turns.filter((t) => t.thread_id === tr.id)
42083
42086
  }));
42084
42087
  }
42088
+ const cuRow = db3.prepare("SELECT context_usage FROM sessions WHERE id = ?").get(id2);
42089
+ if (cuRow?.context_usage) {
42090
+ try {
42091
+ detail.contextUsage = JSON.parse(cuRow.context_usage);
42092
+ } catch {
42093
+ }
42094
+ }
42085
42095
  return detail;
42086
42096
  });
42087
42097
  fastify.post("/api/sessions", {
@@ -42504,11 +42514,20 @@ async function registerThreadRoutes(fastify) {
42504
42514
  const provider = getProvider(session.runtime_type);
42505
42515
  if (provider.forkSession) {
42506
42516
  try {
42507
- const anchorTurn = db3.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
42508
- if (anchorTurn) {
42509
- const forkedSessionId = await provider.forkSession(session, anchorTurn);
42510
- if (forkedSessionId) {
42511
- db3.prepare("UPDATE discussion_threads SET external_thread_id = ? WHERE id = ?").run(forkedSessionId, threadId);
42517
+ if (!session.external_thread_id) {
42518
+ console.warn(`[threads] cannot fork for thread ${threadId}: session ${sessionId} has no external_thread_id \u2014 thread will start a fresh isolated session`);
42519
+ } else {
42520
+ const anchorTurn = db3.prepare("SELECT * FROM turns WHERE id = ?").get(turnId);
42521
+ if (anchorTurn) {
42522
+ const forkedSessionId = await provider.forkSession(session, anchorTurn);
42523
+ if (forkedSessionId) {
42524
+ db3.prepare("UPDATE discussion_threads SET external_thread_id = ? WHERE id = ?").run(forkedSessionId, threadId);
42525
+ console.log(`[threads] forked to ${forkedSessionId} for thread ${threadId} (session ${sessionId})`);
42526
+ } else {
42527
+ console.warn(`[threads] forkSession returned null for thread ${threadId} (external_thread_id=${session.external_thread_id}, upToMessageId=${anchorTurn.external_turn_id}) \u2014 thread will start a fresh isolated session`);
42528
+ }
42529
+ } else {
42530
+ console.warn(`[threads] anchor turn ${turnId} not found for thread ${threadId} \u2014 cannot fork`);
42512
42531
  }
42513
42532
  }
42514
42533
  } catch (err) {
@@ -42690,11 +42709,11 @@ async function registerWorkspaceRoutes(fastify) {
42690
42709
  }
42691
42710
  }
42692
42711
  }, async (request, reply) => {
42693
- const { path, label = null } = request.body || {};
42694
- if (!path || !path.trim()) {
42712
+ const { path: path2, label = null } = request.body || {};
42713
+ if (!path2 || !path2.trim()) {
42695
42714
  return reply.code(400).send({ error: "Path is required" });
42696
42715
  }
42697
- const trimmedPath = path.trim();
42716
+ const trimmedPath = path2.trim();
42698
42717
  const db3 = getDb();
42699
42718
  const existing = db3.prepare("SELECT * FROM workspaces WHERE path = ?").get(trimmedPath);
42700
42719
  if (existing) {
@@ -42722,8 +42741,8 @@ async function registerWorkspaceRoutes(fastify) {
42722
42741
  "-e",
42723
42742
  'POSIX path of (choose folder with prompt "Select a workspace directory")'
42724
42743
  ]);
42725
- const path = stdout.trim().replace(/\/$/, "");
42726
- return { path };
42744
+ const path2 = stdout.trim().replace(/\/$/, "");
42745
+ return { path: path2 };
42727
42746
  } catch {
42728
42747
  return reply.code(204).send({ cancelled: true });
42729
42748
  }
@@ -42739,11 +42758,11 @@ async function registerWorkspaceRoutes(fastify) {
42739
42758
  }
42740
42759
  }
42741
42760
  }, async (request, reply) => {
42742
- const { path } = request.body || {};
42743
- if (!path || !path.trim()) {
42761
+ const { path: path2 } = request.body || {};
42762
+ if (!path2 || !path2.trim()) {
42744
42763
  return reply.code(400).send({ error: "Path is required" });
42745
42764
  }
42746
- const trimmedPath = path.trim();
42765
+ const trimmedPath = path2.trim();
42747
42766
  const db3 = getDb();
42748
42767
  const existing = db3.prepare("SELECT * FROM workspaces WHERE path = ?").get(trimmedPath);
42749
42768
  if (existing) {
@@ -42804,7 +42823,23 @@ var CLAUDE_PROVIDER = {
42804
42823
  fileReferences: true
42805
42824
  }
42806
42825
  };
42807
- var PROVIDERS = [CODEX_PROVIDER, CLAUDE_PROVIDER];
42826
+ var REPOBURG_PROVIDER = {
42827
+ id: "repoburg",
42828
+ label: "Repoburg",
42829
+ available: true,
42830
+ capabilities: {
42831
+ dynamicModels: true,
42832
+ skills: false,
42833
+ plugins: false,
42834
+ mcpServers: false,
42835
+ imageAttachments: false,
42836
+ sandbox: false,
42837
+ webSearch: false,
42838
+ networkAccess: false,
42839
+ fileReferences: false
42840
+ }
42841
+ };
42842
+ var PROVIDERS = [CODEX_PROVIDER, CLAUDE_PROVIDER, REPOBURG_PROVIDER];
42808
42843
  async function registerProviderRoutes(fastify) {
42809
42844
  fastify.get("/api/providers", async () => {
42810
42845
  return PROVIDERS;
@@ -72905,9 +72940,9 @@ function mapToolUse(block) {
72905
72940
  };
72906
72941
  }
72907
72942
  function deriveFileChangeData(input, toolName) {
72908
- const path = input.file_path ?? input.notebook_path ?? "";
72943
+ const path2 = input.file_path ?? input.notebook_path ?? "";
72909
72944
  const kind = toolName === "Write" ? "add" : "modify";
72910
- return { changes: [{ path, kind }], status: "in_progress" };
72945
+ return { changes: [{ path: path2, kind }], status: "in_progress" };
72911
72946
  }
72912
72947
  function extractToolResultText(content) {
72913
72948
  if (!content) return "";
@@ -73052,7 +73087,7 @@ function setSessionStatus2(db3, sessionId, isRunning, status, now, hasUnreviewed
73052
73087
  async function ensureSessionStarted(session, mapKey, resumeSessionId) {
73053
73088
  const db3 = getDb();
73054
73089
  const key = mapKey ?? session.id;
73055
- const resumeId = resumeSessionId ?? session.external_thread_id ?? void 0;
73090
+ const resumeId = mapKey !== void 0 ? resumeSessionId : resumeSessionId ?? session.external_thread_id ?? void 0;
73056
73091
  const options = {
73057
73092
  cwd: session.cwd ?? process.cwd(),
73058
73093
  model: session.model ?? void 0,
@@ -73140,8 +73175,7 @@ async function startTurn2(session, turn) {
73140
73175
  try {
73141
73176
  if (turn.thread_id) {
73142
73177
  const thread = db3.prepare("SELECT external_thread_id FROM discussion_threads WHERE id = ?").get(turn.thread_id);
73143
- const resumeId = thread?.external_thread_id ?? session.external_thread_id ?? void 0;
73144
- entry = await ensureSessionStarted(session, mapKey, resumeId);
73178
+ entry = await ensureSessionStarted(session, mapKey, thread?.external_thread_id ?? void 0);
73145
73179
  } else {
73146
73180
  entry = await ensureSessionStarted(session);
73147
73181
  }
@@ -73154,6 +73188,7 @@ async function startTurn2(session, turn) {
73154
73188
  return;
73155
73189
  }
73156
73190
  }
73191
+ entry.threadId = turn.thread_id ?? null;
73157
73192
  if (entry.turnId) {
73158
73193
  const prevTurn = db3.prepare("SELECT status, token_usage FROM turns WHERE id = ?").get(entry.turnId);
73159
73194
  if (prevTurn && prevTurn.status === "running") {
@@ -73215,12 +73250,14 @@ async function handleMessage(message, sessionId, turnId, entry, db3) {
73215
73250
  const sub = message.subtype;
73216
73251
  if (sub === "init") {
73217
73252
  entry.sessionId = message.session_id;
73218
- const now = (/* @__PURE__ */ new Date()).toISOString();
73219
- db3.prepare("UPDATE sessions SET external_thread_id = ?, updated_at = ? WHERE id = ?").run(
73220
- message.session_id,
73221
- now,
73222
- sessionId
73223
- );
73253
+ if (!entry.threadId) {
73254
+ const now = (/* @__PURE__ */ new Date()).toISOString();
73255
+ db3.prepare("UPDATE sessions SET external_thread_id = ?, updated_at = ? WHERE id = ?").run(
73256
+ message.session_id,
73257
+ now,
73258
+ sessionId
73259
+ );
73260
+ }
73224
73261
  } else if (sub === "compact_boundary") {
73225
73262
  handleCompactBoundary(message, sessionId, turnId, db3);
73226
73263
  } else if (sub === "task_started") {
@@ -73250,7 +73287,7 @@ async function handleMessage(message, sessionId, turnId, entry, db3) {
73250
73287
  break;
73251
73288
  }
73252
73289
  case "result": {
73253
- handleResultMessage(message, sessionId, turnId, db3);
73290
+ handleResultMessage(message, sessionId, turnId, entry, db3);
73254
73291
  break;
73255
73292
  }
73256
73293
  default:
@@ -73500,7 +73537,7 @@ function handleBackgroundTasksChanged(message, sessionId) {
73500
73537
  const m = message;
73501
73538
  broadcast("background_tasks", { sessionId, tasks: m.tasks ?? [] });
73502
73539
  }
73503
- function handleResultMessage(message, sessionId, turnId, db3) {
73540
+ async function handleResultMessage(message, sessionId, turnId, entry, db3) {
73504
73541
  const parentToolUseId = message.parent_tool_use_id ?? null;
73505
73542
  if (parentToolUseId) return;
73506
73543
  if (message.subtype === "success") {
@@ -73512,30 +73549,23 @@ function handleResultMessage(message, sessionId, turnId, db3) {
73512
73549
  turnId
73513
73550
  );
73514
73551
  broadcast("turn:tokenUsage", { sessionId, turnId, usage });
73515
- const result = message;
73516
- const modelUsage = result.modelUsage;
73517
- const session = db3.prepare("SELECT model FROM sessions WHERE id = ?").get(sessionId);
73518
- const sessionModel = session?.model ?? null;
73519
- let modelEntry = void 0;
73520
- if (modelUsage) {
73521
- if (sessionModel && modelUsage[sessionModel]) {
73522
- modelEntry = modelUsage[sessionModel];
73523
- } else {
73524
- modelEntry = Object.values(modelUsage).find(
73525
- (e) => sessionModel && e.canonicalModel === sessionModel
73526
- ) ?? Object.values(modelUsage)[0];
73527
- }
73528
- }
73529
- if (modelEntry && modelEntry.contextWindow > 0) {
73530
- const totalTokens = result.usage.input_tokens + (result.usage.cache_read_input_tokens ?? 0) + (result.usage.cache_creation_input_tokens ?? 0);
73531
- if (totalTokens > 0) {
73552
+ try {
73553
+ const ctx = await entry.query.getContextUsage();
73554
+ if (ctx.totalTokens > 0 && ctx.maxTokens > 0) {
73532
73555
  const contextUsage = {
73533
- totalTokens,
73534
- contextWindow: modelEntry.contextWindow,
73535
- percentage: Math.round(totalTokens / modelEntry.contextWindow * 100)
73556
+ totalTokens: ctx.totalTokens,
73557
+ contextWindow: ctx.maxTokens,
73558
+ percentage: Math.round(ctx.percentage)
73536
73559
  };
73537
73560
  broadcast("turn:contextUsage", { sessionId, ...contextUsage });
73561
+ const cuNow = (/* @__PURE__ */ new Date()).toISOString();
73562
+ db3.prepare("UPDATE sessions SET context_usage = ?, updated_at = ? WHERE id = ?").run(
73563
+ JSON.stringify(contextUsage),
73564
+ cuNow,
73565
+ sessionId
73566
+ );
73538
73567
  }
73568
+ } catch {
73539
73569
  }
73540
73570
  completeTurn(db3, sessionId, turnId, usage);
73541
73571
  } else {
@@ -73793,15 +73823,1138 @@ var claudeProvider = {
73793
73823
  shutdown: shutdown2
73794
73824
  };
73795
73825
 
73826
+ // src/repoburg/repoburg-client.ts
73827
+ function defaultRepoburgBaseUrl() {
73828
+ return process.env.REPOBURG_BACKEND_URL || "http://localhost:3000";
73829
+ }
73830
+ function isHtml(text) {
73831
+ return /^\s*<(?:!doctype|html)/i.test(text);
73832
+ }
73833
+ var RepoburgHttpClient = class {
73834
+ baseUrl;
73835
+ constructor(baseUrl = defaultRepoburgBaseUrl()) {
73836
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
73837
+ }
73838
+ /** Perform a JSON request. Throws a concise error on non-OK/non-JSON responses. */
73839
+ async request(method, path2, body) {
73840
+ const response = await fetch(`${this.baseUrl}${path2}`, {
73841
+ method,
73842
+ headers: { "Content-Type": "application/json" },
73843
+ body: body === void 0 ? void 0 : JSON.stringify(body)
73844
+ });
73845
+ const text = await response.text();
73846
+ if (!response.ok) {
73847
+ if (isHtml(text)) {
73848
+ throw new Error(
73849
+ `${method} ${path2} failed: ${response.status} HTML response from ${this.baseUrl} \u2014 the URL points to the wrong server`
73850
+ );
73851
+ }
73852
+ throw new Error(`${method} ${path2} failed: ${response.status} ${text}`);
73853
+ }
73854
+ try {
73855
+ return JSON.parse(text);
73856
+ } catch {
73857
+ throw new Error(
73858
+ `${method} ${path2} failed: non-JSON response from ${this.baseUrl} \u2014 the URL points to the wrong server`
73859
+ );
73860
+ }
73861
+ }
73862
+ async createSession(dto) {
73863
+ return this.request("POST", "/sessions", dto);
73864
+ }
73865
+ async patchSession(id2, dto) {
73866
+ return this.request("PATCH", `/sessions/${id2}`, dto);
73867
+ }
73868
+ async getSession(id2) {
73869
+ return this.request("GET", `/sessions/${id2}`);
73870
+ }
73871
+ async createInput(sessionId, dto) {
73872
+ return this.request("POST", `/sessions/${sessionId}/inputs`, dto);
73873
+ }
73874
+ async getInputWithActions(sessionId, inputId) {
73875
+ return this.request(
73876
+ "GET",
73877
+ `/sessions/${sessionId}/inputs/${inputId}/actions-with-logs`
73878
+ );
73879
+ }
73880
+ async getSessionInputs(sessionId) {
73881
+ return this.request("GET", `/sessions/${sessionId}/inputs`);
73882
+ }
73883
+ async cancel(sessionId) {
73884
+ return this.request(
73885
+ "POST",
73886
+ `/streaming/${sessionId}/cancel`
73887
+ );
73888
+ }
73889
+ async getModels() {
73890
+ const result = await this.request("GET", "/llm-provider/models");
73891
+ return result.models ?? [];
73892
+ }
73893
+ };
73894
+
73895
+ // src/repoburg/backend-resolver.ts
73896
+ import path from "node:path";
73897
+ var HEALTH_POLL_INTERVAL_MS = 1e3;
73898
+ var HEALTH_TIMEOUT_MS = 3e4;
73899
+ function daemonBaseUrl() {
73900
+ return (process.env.REPOBURG_DAEMON_URL || "http://localhost:9998").replace(/\/+$/, "");
73901
+ }
73902
+ var HttpError = class extends Error {
73903
+ constructor(status, body, url) {
73904
+ super(`${url} failed: ${status} ${body}`);
73905
+ this.status = status;
73906
+ this.body = body;
73907
+ this.url = url;
73908
+ }
73909
+ };
73910
+ async function fetchJson(url, init, timeoutMs = 5e3) {
73911
+ const controller = new AbortController();
73912
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
73913
+ let response;
73914
+ try {
73915
+ response = await fetch(url, { ...init, signal: controller.signal });
73916
+ } finally {
73917
+ clearTimeout(timer);
73918
+ }
73919
+ const text = await response.text();
73920
+ if (!response.ok) {
73921
+ throw new HttpError(response.status, text, url);
73922
+ }
73923
+ try {
73924
+ return JSON.parse(text);
73925
+ } catch {
73926
+ throw new Error(`Unexpected non-JSON response from ${url}`);
73927
+ }
73928
+ }
73929
+ function daemonErrorMessage(err) {
73930
+ if (err instanceof HttpError) {
73931
+ try {
73932
+ const parsed = JSON.parse(err.body);
73933
+ return parsed.message || parsed.error || err.body;
73934
+ } catch {
73935
+ return err.body;
73936
+ }
73937
+ }
73938
+ return err.message;
73939
+ }
73940
+ var resolvedCache = /* @__PURE__ */ new Map();
73941
+ function invalidateBackend(baseUrl) {
73942
+ for (const [key, value] of resolvedCache) {
73943
+ if (value.baseUrl === baseUrl) resolvedCache.delete(key);
73944
+ }
73945
+ }
73946
+ async function backendHealthy(baseUrl) {
73947
+ try {
73948
+ await fetchJson(`${baseUrl}/health`, void 0, 2e3);
73949
+ return true;
73950
+ } catch {
73951
+ return false;
73952
+ }
73953
+ }
73954
+ async function waitForHealthy(baseUrl, name) {
73955
+ const deadline = Date.now() + HEALTH_TIMEOUT_MS;
73956
+ while (Date.now() < deadline) {
73957
+ if (await backendHealthy(baseUrl)) return;
73958
+ await new Promise((resolve5) => setTimeout(resolve5, HEALTH_POLL_INTERVAL_MS));
73959
+ }
73960
+ throw new Error(
73961
+ `Backend '${name}' on ${baseUrl} did not become healthy within ${HEALTH_TIMEOUT_MS / 1e3}s. Check daemon logs: repoburg logs ${name}`
73962
+ );
73963
+ }
73964
+ function serviceBaseUrl(service) {
73965
+ return `http://localhost:${service.port}`;
73966
+ }
73967
+ async function restartService(daemon, name) {
73968
+ try {
73969
+ await fetchJson(`${daemon}/services/${name}/restart`, { method: "POST" });
73970
+ } catch (err) {
73971
+ throw new Error(`Daemon failed to restart backend '${name}': ${daemonErrorMessage(err)}`);
73972
+ }
73973
+ }
73974
+ async function startService(daemon, projectPath) {
73975
+ try {
73976
+ return await fetchJson(`${daemon}/services/start`, {
73977
+ method: "POST",
73978
+ headers: { "Content-Type": "application/json" },
73979
+ body: JSON.stringify({ path: projectPath })
73980
+ });
73981
+ } catch (err) {
73982
+ throw new Error(`Daemon failed to start backend for ${projectPath}: ${daemonErrorMessage(err)}`);
73983
+ }
73984
+ }
73985
+ function cache(absPath, service) {
73986
+ const resolved = {
73987
+ baseUrl: serviceBaseUrl(service),
73988
+ port: service.port,
73989
+ name: service.name
73990
+ };
73991
+ resolvedCache.set(absPath, resolved);
73992
+ return resolved;
73993
+ }
73994
+ async function resolveBackendUrl(projectPath, opts = {}) {
73995
+ const autoStart = opts.autoStart !== false;
73996
+ const envUrl = process.env.REPOBURG_BACKEND_URL;
73997
+ if (envUrl) {
73998
+ return { baseUrl: envUrl.replace(/\/+$/, ""), port: 0, name: "REPOBURG_BACKEND_URL" };
73999
+ }
74000
+ const absPath = path.resolve(projectPath);
74001
+ const daemon = daemonBaseUrl();
74002
+ const cached = resolvedCache.get(absPath);
74003
+ if (cached && await backendHealthy(cached.baseUrl)) {
74004
+ return cached;
74005
+ }
74006
+ try {
74007
+ await fetchJson(`${daemon}/health`, void 0, 3e3);
74008
+ } catch {
74009
+ throw new Error(
74010
+ `Repoburg daemon not reachable at ${daemon}. Start it with 'repoburg-daemon', or set REPOBURG_BACKEND_URL to a running backend.`
74011
+ );
74012
+ }
74013
+ const services = await fetchJson(`${daemon}/services`);
74014
+ const match = services.find((s) => s.path === absPath);
74015
+ if (match && match.status === "running") {
74016
+ if (await backendHealthy(serviceBaseUrl(match))) {
74017
+ return cache(absPath, match);
74018
+ }
74019
+ if (!autoStart) return null;
74020
+ await restartService(daemon, match.name);
74021
+ await waitForHealthy(serviceBaseUrl(match), match.name);
74022
+ return cache(absPath, match);
74023
+ }
74024
+ if (!autoStart) return null;
74025
+ if (match) {
74026
+ await restartService(daemon, match.name);
74027
+ await waitForHealthy(serviceBaseUrl(match), match.name);
74028
+ return cache(absPath, match);
74029
+ }
74030
+ const service = await startService(daemon, absPath);
74031
+ await waitForHealthy(serviceBaseUrl(service), service.name);
74032
+ return cache(absPath, service);
74033
+ }
74034
+
74035
+ // src/repoburg/action-mapping.ts
74036
+ function parseJsonArgs(raw) {
74037
+ if (!raw) return null;
74038
+ try {
74039
+ const parsed = JSON.parse(raw);
74040
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
74041
+ } catch {
74042
+ return null;
74043
+ }
74044
+ }
74045
+ function mapActionToItem(action) {
74046
+ const failed = action.status === "EXECUTION_FAILED";
74047
+ const status = failed ? "failed" : "completed";
74048
+ const log = action.executionLogs?.[0];
74049
+ const output = log?.output ?? "";
74050
+ const errorMsg = log?.error_message ?? "";
74051
+ switch (action.action_type) {
74052
+ case "create_file":
74053
+ case "overwrite_file":
74054
+ case "patch":
74055
+ case "quick_edit":
74056
+ case "apply_diff":
74057
+ case "write_todo":
74058
+ case "delete_file": {
74059
+ const kind = action.action_type === "create_file" ? "add" : action.action_type === "delete_file" ? "delete" : "modify";
74060
+ return {
74061
+ type: "file_change",
74062
+ data: { changes: [{ path: action.file_path ?? "", kind }], status },
74063
+ status
74064
+ };
74065
+ }
74066
+ case "run_command":
74067
+ case "execute_code":
74068
+ return {
74069
+ type: "command_execution",
74070
+ data: {
74071
+ command: action.command_string ?? action.action_type,
74072
+ aggregated_output: output,
74073
+ exit_code: failed ? 1 : 0,
74074
+ status
74075
+ },
74076
+ status
74077
+ };
74078
+ case "invoke_subagent": {
74079
+ const args = parseJsonArgs(action.arguments);
74080
+ return {
74081
+ type: "mcp_tool_call",
74082
+ data: {
74083
+ server: null,
74084
+ tool: "Agent",
74085
+ arguments: {
74086
+ description: args?.agent_name ?? args?.agentName ?? "Subagent",
74087
+ prompt: args?.prompt ?? ""
74088
+ },
74089
+ result: output ? [{ type: "text", text: output }] : null,
74090
+ error: failed ? errorMsg || "Sub-agent failed" : null,
74091
+ status
74092
+ },
74093
+ status
74094
+ };
74095
+ }
74096
+ case "web_search": {
74097
+ const args = parseJsonArgs(action.arguments);
74098
+ return { type: "web_search", data: { query: args?.query ?? "" }, status };
74099
+ }
74100
+ case "final":
74101
+ case "html_final":
74102
+ case "ask_user":
74103
+ return null;
74104
+ default: {
74105
+ const isMcp = !!(action.server_name && action.tool_name);
74106
+ return {
74107
+ type: "mcp_tool_call",
74108
+ data: {
74109
+ server: isMcp ? action.server_name : null,
74110
+ tool: isMcp ? action.tool_name : action.action_type,
74111
+ arguments: parseJsonArgs(action.arguments),
74112
+ result: output ? [{ type: "text", text: output }] : null,
74113
+ error: failed ? errorMsg || "Action failed" : null,
74114
+ status
74115
+ },
74116
+ status
74117
+ };
74118
+ }
74119
+ }
74120
+ }
74121
+ function mapUsage2(u) {
74122
+ return {
74123
+ input_tokens: u.input,
74124
+ cached_input_tokens: u.cached,
74125
+ cache_write_input_tokens: 0,
74126
+ output_tokens: u.output,
74127
+ reasoning_output_tokens: 0
74128
+ };
74129
+ }
74130
+ function setSessionStatus3(db3, sessionId, isRunning, status, now, hasUnreviewed = false) {
74131
+ if (hasUnreviewed) {
74132
+ db3.prepare("UPDATE sessions SET is_running = ?, status = ?, has_unreviewed = 1, updated_at = ? WHERE id = ?").run(
74133
+ isRunning,
74134
+ status,
74135
+ now,
74136
+ sessionId
74137
+ );
74138
+ } else {
74139
+ db3.prepare("UPDATE sessions SET is_running = ?, status = ?, updated_at = ? WHERE id = ?").run(
74140
+ isRunning,
74141
+ status,
74142
+ now,
74143
+ sessionId
74144
+ );
74145
+ }
74146
+ }
74147
+ function insertItem(db3, sessionId, turnId, externalId, type, data, status, broadcastEvent) {
74148
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74149
+ const itemId = v4_default();
74150
+ db3.prepare(
74151
+ "INSERT INTO items (id, turn_id, external_item_id, type, data, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
74152
+ ).run(itemId, turnId, externalId, type, JSON.stringify(data), status, now, now);
74153
+ const item = {
74154
+ id: itemId,
74155
+ turn_id: turnId,
74156
+ external_item_id: externalId,
74157
+ type,
74158
+ data,
74159
+ status,
74160
+ created_at: now,
74161
+ updated_at: now
74162
+ };
74163
+ broadcast(broadcastEvent, { sessionId, turnId, item });
74164
+ return item;
74165
+ }
74166
+ function completeItem(db3, sessionId, turnId, item, data, status) {
74167
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74168
+ db3.prepare("UPDATE items SET data = ?, status = ?, updated_at = ? WHERE id = ?").run(
74169
+ JSON.stringify(data),
74170
+ status,
74171
+ now,
74172
+ item.id
74173
+ );
74174
+ const updated = { ...item, data, status, updated_at: now };
74175
+ broadcast("item:completed", { sessionId, turnId, item: updated });
74176
+ }
74177
+
74178
+ // src/repoburg/turn-projector.ts
74179
+ var RESULT_TIMEOUT_MS = 15 * 6e4;
74180
+ var MAX_RESULT_EXTENSIONS = 3;
74181
+ var TurnProjector = class {
74182
+ constructor(deps) {
74183
+ this.deps = deps;
74184
+ this.armResultWatchdog();
74185
+ }
74186
+ rounds = /* @__PURE__ */ new Map();
74187
+ done = false;
74188
+ resultTimer = null;
74189
+ extensions = 0;
74190
+ get isDone() {
74191
+ return this.done;
74192
+ }
74193
+ /** Main entry — dispatch one agent-runtime message. */
74194
+ handle(message) {
74195
+ if (this.done) return;
74196
+ switch (message.type) {
74197
+ case "system":
74198
+ break;
74199
+ // init — connection marker only
74200
+ case "stream_event":
74201
+ this.handleStreamEvent(message);
74202
+ break;
74203
+ case "assistant":
74204
+ this.handleAssistant(message);
74205
+ break;
74206
+ case "user":
74207
+ this.handleUser(message);
74208
+ break;
74209
+ case "result":
74210
+ this.handleResult(message);
74211
+ break;
74212
+ }
74213
+ }
74214
+ /** Reset the result watchdog (any MESSAGE resets it; heartbeats do not). */
74215
+ touch() {
74216
+ if (this.done) return;
74217
+ this.armResultWatchdog();
74218
+ }
74219
+ /** Stop the projector (turn finalized externally). Clears timers. */
74220
+ close() {
74221
+ this.clearWatchdog();
74222
+ this.done = true;
74223
+ }
74224
+ // -------------------------------------------------------------------------
74225
+ // Message handlers
74226
+ // -------------------------------------------------------------------------
74227
+ round(inputId) {
74228
+ let info = this.rounds.get(inputId);
74229
+ if (!info) {
74230
+ info = {
74231
+ messageItemId: null,
74232
+ reasoningItemId: null,
74233
+ messageExternalId: `${inputId}-text`,
74234
+ reasoningExternalId: `${inputId}-thoughts`,
74235
+ text: "",
74236
+ thoughts: "",
74237
+ finalPlain: null
74238
+ };
74239
+ this.rounds.set(inputId, info);
74240
+ }
74241
+ return info;
74242
+ }
74243
+ handleStreamEvent(msg) {
74244
+ const db3 = getDb();
74245
+ const info = this.round(msg.inputId);
74246
+ const kind = msg.delta.type === "thinking" ? "thoughts" : "text";
74247
+ if (kind === "text") info.text += msg.delta.text;
74248
+ else info.thoughts += msg.delta.text;
74249
+ const externalId = kind === "text" ? info.messageExternalId : info.reasoningExternalId;
74250
+ const type = kind === "text" ? "agent_message" : "reasoning";
74251
+ const itemId = kind === "text" ? info.messageItemId : info.reasoningItemId;
74252
+ if (!itemId) {
74253
+ const item = insertItem(
74254
+ db3,
74255
+ this.deps.agentPaneSessionId,
74256
+ this.deps.turnId,
74257
+ externalId,
74258
+ type,
74259
+ { text: kind === "text" ? info.text : info.thoughts },
74260
+ "in_progress",
74261
+ "item:started"
74262
+ );
74263
+ if (kind === "text") info.messageItemId = item.id;
74264
+ else info.reasoningItemId = item.id;
74265
+ } else {
74266
+ broadcast("item:delta", {
74267
+ sessionId: this.deps.agentPaneSessionId,
74268
+ turnId: this.deps.turnId,
74269
+ itemId: externalId,
74270
+ delta: msg.delta.text
74271
+ });
74272
+ }
74273
+ this.touch();
74274
+ }
74275
+ handleAssistant(msg) {
74276
+ const info = this.round(msg.inputId);
74277
+ const text = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("");
74278
+ const thinking = msg.content.filter((b) => b.type === "thinking").map((b) => b.thinking).join("");
74279
+ if (text) info.text = text;
74280
+ if (thinking) info.thoughts = thinking;
74281
+ this.upsertCompletedTextItem(info, "message", info.text);
74282
+ this.upsertCompletedTextItem(info, "reasoning", info.thoughts);
74283
+ this.touch();
74284
+ }
74285
+ /** Complete a round's text/thoughts item — creates it when deltas were
74286
+ * off or missed, otherwise completes the streamed in_progress item. */
74287
+ upsertCompletedTextItem(info, kind, text) {
74288
+ if (!text) return;
74289
+ const db3 = getDb();
74290
+ const externalId = kind === "message" ? info.messageExternalId : info.reasoningExternalId;
74291
+ const itemId = kind === "message" ? info.messageItemId : info.reasoningItemId;
74292
+ const type = kind === "message" ? "agent_message" : "reasoning";
74293
+ if (itemId) {
74294
+ const itemRow = db3.prepare("SELECT * FROM items WHERE id = ?").get(itemId);
74295
+ if (itemRow) {
74296
+ completeItem(db3, this.deps.agentPaneSessionId, this.deps.turnId, itemRow, { text }, "completed");
74297
+ return;
74298
+ }
74299
+ }
74300
+ const existing = db3.prepare("SELECT id FROM items WHERE turn_id = ? AND external_item_id = ?").get(this.deps.turnId, externalId);
74301
+ if (existing) return;
74302
+ const item = insertItem(
74303
+ db3,
74304
+ this.deps.agentPaneSessionId,
74305
+ this.deps.turnId,
74306
+ externalId,
74307
+ type,
74308
+ { text },
74309
+ "completed",
74310
+ "item:completed"
74311
+ );
74312
+ if (kind === "message") info.messageItemId = item.id;
74313
+ else info.reasoningItemId = item.id;
74314
+ }
74315
+ handleUser(msg) {
74316
+ const db3 = getDb();
74317
+ for (const block of msg.content) {
74318
+ const info = this.round(msg.inputId);
74319
+ const action = {
74320
+ ...block.action,
74321
+ executionLogs: [
74322
+ {
74323
+ output: block.is_error ? "" : block.content,
74324
+ error_message: block.is_error ? block.content : null
74325
+ }
74326
+ ]
74327
+ };
74328
+ if (action.action_type === "final") info.finalPlain = action.plain ?? null;
74329
+ const externalId = `${msg.inputId}-action-${action.id}`;
74330
+ const mapped = mapActionToItem(action);
74331
+ if (!mapped) continue;
74332
+ const existing = db3.prepare("SELECT id FROM items WHERE turn_id = ? AND external_item_id = ?").get(this.deps.turnId, externalId);
74333
+ if (existing) continue;
74334
+ insertItem(
74335
+ db3,
74336
+ this.deps.agentPaneSessionId,
74337
+ this.deps.turnId,
74338
+ externalId,
74339
+ mapped.type,
74340
+ mapped.data,
74341
+ mapped.status,
74342
+ "item:completed"
74343
+ );
74344
+ }
74345
+ this.touch();
74346
+ }
74347
+ handleResult(msg) {
74348
+ switch (msg.subtype) {
74349
+ case "success":
74350
+ this.finishSuccess(msg);
74351
+ break;
74352
+ case "aborted":
74353
+ this.finishAborted();
74354
+ break;
74355
+ case "error_during_execution":
74356
+ default:
74357
+ this.finishFailed((msg.errors ?? []).join("; ") || "Agent turn failed.");
74358
+ break;
74359
+ }
74360
+ }
74361
+ // -------------------------------------------------------------------------
74362
+ // Terminal states
74363
+ // -------------------------------------------------------------------------
74364
+ finishSuccess(msg) {
74365
+ const db3 = getDb();
74366
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74367
+ const lastRound = [...this.rounds.values()].pop();
74368
+ const responseText = msg.result || lastRound?.text || lastRound?.finalPlain || "";
74369
+ const usage = msg.usage ? mapUsage2({
74370
+ input: msg.usage.input_tokens,
74371
+ cached: msg.usage.cache_read_input_tokens,
74372
+ output: msg.usage.output_tokens
74373
+ }) : null;
74374
+ this.closeOpenItems("completed");
74375
+ db3.prepare(
74376
+ "UPDATE turns SET status = ?, agent_response = ?, token_usage = ?, updated_at = ? WHERE id = ?"
74377
+ ).run("completed", responseText || null, usage ? JSON.stringify(usage) : null, now, this.deps.turnId);
74378
+ setSessionStatus3(db3, this.deps.agentPaneSessionId, 0, "active", now, true);
74379
+ broadcast("turn:completed", {
74380
+ sessionId: this.deps.agentPaneSessionId,
74381
+ turnId: this.deps.turnId,
74382
+ ...usage ? { usage } : {},
74383
+ hasUnreviewed: true
74384
+ });
74385
+ void this.syncTitle();
74386
+ this.finalize();
74387
+ }
74388
+ /** Fire-and-forget: copy the runtime session title once (new sessions). */
74389
+ async syncTitle() {
74390
+ try {
74391
+ const db3 = getDb();
74392
+ const session = db3.prepare("SELECT title FROM sessions WHERE id = ?").get(
74393
+ this.deps.agentPaneSessionId
74394
+ );
74395
+ if (!session || session.title) return;
74396
+ const runtimeSession = await this.deps.client.getSession(this.deps.repoburgSessionId);
74397
+ const title = (runtimeSession.session_title || "").trim();
74398
+ if (!title) return;
74399
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74400
+ db3.prepare("UPDATE sessions SET title = ?, updated_at = ? WHERE id = ?").run(
74401
+ title,
74402
+ now,
74403
+ this.deps.agentPaneSessionId
74404
+ );
74405
+ broadcast("session:title", { sessionId: this.deps.agentPaneSessionId, title });
74406
+ } catch {
74407
+ }
74408
+ }
74409
+ finishFailed(error) {
74410
+ const db3 = getDb();
74411
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74412
+ this.closeOpenItems("failed");
74413
+ db3.prepare("UPDATE turns SET status = ?, error = ?, updated_at = ? WHERE id = ?").run(
74414
+ "failed",
74415
+ error,
74416
+ now,
74417
+ this.deps.turnId
74418
+ );
74419
+ setSessionStatus3(db3, this.deps.agentPaneSessionId, 0, "failed", now);
74420
+ broadcast("turn:failed", {
74421
+ sessionId: this.deps.agentPaneSessionId,
74422
+ turnId: this.deps.turnId,
74423
+ error
74424
+ });
74425
+ this.finalize();
74426
+ }
74427
+ finishAborted() {
74428
+ const db3 = getDb();
74429
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74430
+ this.closeOpenItems("completed");
74431
+ db3.prepare("UPDATE turns SET status = ?, updated_at = ? WHERE id = ?").run(
74432
+ "aborted",
74433
+ now,
74434
+ this.deps.turnId
74435
+ );
74436
+ setSessionStatus3(db3, this.deps.agentPaneSessionId, 0, "active", now);
74437
+ broadcast("turn:cancelled", {
74438
+ sessionId: this.deps.agentPaneSessionId,
74439
+ turnId: this.deps.turnId
74440
+ });
74441
+ this.finalize();
74442
+ }
74443
+ finalize() {
74444
+ this.clearWatchdog();
74445
+ this.done = true;
74446
+ this.deps.onFinished?.();
74447
+ }
74448
+ /** Close every still in_progress item of this turn with the given status. */
74449
+ closeOpenItems(status) {
74450
+ const db3 = getDb();
74451
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74452
+ db3.prepare("UPDATE items SET status = ?, updated_at = ? WHERE turn_id = ? AND status = ?").run(
74453
+ status,
74454
+ now,
74455
+ this.deps.turnId,
74456
+ "in_progress"
74457
+ );
74458
+ }
74459
+ // -------------------------------------------------------------------------
74460
+ // Watch-dog + snapshot reconcile
74461
+ // -------------------------------------------------------------------------
74462
+ armResultWatchdog() {
74463
+ if (this.done) return;
74464
+ this.clearWatchdog();
74465
+ this.resultTimer = setTimeout(() => {
74466
+ void this.reconcileFromSnapshot();
74467
+ }, RESULT_TIMEOUT_MS);
74468
+ }
74469
+ clearWatchdog() {
74470
+ if (this.resultTimer) {
74471
+ clearTimeout(this.resultTimer);
74472
+ this.resultTimer = null;
74473
+ }
74474
+ }
74475
+ /** Snapshot reconcile: project missing rounds from the runtime's HTTP
74476
+ * snapshot, then complete the turn when the session stopped running. */
74477
+ async reconcileFromSnapshot() {
74478
+ if (this.done) return;
74479
+ const { client, repoburgSessionId } = this.deps;
74480
+ try {
74481
+ const [inputs, session] = await Promise.all([
74482
+ client.getSessionInputs(repoburgSessionId),
74483
+ client.getSession(repoburgSessionId)
74484
+ ]);
74485
+ if (this.done) return;
74486
+ for (const input of inputs) {
74487
+ if (input.role === "model") this.projectSnapshotRound(input);
74488
+ }
74489
+ if (!session.is_running) {
74490
+ const modelInputs = inputs.filter((i) => i.role === "model");
74491
+ const last = modelInputs[modelInputs.length - 1];
74492
+ const lastRound = [...this.rounds.values()].pop();
74493
+ const responseText = lastRound?.text || lastRound?.finalPlain || extractFinalPlain(last) || last?.raw_llm_response || "";
74494
+ const usage = last ? mapUsage2({
74495
+ input: last.input_token_count ?? 0,
74496
+ cached: last.cached_token_count ?? 0,
74497
+ output: last.output_token_count ?? 0
74498
+ }) : null;
74499
+ const db3 = getDb();
74500
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74501
+ this.closeOpenItems("completed");
74502
+ db3.prepare(
74503
+ "UPDATE turns SET status = ?, agent_response = ?, token_usage = ?, updated_at = ? WHERE id = ?"
74504
+ ).run("completed", responseText || null, usage ? JSON.stringify(usage) : null, now, this.deps.turnId);
74505
+ setSessionStatus3(db3, this.deps.agentPaneSessionId, 0, "active", now, true);
74506
+ broadcast("turn:completed", {
74507
+ sessionId: this.deps.agentPaneSessionId,
74508
+ turnId: this.deps.turnId,
74509
+ ...usage ? { usage } : {},
74510
+ hasUnreviewed: true
74511
+ });
74512
+ void this.syncTitle();
74513
+ this.finalize();
74514
+ return;
74515
+ }
74516
+ if (this.extensions < MAX_RESULT_EXTENSIONS) {
74517
+ this.extensions += 1;
74518
+ this.armResultWatchdog();
74519
+ } else {
74520
+ this.finishFailed(
74521
+ `No result within ${RESULT_TIMEOUT_MS / 6e4 * (MAX_RESULT_EXTENSIONS + 1)} minutes \u2014 the runtime session is still running. Check repoburg logs.`
74522
+ );
74523
+ }
74524
+ } catch (err) {
74525
+ console.error("[repoburg] snapshot reconcile failed:", err);
74526
+ if (this.extensions < MAX_RESULT_EXTENSIONS) {
74527
+ this.extensions += 1;
74528
+ this.armResultWatchdog();
74529
+ } else {
74530
+ this.finishFailed(`Snapshot reconcile failed: ${err.message}`);
74531
+ }
74532
+ }
74533
+ }
74534
+ /** Project one round from the snapshot (idempotent — live-projected
74535
+ * rounds already exist and are skipped). */
74536
+ projectSnapshotRound(input) {
74537
+ if (!input.raw_llm_response && !input.thoughts && !input.aiActions?.length) return;
74538
+ const info = this.round(input.id);
74539
+ info.text = info.text || (input.raw_llm_response ?? "");
74540
+ info.thoughts = info.thoughts || (input.thoughts ?? "");
74541
+ this.upsertCompletedTextItem(info, "message", info.text);
74542
+ this.upsertCompletedTextItem(info, "reasoning", info.thoughts);
74543
+ const actions = [...input.aiActions ?? []].sort(
74544
+ (a, b) => (a.order_of_execution ?? 0) - (b.order_of_execution ?? 0)
74545
+ );
74546
+ const db3 = getDb();
74547
+ for (const action of actions) {
74548
+ if (action.action_type === "final") info.finalPlain = action.plain ?? null;
74549
+ const mapped = mapActionToItem(action);
74550
+ if (!mapped) continue;
74551
+ const externalId = `${input.id}-action-${action.id}`;
74552
+ const existing = db3.prepare("SELECT id FROM items WHERE turn_id = ? AND external_item_id = ?").get(this.deps.turnId, externalId);
74553
+ if (existing) continue;
74554
+ insertItem(
74555
+ db3,
74556
+ this.deps.agentPaneSessionId,
74557
+ this.deps.turnId,
74558
+ externalId,
74559
+ mapped.type,
74560
+ mapped.data,
74561
+ mapped.status,
74562
+ "item:completed"
74563
+ );
74564
+ }
74565
+ }
74566
+ };
74567
+ function extractFinalPlain(input) {
74568
+ const action = input?.aiActions?.find(
74569
+ (a) => a.action_type === "final" || a.action_type === "html_final"
74570
+ );
74571
+ return action?.plain ?? null;
74572
+ }
74573
+
74574
+ // src/repoburg/agent-runtime-client.ts
74575
+ function parseSseFrame(frame) {
74576
+ const dataLines = [];
74577
+ for (const line of frame.split("\n")) {
74578
+ const trimmed = line.replace(/\r$/, "");
74579
+ if (trimmed.startsWith(":")) continue;
74580
+ if (trimmed.startsWith("data:")) {
74581
+ dataLines.push(trimmed.slice(5).replace(/^ /, ""));
74582
+ }
74583
+ }
74584
+ if (dataLines.length === 0) return null;
74585
+ return dataLines.join("\n");
74586
+ }
74587
+ function createSseParser() {
74588
+ let buffer = "";
74589
+ return (chunk) => {
74590
+ buffer += chunk.replace(/\r\n/g, "\n");
74591
+ const payloads = [];
74592
+ let boundary;
74593
+ while ((boundary = buffer.indexOf("\n\n")) !== -1) {
74594
+ const frame = buffer.slice(0, boundary);
74595
+ buffer = buffer.slice(boundary + 2);
74596
+ const data = parseSseFrame(frame);
74597
+ if (data !== null) payloads.push(data);
74598
+ }
74599
+ return payloads;
74600
+ };
74601
+ }
74602
+ async function streamAgentRuntimeMessages(baseUrl, sessionId, onMessage, opts = {}) {
74603
+ const deltas = opts.deltas !== false;
74604
+ const delayMs = opts.reconnectDelayMs ?? 2e3;
74605
+ const url = `${baseUrl.replace(/\/+$/, "")}/agent-runtime/sessions/${sessionId}/messages?stream=${deltas ? 1 : 0}`;
74606
+ for (; ; ) {
74607
+ if (opts.signal?.aborted) return "aborted";
74608
+ let response;
74609
+ try {
74610
+ response = await fetch(url, { method: "GET", signal: opts.signal });
74611
+ } catch (err) {
74612
+ if (opts.signal?.aborted || err.name === "AbortError") {
74613
+ return "aborted";
74614
+ }
74615
+ await reconnectDelay(delayMs, opts.signal);
74616
+ continue;
74617
+ }
74618
+ if (response.status === 404) return "session-not-found";
74619
+ if (!response.ok || !response.body) {
74620
+ await reconnectDelay(delayMs, opts.signal);
74621
+ continue;
74622
+ }
74623
+ const reason = await readBody(
74624
+ response.body,
74625
+ onMessage,
74626
+ opts
74627
+ );
74628
+ if (reason !== null) {
74629
+ await response.body.cancel().catch(() => {
74630
+ });
74631
+ return reason;
74632
+ }
74633
+ await reconnectDelay(delayMs, opts.signal);
74634
+ }
74635
+ }
74636
+ async function readBody(body, onMessage, opts) {
74637
+ const parse3 = createSseParser();
74638
+ const decoder = new TextDecoder();
74639
+ const reader = body.getReader();
74640
+ try {
74641
+ for (; ; ) {
74642
+ const { done, value } = await reader.read();
74643
+ if (done) return null;
74644
+ opts.onActivity?.();
74645
+ for (const payload of parse3(decoder.decode(value, { stream: true }))) {
74646
+ let message = null;
74647
+ try {
74648
+ message = JSON.parse(payload);
74649
+ } catch {
74650
+ continue;
74651
+ }
74652
+ if (!message || typeof message.type !== "string") continue;
74653
+ onMessage(message);
74654
+ if (message.type === "result") return "result";
74655
+ }
74656
+ }
74657
+ } catch (err) {
74658
+ if (opts.signal?.aborted || err.name === "AbortError") {
74659
+ return "aborted";
74660
+ }
74661
+ return null;
74662
+ } finally {
74663
+ try {
74664
+ reader.releaseLock();
74665
+ } catch {
74666
+ }
74667
+ }
74668
+ }
74669
+ function reconnectDelay(delayMs, signal) {
74670
+ return new Promise((resolve5) => {
74671
+ if (signal?.aborted) return resolve5();
74672
+ const timer = setTimeout(resolve5, delayMs);
74673
+ signal?.addEventListener(
74674
+ "abort",
74675
+ () => {
74676
+ clearTimeout(timer);
74677
+ resolve5();
74678
+ },
74679
+ { once: true }
74680
+ );
74681
+ });
74682
+ }
74683
+
74684
+ // src/repoburg/repoburg-provider.ts
74685
+ var REASONING_LEVELS = [
74686
+ { effort: "low", label: "Low" },
74687
+ { effort: "medium", label: "Medium" },
74688
+ { effort: "high", label: "High" },
74689
+ { effort: "xhigh", label: "Extra High" }
74690
+ ];
74691
+ var OLLAMA_REASONING_LEVELS = REASONING_LEVELS.filter((l) => l.effort !== "xhigh");
74692
+ function mapReasoningEffort(modelId, effort) {
74693
+ if (!effort) return void 0;
74694
+ if (!["xhigh", "high", "medium", "low", "minimal", "none"].includes(effort)) return void 0;
74695
+ if (modelId?.startsWith("ollama/")) {
74696
+ if (effort === "xhigh") return "high";
74697
+ if (effort === "low" || effort === "medium" || effort === "high") return effort;
74698
+ return void 0;
74699
+ }
74700
+ return effort;
74701
+ }
74702
+ var sessionMap3 = /* @__PURE__ */ new Map();
74703
+ var STALLED_STREAM_MS = 6e4;
74704
+ function isConnectionError(err) {
74705
+ const message = String(err?.message ?? "");
74706
+ return /fetch failed|ECONNREFUSED|ENOTFOUND|ECONNRESET|ETIMEDOUT|EHOSTUNREACH|socket hang up/i.test(
74707
+ message
74708
+ );
74709
+ }
74710
+ async function ensureSession(session, client, baseUrl) {
74711
+ const existing = sessionMap3.get(session.id);
74712
+ if (existing) return existing;
74713
+ if (session.external_thread_id) {
74714
+ const entry2 = {
74715
+ agentPaneSessionId: session.id,
74716
+ repoburgSessionId: session.external_thread_id,
74717
+ client,
74718
+ baseUrl,
74719
+ modelId: session.model ?? null,
74720
+ // undefined forces a re-push on the next turn — heals sessions created
74721
+ // before unsafe effort values (e.g. ollama xhigh) were clamped.
74722
+ reasoningEffort: void 0,
74723
+ activeTurn: null
74724
+ };
74725
+ sessionMap3.set(session.id, entry2);
74726
+ return entry2;
74727
+ }
74728
+ const mappedEffort = mapReasoningEffort(session.model, session.model_reasoning_effort);
74729
+ const created = await client.createSession({
74730
+ session_title: session.title ?? void 0,
74731
+ model_id: session.model ?? void 0,
74732
+ reasoning_effort: mappedEffort
74733
+ });
74734
+ const db3 = getDb();
74735
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74736
+ db3.prepare("UPDATE sessions SET external_thread_id = ?, updated_at = ? WHERE id = ?").run(
74737
+ created.id,
74738
+ now,
74739
+ session.id
74740
+ );
74741
+ const entry = {
74742
+ agentPaneSessionId: session.id,
74743
+ repoburgSessionId: created.id,
74744
+ client,
74745
+ baseUrl,
74746
+ modelId: session.model ?? null,
74747
+ reasoningEffort: mappedEffort,
74748
+ activeTurn: null
74749
+ };
74750
+ sessionMap3.set(session.id, entry);
74751
+ return entry;
74752
+ }
74753
+ function failTurnBeforeStart(db3, sessionId, turnId, error) {
74754
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74755
+ db3.prepare("UPDATE turns SET status = ?, error = ?, updated_at = ? WHERE id = ?").run(
74756
+ "failed",
74757
+ error,
74758
+ now,
74759
+ turnId
74760
+ );
74761
+ setSessionStatus3(db3, sessionId, 0, "failed", now);
74762
+ broadcast("turn:failed", { sessionId, turnId, error });
74763
+ }
74764
+ function failTurn(entry, error) {
74765
+ const active = entry.activeTurn;
74766
+ if (!active) return;
74767
+ entry.activeTurn = null;
74768
+ active.projector.close();
74769
+ active.sseAbort.abort();
74770
+ const db3 = getDb();
74771
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74772
+ db3.prepare("UPDATE turns SET status = ?, error = ?, updated_at = ? WHERE id = ?").run(
74773
+ "failed",
74774
+ error,
74775
+ now,
74776
+ active.turnId
74777
+ );
74778
+ db3.prepare("UPDATE items SET status = ?, updated_at = ? WHERE turn_id = ? AND status = ?").run(
74779
+ "failed",
74780
+ now,
74781
+ active.turnId,
74782
+ "in_progress"
74783
+ );
74784
+ setSessionStatus3(db3, entry.agentPaneSessionId, 0, "failed", now);
74785
+ broadcast("turn:failed", { sessionId: entry.agentPaneSessionId, turnId: active.turnId, error });
74786
+ }
74787
+ async function runStreamLoop(entry, projector) {
74788
+ while (entry.activeTurn?.projector === projector && !projector.isDone) {
74789
+ const active = entry.activeTurn;
74790
+ const controller = new AbortController();
74791
+ active.sseAbort = controller;
74792
+ let stallTimer = null;
74793
+ const resetStall = () => {
74794
+ if (stallTimer) clearTimeout(stallTimer);
74795
+ stallTimer = setTimeout(() => controller.abort(), STALLED_STREAM_MS);
74796
+ };
74797
+ resetStall();
74798
+ const reason = await streamAgentRuntimeMessages(
74799
+ entry.baseUrl,
74800
+ entry.repoburgSessionId,
74801
+ (message) => projector.handle(message),
74802
+ { signal: controller.signal, onActivity: resetStall }
74803
+ );
74804
+ if (stallTimer) clearTimeout(stallTimer);
74805
+ if (projector.isDone || entry.activeTurn?.projector !== projector) return;
74806
+ if (reason === "session-not-found") {
74807
+ failTurn(entry, "Repoburg session no longer exists on the backend.");
74808
+ return;
74809
+ }
74810
+ if (reason === "aborted") {
74811
+ if (active.cancelled) return;
74812
+ continue;
74813
+ }
74814
+ }
74815
+ }
74816
+ async function startTurn3(session, turn) {
74817
+ const db3 = getDb();
74818
+ let client;
74819
+ let baseUrl;
74820
+ try {
74821
+ const resolved = await resolveBackendUrl(session.cwd ?? process.cwd());
74822
+ if (!resolved) throw new Error("No repoburg backend resolved.");
74823
+ baseUrl = resolved.baseUrl;
74824
+ client = new RepoburgHttpClient(baseUrl);
74825
+ } catch (err) {
74826
+ failTurnBeforeStart(db3, session.id, turn.id, `Failed to resolve repoburg backend: ${err.message}`);
74827
+ return;
74828
+ }
74829
+ let entry;
74830
+ try {
74831
+ entry = await ensureSession(session, client, baseUrl);
74832
+ } catch (err) {
74833
+ if (isConnectionError(err)) invalidateBackend(baseUrl);
74834
+ failTurnBeforeStart(db3, session.id, turn.id, `Failed to create repoburg session: ${err.message}`);
74835
+ return;
74836
+ }
74837
+ const wantedModel = session.model ?? null;
74838
+ const wantedEffort = mapReasoningEffort(session.model, session.model_reasoning_effort);
74839
+ if (wantedModel !== entry.modelId || wantedEffort !== entry.reasoningEffort) {
74840
+ try {
74841
+ await entry.client.patchSession(entry.repoburgSessionId, {
74842
+ model_id: wantedModel ?? void 0,
74843
+ reasoning_effort: wantedEffort
74844
+ });
74845
+ entry.modelId = wantedModel;
74846
+ entry.reasoningEffort = wantedEffort;
74847
+ } catch (err) {
74848
+ console.error(`[repoburg] patchSession failed for ${entry.repoburgSessionId}:`, err);
74849
+ }
74850
+ }
74851
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74852
+ db3.prepare("UPDATE turns SET status = ?, updated_at = ? WHERE id = ?").run("running", now, turn.id);
74853
+ setSessionStatus3(db3, session.id, 1, "running", now);
74854
+ broadcast("turn:started", { sessionId: session.id, turnId: turn.id });
74855
+ const projector = new TurnProjector({
74856
+ agentPaneSessionId: session.id,
74857
+ turnId: turn.id,
74858
+ repoburgSessionId: entry.repoburgSessionId,
74859
+ client: entry.client
74860
+ });
74861
+ entry.activeTurn = { turnId: turn.id, projector, sseAbort: new AbortController(), cancelled: false };
74862
+ runStreamLoop(entry, projector).catch((err) => {
74863
+ console.error("[repoburg] stream loop crashed:", err);
74864
+ failTurn(entry, `Stream loop failed: ${err.message}`);
74865
+ });
74866
+ try {
74867
+ await entry.client.createInput(entry.repoburgSessionId, {
74868
+ user_prompt: turn.user_prompt,
74869
+ execution_strategy: "auto_apply"
74870
+ });
74871
+ } catch (err) {
74872
+ if (isConnectionError(err)) invalidateBackend(entry.baseUrl);
74873
+ failTurn(entry, err.message);
74874
+ }
74875
+ }
74876
+ async function interruptTurn3(sessionId) {
74877
+ const entry = sessionMap3.get(sessionId);
74878
+ const active = entry?.activeTurn;
74879
+ if (!entry || !active) return false;
74880
+ active.cancelled = true;
74881
+ entry.activeTurn = null;
74882
+ active.projector.close();
74883
+ active.sseAbort.abort();
74884
+ entry.client.cancel(entry.repoburgSessionId).catch((err) => console.error("[repoburg] cancel failed:", err));
74885
+ const db3 = getDb();
74886
+ const now = (/* @__PURE__ */ new Date()).toISOString();
74887
+ db3.prepare("UPDATE turns SET status = ?, updated_at = ? WHERE id = ?").run("aborted", now, active.turnId);
74888
+ db3.prepare("UPDATE items SET status = ?, updated_at = ? WHERE turn_id = ? AND status = ?").run(
74889
+ "completed",
74890
+ now,
74891
+ active.turnId,
74892
+ "in_progress"
74893
+ );
74894
+ setSessionStatus3(db3, sessionId, 0, "active", now);
74895
+ broadcast("turn:cancelled", { sessionId, turnId: active.turnId });
74896
+ return true;
74897
+ }
74898
+ function clearThread3(sessionId) {
74899
+ const entry = sessionMap3.get(sessionId);
74900
+ if (entry?.activeTurn) {
74901
+ const active = entry.activeTurn;
74902
+ entry.activeTurn = null;
74903
+ active.projector.close();
74904
+ active.sseAbort.abort();
74905
+ }
74906
+ sessionMap3.delete(sessionId);
74907
+ }
74908
+ function clearAllThreads3() {
74909
+ for (const entry of sessionMap3.values()) {
74910
+ if (entry.activeTurn) {
74911
+ const active = entry.activeTurn;
74912
+ entry.activeTurn = null;
74913
+ active.projector.close();
74914
+ active.sseAbort.abort();
74915
+ }
74916
+ }
74917
+ sessionMap3.clear();
74918
+ }
74919
+ async function getModels3() {
74920
+ try {
74921
+ const resolved = await resolveBackendUrl(process.cwd(), { autoStart: false });
74922
+ if (!resolved) return [];
74923
+ const models = await new RepoburgHttpClient(resolved.baseUrl).getModels();
74924
+ return models.map((m) => ({
74925
+ slug: m.id,
74926
+ displayName: m.name,
74927
+ description: "Repoburg backend",
74928
+ defaultReasoning: "medium",
74929
+ // Ollama rejects xhigh/minimal/none as `think` — offer only valid levels.
74930
+ reasoningLevels: m.id.startsWith("ollama/") ? OLLAMA_REASONING_LEVELS : REASONING_LEVELS
74931
+ }));
74932
+ } catch {
74933
+ return [];
74934
+ }
74935
+ }
74936
+ async function shutdown3() {
74937
+ clearAllThreads3();
74938
+ }
74939
+ var repoburgProvider = {
74940
+ startTurn: startTurn3,
74941
+ interruptTurn: interruptTurn3,
74942
+ clearThread: clearThread3,
74943
+ clearAllThreads: clearAllThreads3,
74944
+ getModels: getModels3,
74945
+ shutdown: shutdown3
74946
+ };
74947
+
73796
74948
  // src/providers/index.ts
73797
74949
  registerProvider("codex", codexProvider);
73798
74950
  registerProvider("claude", claudeProvider);
74951
+ registerProvider("repoburg", repoburgProvider);
73799
74952
 
73800
74953
  // src/index.ts
73801
74954
  var PORT = 3003;
73802
74955
  async function main() {
73803
74956
  initDb("data.db");
73804
- const fastify = (0, import_fastify.default)({ logger: true });
74957
+ const fastify = (0, import_fastify.default)({ logger: true, bodyLimit: 50 * 1024 * 1024 });
73805
74958
  await fastify.register(import_cors.default, { origin: true });
73806
74959
  await registerSessionRoutes(fastify);
73807
74960
  await registerTurnRoutes(fastify);