@band-app/server 0.53.0 → 0.54.1

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 (71) hide show
  1. package/dist/client/_shell.html +0 -0
  2. package/dist/client/assets/{TerminalPanel-CUrp7Wxk.js → TerminalPanel-CfzL015Z.js} +1 -1
  3. package/dist/client/assets/{_basePickBy-DzTpqc54.js → _basePickBy-DCBI2ZYZ.js} +1 -1
  4. package/dist/client/assets/{_baseUniq-BH8BhmRB.js → _baseUniq-DcG-qGfl.js} +1 -1
  5. package/dist/client/assets/{arc-C3KloRZC.js → arc-Dtd3NOeG.js} +1 -1
  6. package/dist/client/assets/{architectureDiagram-VXUJARFQ-C0v4c_1F.js → architectureDiagram-VXUJARFQ-_4wJCo66.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-VD42YOAC-JA1asAF3.js → blockDiagram-VD42YOAC-BLg8A5DO.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YG6GDRKO-eDAKz1MH.js → c4Diagram-YG6GDRKO-1o6lovC1.js} +1 -1
  9. package/dist/client/assets/channel-CXnvJLnE.js +1 -0
  10. package/dist/client/assets/{chunk-4BX2VUAB-GiBdk6wd.js → chunk-4BX2VUAB-pUhlexDl.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-CZirdcYj.js → chunk-55IACEB6-DIOOkGXI.js} +1 -1
  12. package/dist/client/assets/{chunk-B4BG7PRW-CRx24wmo.js → chunk-B4BG7PRW-betJcaMy.js} +1 -1
  13. package/dist/client/assets/{chunk-DI55MBZ5-BDlvmWyE.js → chunk-DI55MBZ5-Du6zLzqO.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-CFQ4Ns-B.js → chunk-FMBD7UC4-jlnPGz3-.js} +1 -1
  15. package/dist/client/assets/{chunk-QN33PNHL-O1rjaqXm.js → chunk-QN33PNHL-BtZcZKWT.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-BUex41N2.js → chunk-QZHKN3VN-CCXlh8PQ.js} +1 -1
  17. package/dist/client/assets/{chunk-TZMSLE5B-DJjv_do_.js → chunk-TZMSLE5B-EGqxu3bA.js} +1 -1
  18. package/dist/client/assets/classDiagram-2ON5EDUG-Dp5-cWrq.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-WZHVMYZB-Dp5-cWrq.js +1 -0
  20. package/dist/client/assets/clone-D5FdW0HP.js +1 -0
  21. package/dist/client/assets/{cose-bilkent-S5V4N54A-DFpXjakt.js → cose-bilkent-S5V4N54A-CiQDuqKy.js} +1 -1
  22. package/dist/client/assets/{dagre-6UL2VRFP-CduI6jnM.js → dagre-6UL2VRFP-BV1RIA6i.js} +1 -1
  23. package/dist/client/assets/{diagram-PSM6KHXK-CzWJmLPu.js → diagram-PSM6KHXK-oZBpmBZ4.js} +1 -1
  24. package/dist/client/assets/{diagram-QEK2KX5R-CyCNI4-k.js → diagram-QEK2KX5R-BvBvt_5J.js} +1 -1
  25. package/dist/client/assets/{diagram-S2PKOQOG-C5wLA6ra.js → diagram-S2PKOQOG-sjeU7pbV.js} +1 -1
  26. package/dist/client/assets/{erDiagram-Q2GNP2WA-BNMyokGR.js → erDiagram-Q2GNP2WA-DnmU3JYj.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-NV44I4VS-CDMiz1jN.js → flowDiagram-NV44I4VS-vWTy8wO1.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-JELNMOA3-BjKbhCuq.js → ganttDiagram-JELNMOA3-C8UgEfn6.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-V2S2FVAM-DcKCNdhS.js → gitGraphDiagram-V2S2FVAM-D4Y2-pQd.js} +1 -1
  30. package/dist/client/assets/{graph-BCkWMEPy.js → graph-wAJZ-snQ.js} +1 -1
  31. package/dist/client/assets/{highlighted-body-B3W2YXNL-ESHG-c2t.js → highlighted-body-B3W2YXNL-BS1x7lkZ.js} +1 -1
  32. package/dist/client/assets/{index-CJAA69-B.js → index-21p4gEDF.js} +1 -1
  33. package/dist/client/assets/{index-biU1uw37.js → index-B52rCane.js} +1 -1
  34. package/dist/client/assets/{index-kl_BbR04.js → index-BMcO1RPX.js} +1 -1
  35. package/dist/client/assets/{index-CklvaSBA.js → index-BULPK8ND.js} +1 -1
  36. package/dist/client/assets/{index-nnOiMGMS.js → index-CDRJgI3A.js} +1 -1
  37. package/dist/client/assets/{index-CutOvwS7.js → index-ClYtumza.js} +1 -1
  38. package/dist/client/assets/{index-Ong_o86j.js → index-CxNXgFPY.js} +1 -1
  39. package/dist/client/assets/{index-Bp2vWP2Y.js → index-DIelkckr.js} +1 -1
  40. package/dist/client/assets/{index-C4YFmo8L.js → index-DRo8uUPl.js} +1 -1
  41. package/dist/client/assets/{index-ChF20gAc.js → index-DvCvhnCb.js} +1 -1
  42. package/dist/client/assets/{index-MWMi8v82.js → index-Hh-Dy8VL.js} +1 -1
  43. package/dist/client/assets/{index-C3m3P5mw.js → index-ZYHE2FSs.js} +1 -1
  44. package/dist/client/assets/{index-D1w6ILcm.js → index-g0Sr5h74.js} +1 -1
  45. package/dist/client/assets/{infoDiagram-HS3SLOUP-CoptTTxB.js → infoDiagram-HS3SLOUP-CmZ04ZX2.js} +1 -1
  46. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-CMN-HV9u.js → journeyDiagram-XKPGCS4Q-CyBTVa_6.js} +1 -1
  47. package/dist/client/assets/{kanban-definition-3W4ZIXB7-DC3laXMu.js → kanban-definition-3W4ZIXB7-C6sCohDW.js} +1 -1
  48. package/dist/client/assets/{layout-BNpvAk6E.js → layout-DbAdffkE.js} +1 -1
  49. package/dist/client/assets/main-BYKQWpTo.css +1 -0
  50. package/dist/client/assets/{main-Bgor0kVJ.js → main-DfjP5I-Q.js} +282 -282
  51. package/dist/client/assets/{mindmap-definition-VGOIOE7T-CFfDEH47.js → mindmap-definition-VGOIOE7T-D4byQ-t_.js} +1 -1
  52. package/dist/client/assets/{pieDiagram-ADFJNKIX-CZP5lrkz.js → pieDiagram-ADFJNKIX-SdHTH4tD.js} +1 -1
  53. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-Bc1rWWnR.js → quadrantDiagram-AYHSOK5B-CctaxdVX.js} +1 -1
  54. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-BtfVzz9o.js → requirementDiagram-UZGBJVZJ-BiuKR3TQ.js} +1 -1
  55. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-CTFUjzzh.js → sankeyDiagram-TZEHDZUN-BTpPs36c.js} +1 -1
  56. package/dist/client/assets/{sequenceDiagram-WL72ISMW-Ceovvbrm.js → sequenceDiagram-WL72ISMW-BRAorH_1.js} +1 -1
  57. package/dist/client/assets/{stateDiagram-FKZM4ZOC-BboZL1pg.js → stateDiagram-FKZM4ZOC-BtHKF925.js} +1 -1
  58. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-B40ZaZyn.js +1 -0
  59. package/dist/client/assets/{timeline-definition-IT6M3QCI-7vfajGp6.js → timeline-definition-IT6M3QCI-BxQS_MT5.js} +1 -1
  60. package/dist/client/assets/{treemap-GDKQZRPO-C1ZwadxG.js → treemap-GDKQZRPO-DdrDkT5H.js} +1 -1
  61. package/dist/client/assets/{worktree._worktreeId-C4_UcKsk.js → worktree._worktreeId-C2psBRXR.js} +1 -1
  62. package/dist/client/assets/{worktree._worktreeId-BmMetrj_.js → worktree._worktreeId-CVx6cyp5.js} +1 -1
  63. package/dist/client/assets/{xychartDiagram-PRI3JC2R-pTpN8cts.js → xychartDiagram-PRI3JC2R-R2Q9xRsW.js} +1 -1
  64. package/dist/start-server.mjs +410 -407
  65. package/package.json +9 -8
  66. package/dist/client/assets/channel-DO7Rw5s3.js +0 -1
  67. package/dist/client/assets/classDiagram-2ON5EDUG-Dydmjn5K.js +0 -1
  68. package/dist/client/assets/classDiagram-v2-WZHVMYZB-Dydmjn5K.js +0 -1
  69. package/dist/client/assets/clone-BBqOdmdW.js +0 -1
  70. package/dist/client/assets/main-oF1qBPU-.css +0 -1
  71. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BsPSpOyb.js +0 -1
@@ -2136,7 +2136,7 @@ var require_thread_stream = __commonJS({
2136
2136
  var { version: version3 } = require_package();
2137
2137
  var { EventEmitter: EventEmitter4 } = __require("events");
2138
2138
  var { Worker: Worker2 } = __require("worker_threads");
2139
- var { join: join60 } = __require("path");
2139
+ var { join: join59 } = __require("path");
2140
2140
  var { pathToFileURL } = __require("url");
2141
2141
  var { wait } = require_wait();
2142
2142
  var {
@@ -2172,7 +2172,7 @@ var require_thread_stream = __commonJS({
2172
2172
  function createWorker(stream, opts) {
2173
2173
  const { filename, workerData } = opts;
2174
2174
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
2175
- const toExecute = bundlerOverrides["thread-stream-worker"] || join60(__dirname, "lib", "worker.js");
2175
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join59(__dirname, "lib", "worker.js");
2176
2176
  const worker2 = new Worker2(toExecute, {
2177
2177
  ...opts.workerOpts,
2178
2178
  trackUnmanagedFds: false,
@@ -2558,7 +2558,7 @@ var require_transport = __commonJS({
2558
2558
  "use strict";
2559
2559
  var { createRequire: createRequire2 } = __require("module");
2560
2560
  var getCallers = require_caller();
2561
- var { join: join60, isAbsolute: isAbsolute7, sep: sep11 } = __require("node:path");
2561
+ var { join: join59, isAbsolute: isAbsolute7, sep: sep11 } = __require("node:path");
2562
2562
  var sleep3 = require_atomic_sleep();
2563
2563
  var onExit = require_on_exit_leak_free();
2564
2564
  var ThreadStream = require_thread_stream();
@@ -2621,7 +2621,7 @@ var require_transport = __commonJS({
2621
2621
  throw new Error("only one of target or targets can be specified");
2622
2622
  }
2623
2623
  if (targets) {
2624
- target = bundlerOverrides["pino-worker"] || join60(__dirname, "worker.js");
2624
+ target = bundlerOverrides["pino-worker"] || join59(__dirname, "worker.js");
2625
2625
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
2626
2626
  return {
2627
2627
  ...dest,
@@ -2639,7 +2639,7 @@ var require_transport = __commonJS({
2639
2639
  });
2640
2640
  });
2641
2641
  } else if (pipeline3) {
2642
- target = bundlerOverrides["pino-worker"] || join60(__dirname, "worker.js");
2642
+ target = bundlerOverrides["pino-worker"] || join59(__dirname, "worker.js");
2643
2643
  options.pipelines = [pipeline3.map((dest) => {
2644
2644
  return {
2645
2645
  ...dest,
@@ -2661,7 +2661,7 @@ var require_transport = __commonJS({
2661
2661
  return origin;
2662
2662
  }
2663
2663
  if (origin === "pino/file") {
2664
- return join60(__dirname, "..", "file.js");
2664
+ return join59(__dirname, "..", "file.js");
2665
2665
  }
2666
2666
  let fixTarget2;
2667
2667
  for (const filePath of callers) {
@@ -2989,11 +2989,11 @@ var require_tools = __commonJS({
2989
2989
  }
2990
2990
  }
2991
2991
  }
2992
- function buildFormatters(level, bindings, log91) {
2992
+ function buildFormatters(level, bindings, log90) {
2993
2993
  return {
2994
2994
  level,
2995
2995
  bindings,
2996
- log: log91
2996
+ log: log90
2997
2997
  };
2998
2998
  }
2999
2999
  function normalizeDestFileDescriptor(destination) {
@@ -3376,11 +3376,11 @@ var require_proto = __commonJS({
3376
3376
  }
3377
3377
  } else instance[serializersSym] = serializers;
3378
3378
  if (options.hasOwnProperty("formatters")) {
3379
- const { level, bindings: chindings, log: log91 } = options.formatters;
3379
+ const { level, bindings: chindings, log: log90 } = options.formatters;
3380
3380
  instance[formattersSym] = buildFormatters(
3381
3381
  level || formatters.level,
3382
3382
  chindings || resetChildingsFormatter,
3383
- log91 || formatters.log
3383
+ log90 || formatters.log
3384
3384
  );
3385
3385
  } else {
3386
3386
  instance[formattersSym] = buildFormatters(
@@ -3650,7 +3650,7 @@ var require_safe_stable_stringify = __commonJS({
3650
3650
  return circularValue;
3651
3651
  }
3652
3652
  let res = "";
3653
- let join60 = ",";
3653
+ let join59 = ",";
3654
3654
  const originalIndentation = indentation;
3655
3655
  if (Array.isArray(value)) {
3656
3656
  if (value.length === 0) {
@@ -3664,7 +3664,7 @@ var require_safe_stable_stringify = __commonJS({
3664
3664
  indentation += spacer;
3665
3665
  res += `
3666
3666
  ${indentation}`;
3667
- join60 = `,
3667
+ join59 = `,
3668
3668
  ${indentation}`;
3669
3669
  }
3670
3670
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3672,13 +3672,13 @@ ${indentation}`;
3672
3672
  for (; i < maximumValuesToStringify - 1; i++) {
3673
3673
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3674
3674
  res += tmp2 !== void 0 ? tmp2 : "null";
3675
- res += join60;
3675
+ res += join59;
3676
3676
  }
3677
3677
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3678
3678
  res += tmp !== void 0 ? tmp : "null";
3679
3679
  if (value.length - 1 > maximumBreadth) {
3680
3680
  const removedKeys = value.length - maximumBreadth - 1;
3681
- res += `${join60}"... ${getItemCount(removedKeys)} not stringified"`;
3681
+ res += `${join59}"... ${getItemCount(removedKeys)} not stringified"`;
3682
3682
  }
3683
3683
  if (spacer !== "") {
3684
3684
  res += `
@@ -3699,7 +3699,7 @@ ${originalIndentation}`;
3699
3699
  let separator = "";
3700
3700
  if (spacer !== "") {
3701
3701
  indentation += spacer;
3702
- join60 = `,
3702
+ join59 = `,
3703
3703
  ${indentation}`;
3704
3704
  whitespace = " ";
3705
3705
  }
@@ -3713,13 +3713,13 @@ ${indentation}`;
3713
3713
  const tmp = stringifyFnReplacer(key3, value, stack, replacer, spacer, indentation);
3714
3714
  if (tmp !== void 0) {
3715
3715
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3716
- separator = join60;
3716
+ separator = join59;
3717
3717
  }
3718
3718
  }
3719
3719
  if (keyLength > maximumBreadth) {
3720
3720
  const removedKeys = keyLength - maximumBreadth;
3721
3721
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
3722
- separator = join60;
3722
+ separator = join59;
3723
3723
  }
3724
3724
  if (spacer !== "" && separator.length > 1) {
3725
3725
  res = `
@@ -3760,7 +3760,7 @@ ${originalIndentation}`;
3760
3760
  }
3761
3761
  const originalIndentation = indentation;
3762
3762
  let res = "";
3763
- let join60 = ",";
3763
+ let join59 = ",";
3764
3764
  if (Array.isArray(value)) {
3765
3765
  if (value.length === 0) {
3766
3766
  return "[]";
@@ -3773,7 +3773,7 @@ ${originalIndentation}`;
3773
3773
  indentation += spacer;
3774
3774
  res += `
3775
3775
  ${indentation}`;
3776
- join60 = `,
3776
+ join59 = `,
3777
3777
  ${indentation}`;
3778
3778
  }
3779
3779
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3781,13 +3781,13 @@ ${indentation}`;
3781
3781
  for (; i < maximumValuesToStringify - 1; i++) {
3782
3782
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3783
3783
  res += tmp2 !== void 0 ? tmp2 : "null";
3784
- res += join60;
3784
+ res += join59;
3785
3785
  }
3786
3786
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3787
3787
  res += tmp !== void 0 ? tmp : "null";
3788
3788
  if (value.length - 1 > maximumBreadth) {
3789
3789
  const removedKeys = value.length - maximumBreadth - 1;
3790
- res += `${join60}"... ${getItemCount(removedKeys)} not stringified"`;
3790
+ res += `${join59}"... ${getItemCount(removedKeys)} not stringified"`;
3791
3791
  }
3792
3792
  if (spacer !== "") {
3793
3793
  res += `
@@ -3800,7 +3800,7 @@ ${originalIndentation}`;
3800
3800
  let whitespace = "";
3801
3801
  if (spacer !== "") {
3802
3802
  indentation += spacer;
3803
- join60 = `,
3803
+ join59 = `,
3804
3804
  ${indentation}`;
3805
3805
  whitespace = " ";
3806
3806
  }
@@ -3809,7 +3809,7 @@ ${indentation}`;
3809
3809
  const tmp = stringifyArrayReplacer(key3, value[key3], stack, replacer, spacer, indentation);
3810
3810
  if (tmp !== void 0) {
3811
3811
  res += `${separator}${strEscape(key3)}:${whitespace}${tmp}`;
3812
- separator = join60;
3812
+ separator = join59;
3813
3813
  }
3814
3814
  }
3815
3815
  if (spacer !== "" && separator.length > 1) {
@@ -3867,20 +3867,20 @@ ${originalIndentation}`;
3867
3867
  indentation += spacer;
3868
3868
  let res2 = `
3869
3869
  ${indentation}`;
3870
- const join61 = `,
3870
+ const join60 = `,
3871
3871
  ${indentation}`;
3872
3872
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
3873
3873
  let i = 0;
3874
3874
  for (; i < maximumValuesToStringify - 1; i++) {
3875
3875
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3876
3876
  res2 += tmp2 !== void 0 ? tmp2 : "null";
3877
- res2 += join61;
3877
+ res2 += join60;
3878
3878
  }
3879
3879
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3880
3880
  res2 += tmp !== void 0 ? tmp : "null";
3881
3881
  if (value.length - 1 > maximumBreadth) {
3882
3882
  const removedKeys = value.length - maximumBreadth - 1;
3883
- res2 += `${join61}"... ${getItemCount(removedKeys)} not stringified"`;
3883
+ res2 += `${join60}"... ${getItemCount(removedKeys)} not stringified"`;
3884
3884
  }
3885
3885
  res2 += `
3886
3886
  ${originalIndentation}`;
@@ -3896,16 +3896,16 @@ ${originalIndentation}`;
3896
3896
  return '"[Object]"';
3897
3897
  }
3898
3898
  indentation += spacer;
3899
- const join60 = `,
3899
+ const join59 = `,
3900
3900
  ${indentation}`;
3901
3901
  let res = "";
3902
3902
  let separator = "";
3903
3903
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
3904
3904
  if (isTypedArrayWithEntries(value)) {
3905
- res += stringifyTypedArray(value, join60, maximumBreadth);
3905
+ res += stringifyTypedArray(value, join59, maximumBreadth);
3906
3906
  keys = keys.slice(value.length);
3907
3907
  maximumPropertiesToStringify -= value.length;
3908
- separator = join60;
3908
+ separator = join59;
3909
3909
  }
3910
3910
  if (deterministic) {
3911
3911
  keys = sort(keys, comparator2);
@@ -3916,13 +3916,13 @@ ${indentation}`;
3916
3916
  const tmp = stringifyIndent(key3, value[key3], stack, spacer, indentation);
3917
3917
  if (tmp !== void 0) {
3918
3918
  res += `${separator}${strEscape(key3)}: ${tmp}`;
3919
- separator = join60;
3919
+ separator = join59;
3920
3920
  }
3921
3921
  }
3922
3922
  if (keyLength > maximumBreadth) {
3923
3923
  const removedKeys = keyLength - maximumBreadth;
3924
3924
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
3925
- separator = join60;
3925
+ separator = join59;
3926
3926
  }
3927
3927
  if (separator !== "") {
3928
3928
  res = `
@@ -14699,7 +14699,7 @@ var require_websocket = __commonJS({
14699
14699
  var http = __require("http");
14700
14700
  var net = __require("net");
14701
14701
  var tls = __require("tls");
14702
- var { randomBytes: randomBytes17, createHash: createHash15 } = __require("crypto");
14702
+ var { randomBytes: randomBytes17, createHash: createHash14 } = __require("crypto");
14703
14703
  var { Duplex, Readable: Readable3 } = __require("stream");
14704
14704
  var { URL: URL2 } = __require("url");
14705
14705
  var PerMessageDeflate = require_permessage_deflate();
@@ -15359,7 +15359,7 @@ var require_websocket = __commonJS({
15359
15359
  abortHandshake(websocket, socket, "Invalid Upgrade header");
15360
15360
  return;
15361
15361
  }
15362
- const digest2 = createHash15("sha1").update(key2 + GUID).digest("base64");
15362
+ const digest2 = createHash14("sha1").update(key2 + GUID).digest("base64");
15363
15363
  if (res.headers["sec-websocket-accept"] !== digest2) {
15364
15364
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
15365
15365
  return;
@@ -15726,7 +15726,7 @@ var require_websocket_server = __commonJS({
15726
15726
  var EventEmitter4 = __require("events");
15727
15727
  var http = __require("http");
15728
15728
  var { Duplex } = __require("stream");
15729
- var { createHash: createHash15 } = __require("crypto");
15729
+ var { createHash: createHash14 } = __require("crypto");
15730
15730
  var extension = require_extension();
15731
15731
  var PerMessageDeflate = require_permessage_deflate();
15732
15732
  var subprotocol = require_subprotocol();
@@ -16027,7 +16027,7 @@ var require_websocket_server = __commonJS({
16027
16027
  );
16028
16028
  }
16029
16029
  if (this._state > RUNNING) return abortHandshake(socket, 503);
16030
- const digest2 = createHash15("sha1").update(key2 + GUID).digest("base64");
16030
+ const digest2 = createHash14("sha1").update(key2 + GUID).digest("base64");
16031
16031
  const headers = [
16032
16032
  "HTTP/1.1 101 Switching Protocols",
16033
16033
  "Upgrade: websocket",
@@ -41799,7 +41799,7 @@ var init_sql = __esm({
41799
41799
  return new SQL([new StringChunk(str4)]);
41800
41800
  }
41801
41801
  _sql.raw = raw;
41802
- function join60(chunks, separator) {
41802
+ function join59(chunks, separator) {
41803
41803
  const result = [];
41804
41804
  for (const [i, chunk] of chunks.entries()) {
41805
41805
  if (i > 0 && separator !== void 0) result.push(separator);
@@ -41807,7 +41807,7 @@ var init_sql = __esm({
41807
41807
  }
41808
41808
  return new SQL(result);
41809
41809
  }
41810
- _sql.join = join60;
41810
+ _sql.join = join59;
41811
41811
  function identifier(value) {
41812
41812
  return new Name(value);
41813
41813
  }
@@ -43735,7 +43735,7 @@ var init_sql2 = __esm({
43735
43735
  return new SQL3([new StringChunk2(str4)]);
43736
43736
  }
43737
43737
  _sql.raw = raw;
43738
- function join60(chunks, separator) {
43738
+ function join59(chunks, separator) {
43739
43739
  const result = [];
43740
43740
  for (const [i, chunk] of chunks.entries()) {
43741
43741
  if (i > 0 && separator !== void 0) result.push(separator);
@@ -43743,7 +43743,7 @@ var init_sql2 = __esm({
43743
43743
  }
43744
43744
  return new SQL3(result);
43745
43745
  }
43746
- _sql.join = join60;
43746
+ _sql.join = join59;
43747
43747
  function identifier(value) {
43748
43748
  return new Name2(value);
43749
43749
  }
@@ -48936,7 +48936,7 @@ var init_select3 = __esm({
48936
48936
  const baseTableName = this.tableName;
48937
48937
  const tableName = getTableLikeName(table);
48938
48938
  for (const item of extractUsedTable(table)) this.usedTables.add(item);
48939
- if (typeof tableName === "string" && this.config.joins?.some((join60) => join60.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
48939
+ if (typeof tableName === "string" && this.config.joins?.some((join59) => join59.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
48940
48940
  if (!this.isPartialSelect) {
48941
48941
  if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") this.config.fields = { [baseTableName]: this.config.fields };
48942
48942
  if (typeof tableName === "string" && !is2(table, SQL3)) {
@@ -50201,7 +50201,7 @@ var init_dialect = __esm({
50201
50201
  if (!joins2) return;
50202
50202
  const withEntries = Object.entries(joins2).filter(([_2, v2]) => v2);
50203
50203
  if (!withEntries.length) return;
50204
- return sql2.join(withEntries.map(([k2, join60]) => {
50204
+ return sql2.join(withEntries.map(([k2, join59]) => {
50205
50205
  const relation = tableConfig.relations[k2];
50206
50206
  const isSingle2 = is2(relation, One);
50207
50207
  const targetTable = aliasedTable(relation.targetTable, `d${currentDepth + 1}`);
@@ -50212,7 +50212,7 @@ var init_dialect = __esm({
50212
50212
  table: targetTable,
50213
50213
  mode: isSingle2 ? "first" : "many",
50214
50214
  schema,
50215
- queryConfig: join60,
50215
+ queryConfig: join59,
50216
50216
  tableConfig: schema[relation.targetTableName],
50217
50217
  relationWhere: filter,
50218
50218
  isNested: true,
@@ -50226,7 +50226,7 @@ var init_dialect = __esm({
50226
50226
  key: k2,
50227
50227
  selection: innerQuery.selection,
50228
50228
  isArray: !isSingle2,
50229
- isOptional: (relation.optional ?? false) || join60 !== true && !!join60.where
50229
+ isOptional: (relation.optional ?? false) || join59 !== true && !!join59.where
50230
50230
  });
50231
50231
  const jsonColumns = sql2.join(innerQuery.selection.map((s2) => {
50232
50232
  return sql2`${sql2.raw(this.escapeString(s2.key))}, ${s2.selection ? sql2`${jsonb2}(${sql2.identifier(s2.key)})` : sql2.identifier(s2.key)}`;
@@ -50745,7 +50745,7 @@ var init_update = __esm({
50745
50745
  createJoin(joinType) {
50746
50746
  return ((table, on) => {
50747
50747
  const tableName = getTableLikeName(table);
50748
- if (typeof tableName === "string" && this.config.joins.some((join60) => join60.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
50748
+ if (typeof tableName === "string" && this.config.joins.some((join59) => join59.alias === tableName)) throw new Error(`Alias "${tableName}" is already used in this query`);
50749
50749
  if (typeof on === "function") {
50750
50750
  const from = this.config.from ? is2(table, SQLiteTable2) ? table[Table2.Symbol.Columns] : is2(table, Subquery2) ? table._.selectedFields : is2(table, SQLiteViewBase) ? table[ViewBaseConfig2].selectedFields : void 0 : void 0;
50751
50751
  on = on(new Proxy(this.config.table[Table2.Symbol.Columns], new SelectionProxyHandler({
@@ -54081,7 +54081,7 @@ import { lstatSync as lstatSync3, realpathSync as realpathSync4 } from "node:fs"
54081
54081
  import { platform } from "node:os";
54082
54082
  import { delimiter as delimiter3, join as join19, resolve as resolve4 } from "node:path";
54083
54083
  function findCliBinaryAt(opts) {
54084
- const { cwd, dirname: dirname17 } = opts;
54084
+ const { cwd, dirname: dirname18 } = opts;
54085
54085
  const exe = platform() === "win32" ? "band.exe" : "band";
54086
54086
  const explicit = process.env.BAND_CLI_PATH;
54087
54087
  if (explicit) {
@@ -54097,7 +54097,7 @@ function findCliBinaryAt(opts) {
54097
54097
  // cwd = repo root (fallback)
54098
54098
  resolve4(cwd, "apps"),
54099
54099
  // From this source file in dev (packages/host-local/src/process/ → apps/)
54100
- resolve4(dirname17, "..", "..", "..", "..", "apps"),
54100
+ resolve4(dirname18, "..", "..", "..", "..", "apps"),
54101
54101
  // From bundled `dist/` file (<Resources>/web/dist/ → <Resources>/) only
54102
54102
  // — in dev mode this resolves to `packages/`, which has no
54103
54103
  // `cli/target/<profile>/band` and is harmless; the walk above is the
@@ -54105,7 +54105,7 @@ function findCliBinaryAt(opts) {
54105
54105
  // layout under <Resources>/cli/ would still resolve. Today's Electron
54106
54106
  // bundle ships the binary under `binaries/` (handled by Strategy B),
54107
54107
  // so this strategy never hits in production either.
54108
- resolve4(dirname17, "..", "..", "..")
54108
+ resolve4(dirname18, "..", "..", "..")
54109
54109
  ];
54110
54110
  for (const appsDir of appsStrategies) {
54111
54111
  for (const profile of ["release", "debug"]) {
@@ -54122,7 +54122,7 @@ function findCliBinaryAt(opts) {
54122
54122
  resolve4(cwd, "..", "binaries", exe),
54123
54123
  // From the bundled dist file (<Resources>/web/dist/start-server.mjs)
54124
54124
  // → <Resources>/binaries/band
54125
- resolve4(dirname17, "..", "..", "binaries", exe)
54125
+ resolve4(dirname18, "..", "..", "binaries", exe)
54126
54126
  ];
54127
54127
  for (const p2 of electronCandidates) {
54128
54128
  try {
@@ -63153,10 +63153,10 @@ var init_agent_command = __esm({
63153
63153
  import { readdirSync as readdirSync8 } from "node:fs";
63154
63154
  import { mkdir as mkdir5 } from "node:fs/promises";
63155
63155
  import { join as join38 } from "node:path";
63156
- async function openSharedDir(worktreeId4) {
63156
+ async function openSharedDir(worktreeId4, chatId) {
63157
63157
  const host = hostRegistry.hostFor(worktreeId4);
63158
63158
  if (host.id === hostRegistry.local.id) {
63159
- const path3 = join38(bandHome(), "shared", worktreeId4);
63159
+ const path3 = join38(bandHome(), "shared", worktreeId4, chatId);
63160
63160
  await mkdir5(path3, { recursive: true });
63161
63161
  return {
63162
63162
  path: path3,
@@ -63171,7 +63171,7 @@ async function openSharedDir(worktreeId4) {
63171
63171
  }
63172
63172
  const dirs = (await host.info()).dirs;
63173
63173
  if (!dirs) throw new Error(`Worker ${host.id} has no directory for shared files`);
63174
- const path2 = join38(dirs.shared, worktreeId4);
63174
+ const path2 = join38(dirs.shared, worktreeId4, chatId);
63175
63175
  await host.fs.mkdir(path2, { recursive: true });
63176
63176
  return {
63177
63177
  path: path2,
@@ -63192,6 +63192,25 @@ async function agentExtraDirs(worktreeId4) {
63192
63192
  const dirs = (await host.info()).dirs;
63193
63193
  return dirs ? [dirs.uploads, dirs.shared] : [];
63194
63194
  }
63195
+ function sharedFileUrl(worktreeId4, chatId, filename) {
63196
+ return `/api/shared/${encodeURIComponent(worktreeId4)}/${encodeURIComponent(chatId)}/${encodeURIComponent(filename)}`;
63197
+ }
63198
+ function parseSharedPath(rest) {
63199
+ const raw = rest.split("?")[0].split("/");
63200
+ if (raw.length !== 2 && raw.length !== 3) return null;
63201
+ const parts = [];
63202
+ for (const segment of raw) {
63203
+ let decoded;
63204
+ try {
63205
+ decoded = decodeURIComponent(segment);
63206
+ } catch {
63207
+ return null;
63208
+ }
63209
+ if (!decoded || decoded === "." || decoded === ".." || /[/\\\0]/.test(decoded)) return null;
63210
+ parts.push(decoded);
63211
+ }
63212
+ return parts.length === 3 ? { worktreeId: parts[0], chatId: parts[1], name: parts[2] } : { worktreeId: parts[0], name: parts[1] };
63213
+ }
63195
63214
  var init_shared_dir = __esm({
63196
63215
  "src/server/services/_utils/shared-dir.ts"() {
63197
63216
  "use strict";
@@ -68229,7 +68248,7 @@ function turnUsage(res, ctx) {
68229
68248
  return { ...usage, model, costUsd: (previousCost ?? 0) + cost };
68230
68249
  }
68231
68250
  function sharedDirNote(sharedDir) {
68232
- return `[File sharing: to send a file to the user, write or copy it to ${sharedDir}/ and it will appear as a downloadable file card in the chat.]`;
68251
+ return `[File sharing: to send a file to the user, write or copy it to ${sharedDir}/ and it will appear as a file card in this chat.]`;
68233
68252
  }
68234
68253
  function fileUri(path2) {
68235
68254
  return `file://${path2.split("/").map(encodeURIComponent).join("/")}`;
@@ -68729,6 +68748,8 @@ var init_session3 = __esm({
68729
68748
  this.misses = opts.heartbeatMisses ?? HEARTBEAT_MISSES;
68730
68749
  this.nextChan = opts.role === "client" ? 1 : 2;
68731
68750
  }
68751
+ /** Close code and reason of the last socket that ended. Code 1006 means no close frame arrived. */
68752
+ lastClose = null;
68732
68753
  get attached() {
68733
68754
  return this.ws !== null && this.ws.readyState === 1;
68734
68755
  }
@@ -68823,8 +68844,10 @@ var init_session3 = __esm({
68823
68844
  ws.on("message", (data, isBinary) => {
68824
68845
  if (this.ws === ws) this.onMessage(data, isBinary);
68825
68846
  });
68826
- ws.on("close", () => {
68827
- if (this.ws === ws) this.detach();
68847
+ ws.on("close", (code, reason) => {
68848
+ if (this.ws !== ws) return;
68849
+ this.lastClose = { code, reason: reason.toString().slice(0, 200) };
68850
+ this.detach();
68828
68851
  });
68829
68852
  ws.on("error", () => {
68830
68853
  });
@@ -68913,34 +68936,40 @@ var init_session3 = __esm({
68913
68936
  let frame;
68914
68937
  try {
68915
68938
  frame = decodeFrame(Buffer.isBuffer(data) ? data : Buffer.from(data));
68916
- } catch {
68917
- this.ws?.terminate();
68939
+ } catch (err) {
68940
+ this.cut("undecodable frame", err);
68918
68941
  return;
68919
68942
  }
68920
68943
  try {
68921
68944
  this.channels.get(frame.chan)?.handleFrame(frame);
68922
- } catch {
68923
- this.ws?.terminate();
68945
+ } catch (err) {
68946
+ this.cut(`channel ${frame.chan} failed to handle a frame`, err);
68924
68947
  }
68925
68948
  return;
68926
68949
  }
68927
68950
  let msg;
68928
68951
  try {
68929
68952
  msg = JSON.parse(data.toString());
68930
- } catch {
68931
- this.ws?.terminate();
68953
+ } catch (err) {
68954
+ this.cut("unparsable message", err);
68932
68955
  return;
68933
68956
  }
68934
68957
  if (msg === null || typeof msg !== "object") {
68935
- this.ws?.terminate();
68958
+ this.cut("message is not an object");
68936
68959
  return;
68937
68960
  }
68938
68961
  try {
68939
68962
  this.dispatchText(msg);
68940
- } catch {
68941
- this.ws?.terminate();
68963
+ } catch (err) {
68964
+ this.cut("invalid message", err);
68942
68965
  }
68943
68966
  }
68967
+ /** Drops the socket after a protocol violation, and says why, so the drop is not silent. */
68968
+ cut(reason, err) {
68969
+ const detail = err instanceof Error ? `: ${err.message}` : "";
68970
+ this.emit("fault", `${reason}${detail}`);
68971
+ this.ws?.terminate();
68972
+ }
68944
68973
  dispatchText(msg) {
68945
68974
  if (typeof msg.method === "string") {
68946
68975
  if ("id" in msg && msg.id !== void 0 && msg.id !== null)
@@ -68965,14 +68994,32 @@ var init_session3 = __esm({
68965
68994
  throw new Error("malformed link.open");
68966
68995
  }
68967
68996
  if (this.channels.has(p2.chan) || this.tombstones.has(p2.chan)) return;
68968
- if (this.channels.size >= MAX_CHANNELS) throw new Error("too many channels");
68997
+ if (this.channels.size >= MAX_CHANNELS) {
68998
+ this.emit("fault", `refused channel ${p2.chan}: too many channels`);
68999
+ this.writeBinary(
69000
+ encodeFrame({
69001
+ chan: p2.chan,
69002
+ seq: 0,
69003
+ kind: "reset",
69004
+ payload: Buffer.from("too many channels")
69005
+ })
69006
+ );
69007
+ return;
69008
+ }
68969
69009
  const ch = new Channel(this, p2.chan, p2.name, p2.meta, this.window);
68970
69010
  this.channels.set(p2.chan, ch);
68971
69011
  this.emit("channel", ch);
68972
69012
  return;
68973
69013
  }
68974
69014
  }
68975
- this.notifyHandlers.get(msg.method)?.(msg.params);
69015
+ try {
69016
+ this.notifyHandlers.get(msg.method)?.(msg.params);
69017
+ } catch (err) {
69018
+ this.emit(
69019
+ "fault",
69020
+ `notification ${msg.method} handler threw: ${err instanceof Error ? err.message : String(err)}`
69021
+ );
69022
+ }
68976
69023
  }
68977
69024
  async onRequest(msg) {
68978
69025
  const handler = this.handlers.get(msg.method);
@@ -69110,7 +69157,7 @@ var init_payload = __esm({
69110
69157
  });
69111
69158
 
69112
69159
  // ../../packages/link/src/relay.ts
69113
- var METHOD_RELAY_REGISTER, METHOD_RELAY_REVOKE, METHOD_RELAY_HTTP, RELAY_MAX_BODY_BYTES, METHOD_CLI_FETCH, METHOD_LIFECYCLE_IDLE, METHOD_LIFECYCLE_POLICY, METHOD_LIFECYCLE_SLEEP, METHOD_LIFECYCLE_SHUTDOWN, METHOD_LIFECYCLE_EXPORT_SESSIONS, METHOD_LIFECYCLE_IMPORT_SESSIONS, METHOD_GIT_CREDENTIAL, METHOD_GH_TOKEN, METHOD_LEASE_RENEW, METHOD_WORKER_UPDATE;
69160
+ var METHOD_RELAY_REGISTER, METHOD_RELAY_REVOKE, METHOD_RELAY_HTTP, RELAY_MAX_BODY_BYTES, METHOD_LIFECYCLE_IDLE, METHOD_LIFECYCLE_POLICY, METHOD_LIFECYCLE_SLEEP, METHOD_LIFECYCLE_SHUTDOWN, METHOD_LIFECYCLE_EXPORT_SESSIONS, METHOD_LIFECYCLE_IMPORT_SESSIONS, METHOD_GIT_CREDENTIAL, METHOD_GH_TOKEN, METHOD_LEASE_RENEW, METHOD_WORKER_UPDATE;
69114
69161
  var init_relay = __esm({
69115
69162
  "../../packages/link/src/relay.ts"() {
69116
69163
  "use strict";
@@ -69118,7 +69165,6 @@ var init_relay = __esm({
69118
69165
  METHOD_RELAY_REVOKE = "relay.revoke";
69119
69166
  METHOD_RELAY_HTTP = "relay.http";
69120
69167
  RELAY_MAX_BODY_BYTES = 512 * 1024;
69121
- METHOD_CLI_FETCH = "cli.fetch";
69122
69168
  METHOD_LIFECYCLE_IDLE = "lifecycle.idle";
69123
69169
  METHOD_LIFECYCLE_POLICY = "lifecycle.policy";
69124
69170
  METHOD_LIFECYCLE_SLEEP = "lifecycle.sleep";
@@ -69324,7 +69370,8 @@ var init_server3 = __esm({
69324
69370
  resumed,
69325
69371
  wsPing: true
69326
69372
  });
69327
- } catch {
69373
+ } catch (err) {
69374
+ this.emit("fault", session, `attach failed: ${err instanceof Error ? err.message : err}`);
69328
69375
  ws.terminate();
69329
69376
  return;
69330
69377
  }
@@ -69341,6 +69388,7 @@ var init_server3 = __esm({
69341
69388
  this.expiry.set(session.workerId, t2);
69342
69389
  });
69343
69390
  session.on("lost", () => this.emit("lost", session));
69391
+ session.on("fault", (reason) => this.emit("fault", session, reason));
69344
69392
  }
69345
69393
  dropSession(session, reason) {
69346
69394
  clearTimeout(this.expiry.get(session.workerId));
@@ -70413,7 +70461,7 @@ async function runTask(task) {
70413
70461
  }
70414
70462
  if (task.model) await applyTurnChoice(chatId, "model", task.model);
70415
70463
  if (task.mode) await applyTurnChoice(chatId, "mode", task.mode);
70416
- const shared2 = await openSharedDir(task.worktreeId);
70464
+ const shared2 = await openSharedDir(task.worktreeId, chatId);
70417
70465
  const seenShared = new Set(await shared2.list());
70418
70466
  const announce = (names) => {
70419
70467
  for (const filename of names) {
@@ -70422,7 +70470,7 @@ async function runTask(task) {
70422
70470
  agentSessionService.record(chatId, {
70423
70471
  type: "file",
70424
70472
  mediaType: mimeTypeFromFilename(filename),
70425
- url: `/api/shared/${encodeURIComponent(task.worktreeId)}/${encodeURIComponent(filename)}`,
70473
+ url: sharedFileUrl(task.worktreeId, chatId, filename),
70426
70474
  filename
70427
70475
  });
70428
70476
  }
@@ -72197,8 +72245,8 @@ var init_environment_builds = __esm({
72197
72245
  get(id) {
72198
72246
  return getDb().select().from(environmentBuilds).where(eq2(environmentBuilds.id, id)).get();
72199
72247
  }
72200
- setLog(id, log91) {
72201
- getDb().update(environmentBuilds).set({ log: log91 }).where(eq2(environmentBuilds.id, id)).run();
72248
+ setLog(id, log90) {
72249
+ getDb().update(environmentBuilds).set({ log: log90 }).where(eq2(environmentBuilds.id, id)).run();
72202
72250
  }
72203
72251
  finish(id, result) {
72204
72252
  getDb().update(environmentBuilds).set({
@@ -72566,32 +72614,32 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72566
72614
  }
72567
72615
  // ---- running ---------------------------------------------------------------
72568
72616
  async run(row, plan) {
72569
- const log91 = new BuildLog(row.id, (id, text4) => this.queries.setLog(id, text4));
72617
+ const log90 = new BuildLog(row.id, (id, text4) => this.queries.setLog(id, text4));
72570
72618
  let tmp = null;
72571
72619
  const container = `band-env-${row.id.slice(0, 12)}`;
72572
72620
  let failure4 = null;
72573
72621
  try {
72574
- log91.add(`Building ${plan.tag} for ${plan.repo} at ${plan.ref} (${plan.commit.slice(0, 12)})`);
72575
- log91.flush();
72622
+ log90.add(`Building ${plan.tag} for ${plan.repo} at ${plan.ref} (${plan.commit.slice(0, 12)})`);
72623
+ log90.flush();
72576
72624
  tmp = await plan.host.fs.mkdtemp("band-env-");
72577
- await this.exportCheckout(plan, tmp, log91);
72578
- const toolchain = await this.buildToolchain(plan, tmp, log91);
72579
- const layered = await this.addWorkerLayer(plan, tmp, toolchain, log91);
72580
- await this.install(plan, tmp, layered, container, log91);
72581
- if (plan.registry) await this.push(plan, log91);
72582
- log91.add(`Done: ${plan.tag}`);
72625
+ await this.exportCheckout(plan, tmp, log90);
72626
+ const toolchain = await this.buildToolchain(plan, tmp, log90);
72627
+ const layered = await this.addWorkerLayer(plan, tmp, toolchain, log90);
72628
+ await this.install(plan, tmp, layered, container, log90);
72629
+ if (plan.registry) await this.push(plan, log90);
72630
+ log90.add(`Done: ${plan.tag}`);
72583
72631
  } catch (err) {
72584
72632
  failure4 = err.message;
72585
- log91.add(`FAILED: ${failure4}`);
72633
+ log90.add(`FAILED: ${failure4}`);
72586
72634
  }
72587
- await this.exec(plan.host, "docker", ["rm", "--force", container], log91, { quiet: true }).catch(
72635
+ await this.exec(plan.host, "docker", ["rm", "--force", container], log90, { quiet: true }).catch(
72588
72636
  () => void 0
72589
72637
  );
72590
72638
  await this.exec(
72591
72639
  plan.host,
72592
72640
  "docker",
72593
72641
  ["rmi", toolchainTag(plan.repo, plan.key), layeredTag(plan.repo, plan.key)],
72594
- log91,
72642
+ log90,
72595
72643
  { quiet: true }
72596
72644
  ).catch(() => void 0);
72597
72645
  if (tmp) await plan.host.fs.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
@@ -72600,14 +72648,14 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72600
72648
  this.queries.finish(row.id, {
72601
72649
  status: "ready",
72602
72650
  image: plan.tag,
72603
- log: log91.toString(),
72651
+ log: log90.toString(),
72604
72652
  at: Date.now()
72605
72653
  });
72606
72654
  } else {
72607
72655
  this.queries.finish(row.id, {
72608
72656
  status: "failed",
72609
72657
  error: failure4.slice(0, 2e3),
72610
- log: log91.toString(),
72658
+ log: log90.toString(),
72611
72659
  at: Date.now()
72612
72660
  });
72613
72661
  }
@@ -72616,9 +72664,9 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72616
72664
  }
72617
72665
  }
72618
72666
  /** Runs a command on the builder host, adding it and its output to the log. */
72619
- async exec(host, tool, args, log91, options = {}) {
72667
+ async exec(host, tool, args, log90, options = {}) {
72620
72668
  const bin = tool === "docker" ? this.dockerBin(host) : tool === "devcontainer" ? this.devcontainerBin(host) : "git";
72621
- if (!options.quiet) log91.add(`$ ${tool} ${args.join(" ")}`);
72669
+ if (!options.quiet) log90.add(`$ ${tool} ${args.join(" ")}`);
72622
72670
  try {
72623
72671
  const out = await host.exec(bin, args, {
72624
72672
  cwd: options.cwd,
@@ -72626,35 +72674,35 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72626
72674
  timeoutMs: envNumber("BAND_ENVIRONMENT_BUILD_TIMEOUT_MS", DEFAULT_STEP_TIMEOUT_MS)
72627
72675
  });
72628
72676
  if (!options.quiet) {
72629
- if (out.stdout.trim()) log91.add(out.stdout.trimEnd());
72630
- if (out.stderr.trim()) log91.add(out.stderr.trimEnd());
72631
- log91.flush();
72677
+ if (out.stdout.trim()) log90.add(out.stdout.trimEnd());
72678
+ if (out.stderr.trim()) log90.add(out.stderr.trimEnd());
72679
+ log90.flush();
72632
72680
  }
72633
72681
  return out.stdout;
72634
72682
  } catch (err) {
72635
72683
  if (!options.quiet) {
72636
- log91.add(err.message);
72637
- log91.flush();
72684
+ log90.add(err.message);
72685
+ log90.flush();
72638
72686
  }
72639
72687
  throw new Error(`${tool} ${args[0] ?? ""} failed: ${firstLine(err.message)}`);
72640
72688
  }
72641
72689
  }
72642
72690
  /** Writes the default branch's files, with no `.git`, to `<tmp>/src`. */
72643
- async exportCheckout(plan, tmp, log91) {
72691
+ async exportCheckout(plan, tmp, log90) {
72644
72692
  const src = posix4.join(tmp, "src");
72645
72693
  await plan.host.fs.mkdir(src);
72646
72694
  const index3 = posix4.join(tmp, "index");
72647
- await this.exec(plan.host, "git", ["read-tree", plan.ref], log91, {
72695
+ await this.exec(plan.host, "git", ["read-tree", plan.ref], log90, {
72648
72696
  cwd: plan.repoPath,
72649
72697
  env: { GIT_INDEX_FILE: index3 }
72650
72698
  });
72651
- await this.exec(plan.host, "git", ["checkout-index", "--all", `--prefix=${src}/`], log91, {
72699
+ await this.exec(plan.host, "git", ["checkout-index", "--all", `--prefix=${src}/`], log90, {
72652
72700
  cwd: plan.repoPath,
72653
72701
  env: { GIT_INDEX_FILE: index3 }
72654
72702
  });
72655
72703
  }
72656
72704
  /** Layer 2: returns the tag of an image holding the repo's toolchain. */
72657
- async buildToolchain(plan, tmp, log91) {
72705
+ async buildToolchain(plan, tmp, log90) {
72658
72706
  const build = plan.environment.build;
72659
72707
  const src = posix4.join(tmp, "src");
72660
72708
  const tag = toolchainTag(plan.repo, plan.key);
@@ -72663,7 +72711,7 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72663
72711
  plan.host,
72664
72712
  "docker",
72665
72713
  dockerBuildArgs({ checkout: src, dockerfile: build.dockerfile, tag }),
72666
- log91
72714
+ log90
72667
72715
  );
72668
72716
  return tag;
72669
72717
  }
@@ -72673,7 +72721,7 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72673
72721
  plan.host,
72674
72722
  "devcontainer",
72675
72723
  devcontainerBuildArgs({ checkout: src, config: build.devcontainer, tag }),
72676
- log91
72724
+ log90
72677
72725
  );
72678
72726
  } catch (err) {
72679
72727
  throw new Error(
@@ -72683,11 +72731,11 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72683
72731
  return tag;
72684
72732
  }
72685
72733
  const image = build?.image;
72686
- await this.exec(plan.host, "docker", ["pull", image], log91);
72734
+ await this.exec(plan.host, "docker", ["pull", image], log90);
72687
72735
  return image;
72688
72736
  }
72689
72737
  /** Layer 1 on top of layer 2: copies the worker from the worker base image. */
72690
- async addWorkerLayer(plan, tmp, toolchain, log91) {
72738
+ async addWorkerLayer(plan, tmp, toolchain, log90) {
72691
72739
  const dir = posix4.join(tmp, "layer");
72692
72740
  await plan.host.fs.mkdir(dir);
72693
72741
  await plan.host.fs.writeFile(
@@ -72699,38 +72747,38 @@ ${this.text.slice(-MAX_LOG_BYTES)}`;
72699
72747
  });
72700
72748
  await plan.host.fs.mkdir(posix4.join(dir, "root", "work"), { recursive: true });
72701
72749
  const tag = layeredTag(plan.repo, plan.key);
72702
- await this.exec(plan.host, "docker", ["build", "--tag", tag, dir], log91);
72750
+ await this.exec(plan.host, "docker", ["build", "--tag", tag, dir], log90);
72703
72751
  return tag;
72704
72752
  }
72705
72753
  /** Runs `install` at the default branch inside the image and commits the result as the final tag. */
72706
- async install(plan, tmp, layered, container, log91) {
72754
+ async install(plan, tmp, layered, container, log90) {
72707
72755
  const install = plan.environment.install;
72708
72756
  if (install === void 0) {
72709
- await this.exec(plan.host, "docker", ["tag", layered, plan.tag], log91);
72757
+ await this.exec(plan.host, "docker", ["tag", layered, plan.tag], log90);
72710
72758
  return;
72711
72759
  }
72712
72760
  await this.exec(
72713
72761
  plan.host,
72714
72762
  "docker",
72715
72763
  installCreateArgs({ name: container, image: layered, install }),
72716
- log91
72764
+ log90
72717
72765
  );
72718
72766
  await this.exec(
72719
72767
  plan.host,
72720
72768
  "docker",
72721
72769
  ["cp", `${posix4.join(tmp, "src")}/.`, `${container}:${IMAGE_WORKDIR}`],
72722
- log91
72770
+ log90
72723
72771
  );
72724
- await this.exec(plan.host, "docker", ["start", "--attach", container], log91);
72772
+ await this.exec(plan.host, "docker", ["start", "--attach", container], log90);
72725
72773
  await this.exec(
72726
72774
  plan.host,
72727
72775
  "docker",
72728
72776
  commitArgs({ container, tag: plan.tag, key: plan.key, commit: plan.commit }),
72729
- log91
72777
+ log90
72730
72778
  );
72731
72779
  }
72732
- async push(plan, log91) {
72733
- await this.exec(plan.host, "docker", ["push", plan.tag], log91);
72780
+ async push(plan, log90) {
72781
+ await this.exec(plan.host, "docker", ["push", plan.tag], log90);
72734
72782
  }
72735
72783
  // ---- auto trigger ----------------------------------------------------------
72736
72784
  /**
@@ -75665,10 +75713,8 @@ var init_client_state_keys = __esm({
75665
75713
  perWorktree("band:dockview-layout-v9:", [jsonPart("device")]),
75666
75714
  // The `at` of the continuation the user has seen, which hides the sidebar clock icon.
75667
75715
  perWorktree("band:continued-seen:", [rawPart("device")]),
75668
- // The repo names the mobile app's worktree list has collapsed.
75716
+ // The repo and group names the mobile app's worktree list has collapsed.
75669
75717
  exact("band.mobile.collapsed-repos", [jsonPart("device")]),
75670
- // How the mobile worktree list is grouped: repo, origin or host.
75671
- exact("band.mobile.group-by", [rawPart("device")]),
75672
75718
  // The group the mobile worktree list is filtered to (a group id; unset means All).
75673
75719
  exact("band.mobile.group-filter", [rawPart("device")])
75674
75720
  ];
@@ -75803,7 +75849,7 @@ var init_client_state_service = __esm({
75803
75849
  }
75804
75850
  const updatedAt = Date.now();
75805
75851
  const version3 = input2.baseVersion + 1;
75806
- const written = input2.baseVersion === 0 ? this.queries.insertIfAbsent({
75852
+ let written = input2.baseVersion === 0 ? this.queries.insertIfAbsent({
75807
75853
  key: input2.key,
75808
75854
  scope: input2.scope,
75809
75855
  worktreeId: worktreeId4,
@@ -75815,6 +75861,16 @@ var init_client_state_service = __esm({
75815
75861
  version: version3,
75816
75862
  updatedAt
75817
75863
  });
75864
+ if (!written && input2.baseVersion === 0) {
75865
+ const current3 = this.queries.find(input2.key, input2.scope);
75866
+ if (current3 && current3.value === null) {
75867
+ written = this.queries.updateIfVersion(input2.key, input2.scope, current3.version, {
75868
+ value,
75869
+ version: current3.version + 1,
75870
+ updatedAt
75871
+ });
75872
+ }
75873
+ }
75818
75874
  const entry = this.queries.find(input2.key, input2.scope) ?? {
75819
75875
  key: input2.key,
75820
75876
  scope: input2.scope,
@@ -83233,7 +83289,7 @@ var init_agent_session_service = __esm({
83233
83289
  ownerGrants.delete(chatId);
83234
83290
  const grant = await worktree.host.relay?.issue({ worktreeId: chat.worktreeId, chatId });
83235
83291
  if (grant) ownerGrants.set(chatId, grant);
83236
- const shared2 = await openSharedDir(chat.worktreeId).catch(() => null);
83292
+ const shared2 = await openSharedDir(chat.worktreeId, chatId).catch(() => null);
83237
83293
  const login = await agentLoginService.resolve({
83238
83294
  agentType: def.type,
83239
83295
  repo: worktree.repo.name,
@@ -88139,11 +88195,11 @@ var require_core = __commonJS({
88139
88195
  Ajv2.ValidationError = validation_error_1.default;
88140
88196
  Ajv2.MissingRefError = ref_error_1.default;
88141
88197
  exports.default = Ajv2;
88142
- function checkOptions(checkOpts, options, msg, log91 = "error") {
88198
+ function checkOptions(checkOpts, options, msg, log90 = "error") {
88143
88199
  for (const key2 in checkOpts) {
88144
88200
  const opt = key2;
88145
88201
  if (opt in options)
88146
- this.logger[log91](`${msg}: option ${key2}. ${checkOpts[opt]}`);
88202
+ this.logger[log90](`${msg}: option ${key2}. ${checkOpts[opt]}`);
88147
88203
  }
88148
88204
  }
88149
88205
  function getSchEnv(keyRef) {
@@ -90632,10 +90688,11 @@ import {
90632
90688
  existsSync as existsSync18,
90633
90689
  mkdirSync as mkdirSync11,
90634
90690
  readFileSync as readFileSync12,
90691
+ realpathSync as realpathSync7,
90635
90692
  statSync as statSync16
90636
90693
  } from "node:fs";
90637
90694
  import { createServer as createServer3 } from "node:http";
90638
- import { basename as basename7, join as join59, resolve as resolve14, sep as sep10 } from "node:path";
90695
+ import { basename as basename7, join as join58, resolve as resolve14, sep as sep10 } from "node:path";
90639
90696
  import { pipeline as pipeline2, Readable as Readable2 } from "node:stream";
90640
90697
  import { parseArgs } from "node:util";
90641
90698
 
@@ -111646,7 +111703,7 @@ init_registry();
111646
111703
  // package.json
111647
111704
  var package_default = {
111648
111705
  name: "@band-app/server",
111649
- version: "0.53.0",
111706
+ version: "0.54.1",
111650
111707
  type: "module",
111651
111708
  types: "src/index.ts",
111652
111709
  exports: {
@@ -111686,6 +111743,7 @@ var package_default = {
111686
111743
  "@agentclientprotocol/claude-agent-acp": "0.81.2",
111687
111744
  "@agentclientprotocol/codex-acp": "1.13.1",
111688
111745
  "@agentclientprotocol/sdk": "1.5.0",
111746
+ "@anthropic-ai/sdk": "1.1.0",
111689
111747
  "@vscode/ripgrep": "^1.18.0",
111690
111748
  "node-pty": "^1.1.0",
111691
111749
  prettier: "^3.8.3",
@@ -112663,84 +112721,6 @@ init_git_credential_service();
112663
112721
  init_placement_service();
112664
112722
  init_token_service();
112665
112723
  init_watcher_service();
112666
-
112667
- // src/server/services/worker-cli-service.ts
112668
- init_cli_binary();
112669
- init_src7();
112670
- init_src();
112671
- import { createHash as createHash12 } from "node:crypto";
112672
- import { readFile as readFile12 } from "node:fs/promises";
112673
- import { join as join52 } from "node:path";
112674
- var log65 = createLogger("worker-cli");
112675
- var RPC_INVALID_PARAMS2 = -32602;
112676
- var PLATFORM_NAME = /^[a-z0-9_]{1,16}$/;
112677
- function candidatesFor(platform3, arch) {
112678
- const out = [];
112679
- const dir = process.env.BAND_CLI_BINARIES_DIR;
112680
- if (dir) out.push(join52(dir, `band-${platform3}-${arch}${platform3 === "win32" ? ".exe" : ""}`));
112681
- if (platform3 === process.platform && arch === process.arch) {
112682
- const own2 = findCliBinary();
112683
- if (own2) out.push(own2);
112684
- }
112685
- return out;
112686
- }
112687
- async function readFirst(paths) {
112688
- for (const path2 of paths) {
112689
- const data = await readFile12(path2).catch(() => null);
112690
- if (data) return data;
112691
- }
112692
- return null;
112693
- }
112694
- var WorkerCliService = class {
112695
- /** Answers `cli.fetch` on a worker's session. */
112696
- attach(session) {
112697
- session.handle(METHOD_CLI_FETCH, (params) => this.handle(session, params));
112698
- }
112699
- async handle(session, params) {
112700
- const { platform: platform3, arch, have } = parseParams3(params);
112701
- const data = await readFirst(candidatesFor(platform3, arch));
112702
- if (!data) {
112703
- return {
112704
- available: false,
112705
- reason: `the hub has no band CLI for ${platform3}-${arch}`
112706
- };
112707
- }
112708
- const sha2563 = createHash12("sha256").update(data).digest("hex");
112709
- if (have === sha2563) return { available: true, sha256: sha2563, size: data.length };
112710
- log65.info(
112711
- `sending the band CLI (${platform3}-${arch}, ${data.length} bytes) to ${session.workerId}`
112712
- );
112713
- const ch = session.openChannel("cli.body", { platform: platform3, arch });
112714
- void (async () => {
112715
- try {
112716
- await ch.send(data);
112717
- ch.end();
112718
- const drained = setTimeout(() => ch.reset("the worker did not close the channel"), 3e4);
112719
- drained.unref?.();
112720
- await ch.readAll().finally(() => clearTimeout(drained));
112721
- } catch (err) {
112722
- ch.reset(err instanceof Error ? err.message : "cli transfer failed");
112723
- }
112724
- })();
112725
- return { available: true, sha256: sha2563, size: data.length, chan: ch.id };
112726
- }
112727
- };
112728
- function parseParams3(params) {
112729
- const p2 = params ?? {};
112730
- if (typeof p2.platform !== "string" || !PLATFORM_NAME.test(p2.platform)) {
112731
- throw new RpcError(RPC_INVALID_PARAMS2, "platform must be a short lowercase name");
112732
- }
112733
- if (typeof p2.arch !== "string" || !PLATFORM_NAME.test(p2.arch)) {
112734
- throw new RpcError(RPC_INVALID_PARAMS2, "arch must be a short lowercase name");
112735
- }
112736
- if (p2.have !== void 0 && typeof p2.have !== "string") {
112737
- throw new RpcError(RPC_INVALID_PARAMS2, "have must be a string");
112738
- }
112739
- return { platform: p2.platform, arch: p2.arch, have: p2.have };
112740
- }
112741
- var workerCliService = new WorkerCliService();
112742
-
112743
- // src/server/services/worker-link-service.ts
112744
112724
  init_worker_lease_service();
112745
112725
 
112746
112726
  // src/server/services/worker-relay-service.ts
@@ -112800,7 +112780,7 @@ function repoHostRefusal(repo, callerHostId) {
112800
112780
  init_state();
112801
112781
  init_subscription_service();
112802
112782
  init_terminal_service();
112803
- var log66 = createLogger("worker-relay");
112783
+ var log65 = createLogger("worker-relay");
112804
112784
  var REPLY_HEADERS = ["content-type", "cache-control", "mcp-session-id"];
112805
112785
  var FORWARDED_HEADERS = [
112806
112786
  "content-type",
@@ -112809,7 +112789,7 @@ var FORWARDED_HEADERS = [
112809
112789
  "mcp-session-id",
112810
112790
  "last-event-id"
112811
112791
  ];
112812
- var RPC_INVALID_PARAMS3 = -32602;
112792
+ var RPC_INVALID_PARAMS2 = -32602;
112813
112793
  var defaultLookups = {
112814
112794
  hostOfWorktree: (id) => hostRegistry.hostIdOfScope(id),
112815
112795
  worktreeOfChat: (id) => {
@@ -112841,7 +112821,7 @@ var WorkerRelayService = class {
112841
112821
  let request = parseRequest(params);
112842
112822
  const verdict = checkRelayRequest(request, session.workerId, this.lookups);
112843
112823
  if (!verdict.ok) {
112844
- log66.warn(
112824
+ log65.warn(
112845
112825
  `refused ${request.method} ${request.path.split("?")[0]} from ${session.workerId}: ${verdict.reason}`
112846
112826
  );
112847
112827
  return this.answer(session, verdict.status, refusalBody(request, verdict));
@@ -112854,7 +112834,7 @@ var WorkerRelayService = class {
112854
112834
  chatId: request.scope.chatId,
112855
112835
  ...entry
112856
112836
  });
112857
- log66.info(
112837
+ log65.info(
112858
112838
  `admin host ${session.workerId} called ${entry.procedure}${entry.targetHostId ? ` on ${entry.targetHostId}` : ""}`
112859
112839
  );
112860
112840
  }
@@ -112887,7 +112867,7 @@ var WorkerRelayService = class {
112887
112867
  redirect: "manual"
112888
112868
  });
112889
112869
  } catch (err) {
112890
- log66.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112870
+ log65.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112891
112871
  return this.answer(session, 502, { error: "The hub could not answer" });
112892
112872
  }
112893
112873
  const replyHeaders = {};
@@ -112904,7 +112884,7 @@ var WorkerRelayService = class {
112904
112884
  try {
112905
112885
  return this.answer(session, upstream.status, redactSettingsReply(await upstream.json()));
112906
112886
  } catch (err) {
112907
- log66.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112887
+ log65.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112908
112888
  return this.answer(session, 502, { error: "The hub could not answer" });
112909
112889
  }
112910
112890
  }
@@ -112913,7 +112893,7 @@ var WorkerRelayService = class {
112913
112893
  const filtered = filterReposReply(await upstream.json(), session.workerId);
112914
112894
  return this.answer(session, upstream.status, filtered);
112915
112895
  } catch (err) {
112916
- log66.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112896
+ log65.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112917
112897
  return this.answer(session, 502, { error: "The hub could not answer" });
112918
112898
  }
112919
112899
  }
@@ -112921,7 +112901,7 @@ var WorkerRelayService = class {
112921
112901
  try {
112922
112902
  return this.answer(session, upstream.status, redactHostsReply(await upstream.json()));
112923
112903
  } catch (err) {
112924
- log66.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112904
+ log65.warn(`relay call failed: ${err instanceof Error ? err.message : err}`);
112925
112905
  return this.answer(session, 502, { error: "The hub could not answer" });
112926
112906
  }
112927
112907
  }
@@ -112966,7 +112946,7 @@ function parseRequest(params) {
112966
112946
  const p2 = params;
112967
112947
  const scope3 = p2?.scope;
112968
112948
  if (!p2 || typeof p2.method !== "string" || typeof p2.path !== "string" || typeof scope3?.worktreeId !== "string" || scope3.chatId !== void 0 && typeof scope3.chatId !== "string" || scope3.terminalId !== void 0 && typeof scope3.terminalId !== "string" || !/^\/(?![/\\])/.test(p2.path) || !["GET", "POST", "DELETE", "OPTIONS", "HEAD"].includes(p2.method) || typeof p2.headers !== "object" || p2.headers === null || Object.values(p2.headers).some((v2) => typeof v2 !== "string") || p2.body !== void 0 && typeof p2.body !== "string") {
112969
- throw new RpcError(RPC_INVALID_PARAMS3, "bad relay.http params");
112949
+ throw new RpcError(RPC_INVALID_PARAMS2, "bad relay.http params");
112970
112950
  }
112971
112951
  return p2;
112972
112952
  }
@@ -112974,7 +112954,7 @@ var workerRelayService = new WorkerRelayService();
112974
112954
 
112975
112955
  // src/server/services/worker-link-service.ts
112976
112956
  init_worktree_service();
112977
- var log67 = createLogger("worker-link");
112957
+ var log66 = createLogger("worker-link");
112978
112958
  var repoQueries5 = new RepoQueries();
112979
112959
  var LOCAL_HOST_ID12 = "local";
112980
112960
  var CAPABILITY_REFRESH_MS = 3 * 6e4;
@@ -113002,9 +112982,18 @@ var WorkerLinkService = class {
113002
112982
  this.server = new LinkServer({ authenticate: (hello) => this.authenticate(hello) });
113003
112983
  this.server.on("session", (session) => this.onSession(session));
113004
112984
  this.server.on("connected", (session) => void this.onConnected(session));
112985
+ this.server.on("disconnected", (session) => {
112986
+ const close = session.lastClose;
112987
+ if (close) {
112988
+ log66.info(
112989
+ `link of ${session.workerId} closed (code ${close.code}${close.reason ? `, ${close.reason}` : ""})`
112990
+ );
112991
+ }
112992
+ this.setStatus(session.workerId, "offline", this.now());
112993
+ });
113005
112994
  this.server.on(
113006
- "disconnected",
113007
- (session) => this.setStatus(session.workerId, "offline", this.now())
112995
+ "fault",
112996
+ (session, reason) => log66.warn(`link of ${session.workerId}: ${reason}`)
113008
112997
  );
113009
112998
  this.server.on(
113010
112999
  "lost",
@@ -113029,12 +113018,12 @@ var WorkerLinkService = class {
113029
113018
  const problem2 = compatibilityProblem(version3, HUB_VERSION);
113030
113019
  if (!problem2) return auth2;
113031
113020
  if (HUB_VERSION_UNRELEASED) {
113032
- log67.info(
113021
+ log66.info(
113033
113022
  `worker ${hello.workerId} runs ${version3}, which would be refused by a released hub, but this hub runs from source (${HUB_VERSION}), so version checks are skipped`
113034
113023
  );
113035
113024
  return auth2;
113036
113025
  }
113037
- log67.warn(`worker ${hello.workerId} refused: ${problem2}`);
113026
+ log66.warn(`worker ${hello.workerId} refused: ${problem2}`);
113038
113027
  if (this.server.getSession(hello.workerId)?.attached) {
113039
113028
  return { ok: false, reason: problem2, code: VERSION_REFUSED_CODE };
113040
113029
  }
@@ -113045,7 +113034,7 @@ var WorkerLinkService = class {
113045
113034
  try {
113046
113035
  this.queries.setHostRefusal(hello.workerId, { version: version3, reason: problem2 });
113047
113036
  } catch (err) {
113048
- log67.warn(`could not record the refusal: ${err instanceof Error ? err.message : err}`);
113037
+ log66.warn(`could not record the refusal: ${err instanceof Error ? err.message : err}`);
113049
113038
  }
113050
113039
  this.publish(hello.workerId, "offline");
113051
113040
  return { ok: false, reason: problem2, code: VERSION_REFUSED_CODE };
@@ -113068,7 +113057,7 @@ var WorkerLinkService = class {
113068
113057
  this.refreshTimer.unref();
113069
113058
  this.unsubscribeRevoke = this.tokens.onRevoked((row) => {
113070
113059
  if (row.kind === "worker_session" && row.hostId) {
113071
- if (this.server.drop(row.hostId, "token revoked")) log67.info(`cut link of ${row.hostId}`);
113060
+ if (this.server.drop(row.hostId, "token revoked")) log66.info(`cut link of ${row.hostId}`);
113072
113061
  }
113073
113062
  });
113074
113063
  }
@@ -113098,7 +113087,7 @@ var WorkerLinkService = class {
113098
113087
  this.queries.setHostInfo(row.id, stored);
113099
113088
  if (changed) this.publish(row.id, "online");
113100
113089
  } catch (err) {
113101
- log67.debug(
113090
+ log66.debug(
113102
113091
  `could not refresh the report of ${row.id}: ${err instanceof Error ? err.message : err}`
113103
113092
  );
113104
113093
  }
@@ -113128,7 +113117,6 @@ var WorkerLinkService = class {
113128
113117
  onSession(session) {
113129
113118
  this.remoteHost(session.workerId).attachSession(session);
113130
113119
  workerRelayService.attach(session);
113131
- workerCliService.attach(session);
113132
113120
  gitCredentialService.attach(session);
113133
113121
  ephemeralLifecycleService.attach(session);
113134
113122
  checkpointService.attach(session);
@@ -113142,7 +113130,7 @@ var WorkerLinkService = class {
113142
113130
  try {
113143
113131
  info = await this.remoteHost(workerId).info();
113144
113132
  } catch (err) {
113145
- log67.warn(
113133
+ log66.warn(
113146
113134
  `could not read host info from ${workerId}: ${err instanceof Error ? err.message : err}`
113147
113135
  );
113148
113136
  }
@@ -113162,37 +113150,37 @@ var WorkerLinkService = class {
113162
113150
  const version3 = workerVersionOf(hello);
113163
113151
  this.queries.markHostOnline(workerId, at, { info: stored, version: version3 ?? hello.buildId });
113164
113152
  workerUpdateService.onConnected(workerId, version3);
113165
- log67.info(`worker ${workerId} is online`);
113153
+ log66.info(`worker ${workerId} is online`);
113166
113154
  workerLeaseService.onConnected(session);
113167
113155
  try {
113168
113156
  seedCodingAgentsFromTypes(hello.agents);
113169
113157
  } catch (err) {
113170
- log67.warn(`could not seed coding agents: ${err instanceof Error ? err.message : err}`);
113158
+ log66.warn(`could not seed coding agents: ${err instanceof Error ? err.message : err}`);
113171
113159
  }
113172
113160
  this.publish(workerId, "online");
113173
113161
  void repoService.backfillRemotesFromWorker(workerId).catch((err) => {
113174
- log67.warn(`remote backfill on ${workerId}: ${err instanceof Error ? err.message : err}`);
113162
+ log66.warn(`remote backfill on ${workerId}: ${err instanceof Error ? err.message : err}`);
113175
113163
  });
113176
113164
  chatOwnershipService.onConnected(session);
113177
113165
  void ephemeralLifecycleService.onConnected(session);
113178
113166
  void followService.onHostReturned(workerId).catch((err) => {
113179
- log67.warn(`follow check on ${workerId}: ${err instanceof Error ? err.message : err}`);
113167
+ log66.warn(`follow check on ${workerId}: ${err instanceof Error ? err.message : err}`);
113180
113168
  });
113181
113169
  placementService.onHostOnline(workerId);
113182
113170
  void worktreeService.finishPendingRemovals(workerId).catch((err) => {
113183
- log67.warn(`pending removals on ${workerId}: ${err instanceof Error ? err.message : err}`);
113171
+ log66.warn(`pending removals on ${workerId}: ${err instanceof Error ? err.message : err}`);
113184
113172
  });
113185
113173
  }
113186
113174
  setStatus(workerId, status, lastSeenAt) {
113187
113175
  try {
113188
113176
  this.queries.setHostStatus(workerId, status, lastSeenAt);
113189
113177
  } catch (err) {
113190
- log67.warn(
113178
+ log66.warn(
113191
113179
  `could not record ${workerId} as ${status}: ${err instanceof Error ? err.message : err}`
113192
113180
  );
113193
113181
  return;
113194
113182
  }
113195
- log67.info(`worker ${workerId} is ${status}`);
113183
+ log66.info(`worker ${workerId} is ${status}`);
113196
113184
  this.publish(workerId, status);
113197
113185
  }
113198
113186
  publish(hostId2, hostStatus) {
@@ -113237,7 +113225,7 @@ var WorkerLinkService = class {
113237
113225
  send3(200, out);
113238
113226
  } catch (err) {
113239
113227
  if (!(err instanceof TokenExchangeError)) throw err;
113240
- log67.warn(`bootstrap exchange refused: ${err.reason}`);
113228
+ log66.warn(`bootstrap exchange refused: ${err.reason}`);
113241
113229
  send3(401, { error: "invalid or expired token" });
113242
113230
  }
113243
113231
  }
@@ -113254,7 +113242,7 @@ function reportKey(report2) {
113254
113242
 
113255
113243
  // src/server/services/worker-update-service.ts
113256
113244
  init_worktree_service();
113257
- var log68 = createLogger("worker-update");
113245
+ var log67 = createLogger("worker-update");
113258
113246
  var INSTALL_TIMEOUT_MS = 11 * 6e4;
113259
113247
  var RESTART_TIMEOUT_MS = 3 * 6e4;
113260
113248
  var WorkerUpdateError = class extends Error {
@@ -113300,7 +113288,7 @@ var WorkerUpdateService = class {
113300
113288
  throw new WorkerUpdateError("not-updatable", "The worker is not connected");
113301
113289
  const target = view4.updateTarget;
113302
113290
  this.set(hostId2, { target, state: "installing", error: null }, row.status);
113303
- log68.info(`updating worker ${hostId2} to ${target}`);
113291
+ log67.info(`updating worker ${hostId2} to ${target}`);
113304
113292
  void this.run(hostId2, target, session, row.status);
113305
113293
  return { target };
113306
113294
  }
@@ -113314,7 +113302,7 @@ var WorkerUpdateService = class {
113314
113302
  } catch (err) {
113315
113303
  const message = this.describe(err, target);
113316
113304
  this.set(hostId2, { target, state: "failed", error: message }, hostStatus);
113317
- log68.warn(`update of worker ${hostId2} failed: ${message}`);
113305
+ log67.warn(`update of worker ${hostId2} failed: ${message}`);
113318
113306
  return;
113319
113307
  }
113320
113308
  if (this.updates.get(hostId2)?.state !== "installing") return;
@@ -113351,7 +113339,7 @@ var WorkerUpdateService = class {
113351
113339
  this.timers.delete(hostId2);
113352
113340
  if (version3 === current3.target) {
113353
113341
  this.updates.delete(hostId2);
113354
- log68.info(`worker ${hostId2} now runs ${version3}`);
113342
+ log67.info(`worker ${hostId2} now runs ${version3}`);
113355
113343
  } else {
113356
113344
  this.set(
113357
113345
  hostId2,
@@ -116176,9 +116164,9 @@ init_zod();
116176
116164
  // src/server/services/provisioning-service.ts
116177
116165
  init_src();
116178
116166
  init_dist();
116179
- import { createHash as createHash13, randomBytes as randomBytes16, randomUUID as randomUUID18 } from "node:crypto";
116167
+ import { createHash as createHash12, randomBytes as randomBytes16, randomUUID as randomUUID18 } from "node:crypto";
116180
116168
  import { createReadStream as createReadStream4, existsSync as existsSync17, mkdirSync as mkdirSync10, rmSync as rmSync7, statSync as statSync14 } from "node:fs";
116181
- import { join as join53 } from "node:path";
116169
+ import { join as join52 } from "node:path";
116182
116170
 
116183
116171
  // src/server/infra/db/queries/provisions.ts
116184
116172
  init_drizzle_orm2();
@@ -116205,11 +116193,11 @@ var ProvisionQueries = class {
116205
116193
  const result = this.db().update(hostProvisions).set({ spentAt: at, hostId: hostId2, runHash, state: "running", updatedAt: at }).where(and2(eq2(hostProvisions.id, id), isNull2(hostProvisions.spentAt))).run();
116206
116194
  return Number(result.changes ?? 0) > 0;
116207
116195
  }
116208
- setLog(id, log91, at) {
116209
- this.db().update(hostProvisions).set({ log: log91, updatedAt: at }).where(eq2(hostProvisions.id, id)).run();
116196
+ setLog(id, log90, at) {
116197
+ this.db().update(hostProvisions).set({ log: log90, updatedAt: at }).where(eq2(hostProvisions.id, id)).run();
116210
116198
  }
116211
- finish(id, state2, exitCode, log91, at) {
116212
- this.db().update(hostProvisions).set({ state: state2, exitCode, log: log91, updatedAt: at }).where(eq2(hostProvisions.id, id)).run();
116199
+ finish(id, state2, exitCode, log90, at) {
116200
+ this.db().update(hostProvisions).set({ state: state2, exitCode, log: log90, updatedAt: at }).where(eq2(hostProvisions.id, id)).run();
116213
116201
  }
116214
116202
  /** Ids of rows created before `at`, so their bundle files can be deleted. */
116215
116203
  idsCreatedBefore(at) {
@@ -116461,7 +116449,7 @@ function renderProvisionScript(opts) {
116461
116449
  init_settings_service();
116462
116450
  init_token_service();
116463
116451
  init_vault_service();
116464
- var log69 = createLogger("provisioning");
116452
+ var log68 = createLogger("provisioning");
116465
116453
  var DEFAULT_PROVISION_TTL_MS = 60 * 60 * 1e3;
116466
116454
  var DEFAULT_START_COMMAND = "band/provision.sh";
116467
116455
  var MAX_LOG_BYTES2 = 256 * 1024;
@@ -116493,7 +116481,7 @@ var ProvisionAuthError = class extends Error {
116493
116481
  }
116494
116482
  };
116495
116483
  function sha2562(text4) {
116496
- return createHash13("sha256").update(text4).digest("hex");
116484
+ return createHash12("sha256").update(text4).digest("hex");
116497
116485
  }
116498
116486
  function newSecret(prefix) {
116499
116487
  return `${prefix}${randomBytes16(32).toString("base64url")}`;
@@ -116536,7 +116524,7 @@ var ProvisioningService = class {
116536
116524
  return Date.now();
116537
116525
  }
116538
116526
  dir(id) {
116539
- return join53(bandHome(), "provisioning", id);
116527
+ return join52(bandHome(), "provisioning", id);
116540
116528
  }
116541
116529
  settings() {
116542
116530
  const s2 = settingsService.get().provisioning ?? {};
@@ -116591,7 +116579,7 @@ var ProvisioningService = class {
116591
116579
  spentAt: null,
116592
116580
  updatedAt: at
116593
116581
  });
116594
- log69.info(
116582
+ log68.info(
116595
116583
  `created provisioning command ${id}${commitSha ? ` at ${commitSha.slice(0, 12)}` : ""}`
116596
116584
  );
116597
116585
  const command2 = `curl -fsSL ${hubUrl}/api/provision/${code}/script | sh`;
@@ -116631,7 +116619,7 @@ var ProvisioningService = class {
116631
116619
  tokenService.removeHost(boot.hostId);
116632
116620
  throw new ProvisionExchangeError("used");
116633
116621
  }
116634
- log69.info(`exchanged provisioning code ${row.id} for host ${boot.hostId}`);
116622
+ log68.info(`exchanged provisioning code ${row.id} for host ${boot.hostId}`);
116635
116623
  const lines = [
116636
116624
  `token=${boot.token}`,
116637
116625
  `workerId=${boot.hostId}`,
@@ -116656,7 +116644,7 @@ var ProvisioningService = class {
116656
116644
  /** The bundle file and size for a code, once its run token is shown. */
116657
116645
  bundle(code, runToken) {
116658
116646
  const row = this.authorize(code, runToken);
116659
- const file3 = join53(this.dir(row.id), "bundle.tgz");
116647
+ const file3 = join52(this.dir(row.id), "bundle.tgz");
116660
116648
  if (!row.repoUrl || !existsSync17(file3)) throw new ProvisionAuthError();
116661
116649
  return { stream: createReadStream4(file3), size: statSync14(file3).size };
116662
116650
  }
@@ -116673,7 +116661,7 @@ var ProvisioningService = class {
116673
116661
  return;
116674
116662
  }
116675
116663
  this.queries.finish(row.id, exit === 0 ? "done" : "failed", exit, next, at);
116676
- if (exit !== 0) log69.info(`provisioning ${row.id} failed with exit code ${exit}`);
116664
+ if (exit !== 0) log68.info(`provisioning ${row.id} failed with exit code ${exit}`);
116677
116665
  }
116678
116666
  status(id) {
116679
116667
  const row = this.queries.findById(id);
@@ -116698,7 +116686,7 @@ band provision: the worker did not say hello within ${minutes} min. Marked faile
116698
116686
  `;
116699
116687
  const exitCode = row.exitCode ?? TIMEOUT_EXIT_CODE;
116700
116688
  this.queries.finish(row.id, "failed", exitCode, row.log + note, at);
116701
- log69.info(`provisioning ${row.id} timed out waiting for host ${row.hostId}`);
116689
+ log68.info(`provisioning ${row.id} timed out waiting for host ${row.hostId}`);
116702
116690
  return { ...row, state: "failed", exitCode, log: row.log + note };
116703
116691
  }
116704
116692
  view(spent) {
@@ -116735,7 +116723,7 @@ band provision: the worker did not say hello within ${minutes} min. Marked faile
116735
116723
  async buildBundle(id, settings3) {
116736
116724
  const dir = this.dir(id);
116737
116725
  mkdirSync10(dir, { recursive: true });
116738
- const src = join53(dir, "src");
116726
+ const src = join52(dir, "src");
116739
116727
  const host = hostRegistry.local;
116740
116728
  const env = { GIT_TERMINAL_PROMPT: "0" };
116741
116729
  const key2 = parseRemoteUrl2(settings3.repoUrl);
@@ -116757,10 +116745,10 @@ band provision: the worker did not say hello within ${minutes} min. Marked faile
116757
116745
  await host.exec("git", args, { env, timeoutMs: 12e4 });
116758
116746
  const sha = (await host.exec("git", ["-C", src, "rev-parse", "HEAD"], { env })).stdout.trim();
116759
116747
  const command2 = settings3.command || DEFAULT_START_COMMAND;
116760
- if (!existsSync17(join53(src, command2))) {
116748
+ if (!existsSync17(join52(src, command2))) {
116761
116749
  throw new Error(`the repo at ${sha.slice(0, 12)} has no ${command2}`);
116762
116750
  }
116763
- await host.exec("tar", ["-czf", join53(dir, "bundle.tgz"), "--exclude=.git", "-C", src, "."], {
116751
+ await host.exec("tar", ["-czf", join52(dir, "bundle.tgz"), "--exclude=.git", "-C", src, "."], {
116764
116752
  timeoutMs: 12e4
116765
116753
  });
116766
116754
  rmSync7(src, { recursive: true, force: true });
@@ -116853,12 +116841,12 @@ init_zod();
116853
116841
  init_registry();
116854
116842
  init_queued_message_store();
116855
116843
  import { realpathSync as realpathSync6 } from "node:fs";
116856
- import { join as join54, resolve as resolve11, sep as sep7 } from "node:path";
116844
+ import { join as join53, resolve as resolve11, sep as sep7 } from "node:path";
116857
116845
  init_chat_ownership_service();
116858
116846
  init_chat_service();
116859
116847
  init_state();
116860
116848
  init_task_service();
116861
- var log70 = createLogger("trpc.queue");
116849
+ var log69 = createLogger("trpc.queue");
116862
116850
  var queuedFileSchema = external_exports2.object({
116863
116851
  mediaType: external_exports2.string(),
116864
116852
  url: external_exports2.string(),
@@ -116866,7 +116854,7 @@ var queuedFileSchema = external_exports2.object({
116866
116854
  filename: external_exports2.string().optional()
116867
116855
  });
116868
116856
  function isPathWithinUploadDir(p2) {
116869
- const uploadDir = join54(bandHome(), "uploads");
116857
+ const uploadDir = join53(bandHome(), "uploads");
116870
116858
  const normalized2 = resolve11(p2);
116871
116859
  if (normalized2 !== uploadDir && !normalized2.startsWith(uploadDir + sep7)) {
116872
116860
  return false;
@@ -116891,7 +116879,7 @@ async function resolveQueuedFiles(chatId, worktreeId4, files) {
116891
116879
  if (derivedPath) {
116892
116880
  const inside = remote ? await isWithinUploads(worktreeId4, derivedPath) : isPathWithinUploadDir(derivedPath);
116893
116881
  if (!inside) {
116894
- log70.warn(
116882
+ log69.warn(
116895
116883
  { chatId, path: derivedPath, filename: file3.filename },
116896
116884
  "queue: dropping file with path outside uploads directory"
116897
116885
  );
@@ -116916,7 +116904,7 @@ async function resolveQueuedFiles(chatId, worktreeId4, files) {
116916
116904
  });
116917
116905
  continue;
116918
116906
  }
116919
- log70.warn(
116907
+ log69.warn(
116920
116908
  { chatId, url: file3.url, filename: file3.filename },
116921
116909
  "queue: dropping file with no path and non-data URL \u2014 cannot recover disk path"
116922
116910
  );
@@ -116924,7 +116912,7 @@ async function resolveQueuedFiles(chatId, worktreeId4, files) {
116924
116912
  if (needsSave.length > 0) {
116925
116913
  const saved = await saveWorktreeUploads(worktreeId4, needsSave);
116926
116914
  if (saved.length !== needsSave.length) {
116927
- log70.error(
116915
+ log69.error(
116928
116916
  { chatId, expected: needsSave.length, got: saved.length },
116929
116917
  "queue: saveUploadedFilesDetailed returned unexpected count \u2014 dropping data-URL files (cannot map 1:1)"
116930
116918
  );
@@ -116957,7 +116945,7 @@ var queueRouter = t.router({
116957
116945
  try {
116958
116946
  files = await resolveQueuedFiles(chatId, input2.worktreeId, input2.files);
116959
116947
  } catch (err) {
116960
- log70.error(
116948
+ log69.error(
116961
116949
  { chatId, err: err instanceof Error ? err.message : err },
116962
116950
  "queue.push: failed to persist file uploads; enqueuing text only"
116963
116951
  );
@@ -117007,7 +116995,7 @@ var queueRouter = t.router({
117007
116995
  files: await resolveQueuedFiles(chatId, input2.worktreeId, m2.files)
117008
116996
  };
117009
116997
  } catch (err) {
117010
- log70.error(
116998
+ log69.error(
117011
116999
  { chatId, messageId: m2.id, err: err instanceof Error ? err.message : err },
117012
117000
  "queue: failed to resolve files for queued message; dropping its files"
117013
117001
  );
@@ -117164,7 +117152,7 @@ function aggregateTurnsByHourAndModel(snap, provider) {
117164
117152
  }
117165
117153
  return Array.from(buckets.values());
117166
117154
  }
117167
- var log71 = createLogger("usage-scanner");
117155
+ var log70 = createLogger("usage-scanner");
117168
117156
  var SCHEDULER_KEY2 = Symbol.for("band.usage-scanner");
117169
117157
  var g7 = globalThis;
117170
117158
  if (!g7[SCHEDULER_KEY2]) {
@@ -117226,14 +117214,14 @@ var UsageScannerService = class {
117226
117214
  try {
117227
117215
  totalRows += await this.scanPair(ws, a);
117228
117216
  } catch (err) {
117229
- log71.warn(
117217
+ log70.warn(
117230
117218
  { err, worktreeId: ws.worktreeId, agentType: a.agentType },
117231
117219
  "usage scanner pair failed"
117232
117220
  );
117233
117221
  }
117234
117222
  }
117235
117223
  }
117236
- log71.debug(
117224
+ log70.debug(
117237
117225
  { durationMs: this.now() - started, worktrees: worktrees2.length, rowsWritten: totalRows },
117238
117226
  "usage scanner tick complete"
117239
117227
  );
@@ -117278,7 +117266,7 @@ var UsageScannerService = class {
117278
117266
  try {
117279
117267
  reader = await this.getUsageReader(a, ws.hostId);
117280
117268
  } catch (err) {
117281
- log71.debug({ err, agentId: a.agentId }, "failed to resolve usage reader for scan");
117269
+ log70.debug({ err, agentId: a.agentId }, "failed to resolve usage reader for scan");
117282
117270
  return 0;
117283
117271
  }
117284
117272
  if (!reader) return 0;
@@ -117287,7 +117275,7 @@ var UsageScannerService = class {
117287
117275
  try {
117288
117276
  sessions = await reader.listSessions(ws.worktreePath);
117289
117277
  } catch (err) {
117290
- log71.debug(
117278
+ log70.debug(
117291
117279
  { err, agentId: a.agentId, worktreePath: ws.worktreePath },
117292
117280
  "listSessions failed during usage scan"
117293
117281
  );
@@ -117303,7 +117291,7 @@ var UsageScannerService = class {
117303
117291
  try {
117304
117292
  snap = await reader.getSessionUsage(s2.sessionId, ws.worktreePath);
117305
117293
  } catch (err) {
117306
- log71.debug(
117294
+ log70.debug(
117307
117295
  { err, sessionId: s2.sessionId, agentType: a.agentType },
117308
117296
  "getSessionUsage failed"
117309
117297
  );
@@ -117342,7 +117330,7 @@ var UsageScannerService = class {
117342
117330
  this.scanState.set(ws.worktreeId, a.agentType, maxObserved);
117343
117331
  }
117344
117332
  if (changed.length > slice.length) {
117345
- log71.debug(
117333
+ log70.debug(
117346
117334
  {
117347
117335
  worktreeId: ws.worktreeId,
117348
117336
  agentType: a.agentType,
@@ -117409,11 +117397,11 @@ function startUsageScanner(options = {}) {
117409
117397
  const intervalMs = options.intervalMs ?? USAGE_SCAN_INTERVAL_MS;
117410
117398
  const svc = getUsageScannerService();
117411
117399
  svc.tick().catch((err) => {
117412
- log71.warn({ err }, "initial usage scanner tick failed");
117400
+ log70.warn({ err }, "initial usage scanner tick failed");
117413
117401
  });
117414
117402
  const timer = setInterval(() => {
117415
117403
  svc.tick().catch((err) => {
117416
- log71.warn({ err }, "scheduled usage scanner tick failed");
117404
+ log70.warn({ err }, "scheduled usage scanner tick failed");
117417
117405
  });
117418
117406
  }, intervalMs);
117419
117407
  timer.unref();
@@ -117784,7 +117772,7 @@ function worktreeGh(host, localHostId, cwd) {
117784
117772
  init_branch_status_poller();
117785
117773
  init_plugin_host_service();
117786
117774
  init_worktree_service();
117787
- var log72 = createLogger("review-service");
117775
+ var log71 = createLogger("review-service");
117788
117776
  var NoOpenReviewError = class extends Error {
117789
117777
  constructor(worktreeId4) {
117790
117778
  super(`No open review to merge for worktree ${worktreeId4}`);
@@ -117825,7 +117813,7 @@ var ReviewService = class {
117825
117813
  };
117826
117814
  } catch (err) {
117827
117815
  const message = err instanceof Error ? err.message : String(err);
117828
- log72.warn("Review lookup failed for %s (%s): %s", worktreeId4, provider.id, message);
117816
+ log71.warn("Review lookup failed for %s (%s): %s", worktreeId4, provider.id, message);
117829
117817
  return { status: "error", message };
117830
117818
  }
117831
117819
  }
@@ -117990,7 +117978,7 @@ init_ephemeral_lifecycle_service();
117990
117978
  init_runner_service();
117991
117979
  init_state();
117992
117980
  init_token_service();
117993
- var log73 = createLogger("reaper");
117981
+ var log72 = createLogger("reaper");
117994
117982
  var DEFAULT_INTERVAL_MS = 3e4;
117995
117983
  var DEFAULT_HELLO_GRACE_MS = 6e4;
117996
117984
  var DEFAULT_OFFLINE_MS = 12e4;
@@ -118087,12 +118075,12 @@ var RunnerReaperService = class {
118087
118075
  try {
118088
118076
  await this.reap(machine, Date.now());
118089
118077
  } catch (err) {
118090
- log73.warn(`could not check machine ${machine.id}: ${errorText5(err)}`);
118078
+ log72.warn(`could not check machine ${machine.id}: ${errorText5(err)}`);
118091
118079
  }
118092
118080
  }
118093
118081
  await this.reapOrphans();
118094
118082
  } catch (err) {
118095
- log73.warn(`sweep failed: ${errorText5(err)}`);
118083
+ log72.warn(`sweep failed: ${errorText5(err)}`);
118096
118084
  } finally {
118097
118085
  this.ticking = false;
118098
118086
  }
@@ -118154,7 +118142,7 @@ var RunnerReaperService = class {
118154
118142
  const deadline = machine.spawnedAt + lifetimeMs + runner.lifetimeGraceSec * 1e3;
118155
118143
  if (machine.state === "running") {
118156
118144
  this.machines.update(machine.id, { state: "stopping", stoppingSince: now });
118157
- log73.info(`machine ${machine.id} reached its maximum lifetime of ${runner.maxLifetimeSec}s`);
118145
+ log72.info(`machine ${machine.id} reached its maximum lifetime of ${runner.maxLifetimeSec}s`);
118158
118146
  }
118159
118147
  const reason = `maximum lifetime of ${runner.maxLifetimeSec}s reached`;
118160
118148
  if (!online) {
@@ -118200,7 +118188,7 @@ var RunnerReaperService = class {
118200
118188
  return;
118201
118189
  }
118202
118190
  const lost = this.unstored(machine.workerId);
118203
- log73.error(
118191
+ log72.error(
118204
118192
  `HARD DEADLINE: destroying machine ${machine.id} (${reason}) although worktree(s) ${lost.join(", ") || "of its worker"} were not stored`
118205
118193
  );
118206
118194
  await this.destroyNow(
@@ -118227,11 +118215,11 @@ var RunnerReaperService = class {
118227
118215
  const key2 = `${machine.id}:${text4}`;
118228
118216
  if (!this.warned.has(key2)) {
118229
118217
  this.warned.add(key2);
118230
- log73.info(`machine ${machine.id}: ${text4}`);
118218
+ log72.info(`machine ${machine.id}: ${text4}`);
118231
118219
  }
118232
118220
  }
118233
118221
  async destroyNow(machine, reason, opts = {}) {
118234
- log73.info(`destroying machine ${machine.id} of runner ${machine.runnerId}: ${reason}`);
118222
+ log72.info(`destroying machine ${machine.id} of runner ${machine.runnerId}: ${reason}`);
118235
118223
  const task = this.runners.destroyMachine(machine.id, reason);
118236
118224
  this.pending.add(task);
118237
118225
  try {
@@ -118247,7 +118235,7 @@ var RunnerReaperService = class {
118247
118235
  tokenService.removeHost(hostId2);
118248
118236
  hostRegistry.unregister(hostId2);
118249
118237
  } catch (err) {
118250
- log73.warn(`could not remove host ${hostId2}: ${errorText5(err)}`);
118238
+ log72.warn(`could not remove host ${hostId2}: ${errorText5(err)}`);
118251
118239
  }
118252
118240
  }
118253
118241
  // ---- orphans ---------------------------------------------------------------
@@ -118266,7 +118254,7 @@ var RunnerReaperService = class {
118266
118254
  try {
118267
118255
  handles = await this.runners.listHandles(runner);
118268
118256
  } catch (err) {
118269
- log73.warn(`status of runner ${runner.id} failed: ${errorText5(err)}`);
118257
+ log72.warn(`status of runner ${runner.id} failed: ${errorText5(err)}`);
118270
118258
  continue;
118271
118259
  }
118272
118260
  if (this.runners.hasAttemptInFlight(runner.id)) continue;
@@ -118278,10 +118266,10 @@ var RunnerReaperService = class {
118278
118266
  if (nowKnown.has(handle)) continue;
118279
118267
  const ok2 = await this.runners.destroyHandle(runner, handle, "no record of this machine");
118280
118268
  if (ok2) {
118281
- log73.info(`destroyed orphan ${handle} of runner ${runner.id}`);
118269
+ log72.info(`destroyed orphan ${handle} of runner ${runner.id}`);
118282
118270
  this.machines.settleHandle(runner.id, handle, "destroyed by the reaper as an orphan");
118283
118271
  } else {
118284
- log73.warn(`could not destroy orphan ${handle} of runner ${runner.id}`);
118272
+ log72.warn(`could not destroy orphan ${handle} of runner ${runner.id}`);
118285
118273
  }
118286
118274
  }
118287
118275
  }
@@ -118347,7 +118335,7 @@ init_errors6();
118347
118335
  init_agent_session_service();
118348
118336
  init_chat_service();
118349
118337
  init_worktree_service();
118350
- var log74 = createLogger("session-service");
118338
+ var log73 = createLogger("session-service");
118351
118339
  var SessionService = class {
118352
118340
  /** Lists past sessions for a worktree's chat pane (default chat when
118353
118341
  * `chatId` is undefined). */
@@ -118360,7 +118348,7 @@ var SessionService = class {
118360
118348
  if (!chatService.get(chatId)) {
118361
118349
  chatService.create(input2.worktreeId, { id: chatId, name: "Chat" });
118362
118350
  }
118363
- log74.debug({ chatId, worktreeId: input2.worktreeId }, "listing past sessions for chat");
118351
+ log73.debug({ chatId, worktreeId: input2.worktreeId }, "listing past sessions for chat");
118364
118352
  return agentSessionService.listSessions(chatId);
118365
118353
  }
118366
118354
  };
@@ -118687,7 +118675,7 @@ init_branch_status_poller();
118687
118675
  init_client_activity_service();
118688
118676
  init_state();
118689
118677
  init_tunnel_service();
118690
- var log75 = createLogger("trpc.system");
118678
+ var log74 = createLogger("trpc.system");
118691
118679
  var systemRouter = t.router({
118692
118680
  /**
118693
118681
  * Combined liveness probe — webserver is always true if this query
@@ -118695,16 +118683,16 @@ var systemRouter = t.router({
118695
118683
  * an interval to drive the bottom-bar status pill.
118696
118684
  */
118697
118685
  health: publicProcedure.query(() => {
118698
- log75.debug("services.health called");
118686
+ log74.debug("services.health called");
118699
118687
  const tunnel = tunnelService.getStatus();
118700
- log75.debug({ tunnel }, "services.health: tunnel status");
118688
+ log74.debug({ tunnel }, "services.health: tunnel status");
118701
118689
  const result = {
118702
118690
  webserver: true,
118703
118691
  version: package_default.version,
118704
118692
  tunnel: tunnel.running,
118705
118693
  tunnel_url: tunnel.url
118706
118694
  };
118707
- log75.debug({ result }, "services.health result");
118695
+ log74.debug({ result }, "services.health result");
118708
118696
  return result;
118709
118697
  }),
118710
118698
  // What this client's UI is doing, so the branch-status poller can slow down. A client names
@@ -118843,7 +118831,7 @@ init_errors6();
118843
118831
  init_chat_service();
118844
118832
  init_state();
118845
118833
  init_task_service();
118846
- var log76 = createLogger("tasks-router");
118834
+ var log75 = createLogger("tasks-router");
118847
118835
  var tasksRouter = t.router({
118848
118836
  list: publicProcedure.input(
118849
118837
  external_exports2.object({
@@ -118905,7 +118893,7 @@ var tasksRouter = t.router({
118905
118893
  if (input2.files && input2.files.length > 0) {
118906
118894
  const savedFiles = await saveWorktreeUploads(input2.worktreeId, input2.files);
118907
118895
  if (savedFiles.length !== input2.files.length) {
118908
- log76.warn(
118896
+ log75.warn(
118909
118897
  { chatId, submitted: input2.files.length, saved: savedFiles.length },
118910
118898
  "tasks.submit: some file uploads were dropped (malformed data URL?)"
118911
118899
  );
@@ -119331,25 +119319,25 @@ var tokensRouter = t.router({
119331
119319
  init_src();
119332
119320
  init_zod();
119333
119321
  init_tunnel_service();
119334
- var log77 = createLogger("trpc.tunnel");
119322
+ var log76 = createLogger("trpc.tunnel");
119335
119323
  var tunnelRouter = t.router({
119336
119324
  status: publicProcedure.query(() => {
119337
119325
  return tunnelService.getStatus();
119338
119326
  }),
119339
119327
  start: publicProcedure.input(external_exports2.object({}).optional()).mutation(async () => {
119340
- log77.debug("tunnel.start called");
119328
+ log76.debug("tunnel.start called");
119341
119329
  try {
119342
119330
  await tunnelService.start();
119343
119331
  } catch (err) {
119344
- log77.debug({ err }, "tunnel.start: startTunnel failed");
119332
+ log76.debug({ err }, "tunnel.start: startTunnel failed");
119345
119333
  return { ok: true, url: null };
119346
119334
  }
119347
119335
  const status = tunnelService.getStatus();
119348
- log77.debug({ status }, "tunnel.start: after startTunnel");
119336
+ log76.debug({ status }, "tunnel.start: after startTunnel");
119349
119337
  if (status.url) {
119350
119338
  return { ok: true, url: status.url };
119351
119339
  }
119352
- log77.debug("tunnel.start: no URL available");
119340
+ log76.debug("tunnel.start: no URL available");
119353
119341
  return { ok: true, url: null };
119354
119342
  }),
119355
119343
  stop: publicProcedure.mutation(async () => {
@@ -119739,8 +119727,8 @@ function verifyWorktreePreviewGrant(worktreeId4, grant, filePath, now = Date.now
119739
119727
  init_src2();
119740
119728
  init_src();
119741
119729
  init_resolver();
119742
- import { join as join55, resolve as resolve12, sep as sep8 } from "node:path";
119743
- var log78 = createLogger("diff-service");
119730
+ import { join as join54, resolve as resolve12, sep as sep8 } from "node:path";
119731
+ var log77 = createLogger("diff-service");
119744
119732
  var EMPTY_TREE_ARGS = ["hash-object", "-t", "tree", "/dev/null"];
119745
119733
  var DEFAULT_BRANCH_LIMIT = 50;
119746
119734
  var STAGING_BRANCH_PRIORITY = [
@@ -119836,7 +119824,7 @@ function parseFileStatuses(nameStatusOutput) {
119836
119824
  return fileStatuses;
119837
119825
  }
119838
119826
  function assertWorktreeRelative(cwd, filePath) {
119839
- const target = resolve12(join55(cwd, filePath));
119827
+ const target = resolve12(join54(cwd, filePath));
119840
119828
  if (target !== cwd && !target.startsWith(cwd + sep8)) {
119841
119829
  throw new Error("Invalid path");
119842
119830
  }
@@ -119851,7 +119839,7 @@ function assertWorktreeRelative(cwd, filePath) {
119851
119839
  }
119852
119840
  async function readUntrackedFileLines(host, cwd, file3) {
119853
119841
  try {
119854
- const content = new TextDecoder().decode(await host.fs.readFile(join55(cwd, file3)));
119842
+ const content = new TextDecoder().decode(await host.fs.readFile(join54(cwd, file3)));
119855
119843
  const lines = content.split("\n");
119856
119844
  if (lines.length > 0 && lines[lines.length - 1] === "") {
119857
119845
  lines.pop();
@@ -120087,7 +120075,7 @@ var DiffService = class {
120087
120075
  );
120088
120076
  refs = output2.split("\n").map((line2) => parseBranchRef(line2.trim())).filter((ref) => ref !== null);
120089
120077
  } catch (err) {
120090
- log78.error(
120078
+ log77.error(
120091
120079
  `listBranches: for-each-ref failed for ${cwd}: ${err instanceof Error ? err.message : err}`
120092
120080
  );
120093
120081
  }
@@ -120198,7 +120186,7 @@ var DiffService = class {
120198
120186
  const compareBranch = options.compareBranch ?? defaultBranch;
120199
120187
  const cwd = worktree.worktree.path;
120200
120188
  const execGit2 = gitRunner(worktree.host);
120201
- const hasGit = await worktree.host.fs.stat(join55(cwd, ".git")).then(
120189
+ const hasGit = await worktree.host.fs.stat(join54(cwd, ".git")).then(
120202
120190
  () => true,
120203
120191
  (err) => {
120204
120192
  if (err instanceof HostOfflineError || err instanceof HostTimeoutError) throw err;
@@ -120236,7 +120224,7 @@ var DiffService = class {
120236
120224
  applyLineCounts(status.staged, parseNumstat(stagedNumstat));
120237
120225
  await Promise.all(
120238
120226
  status.untracked.map(async (entry) => {
120239
- const lines = await countUntrackedLines(worktree.host, join55(cwd, entry.path));
120227
+ const lines = await countUntrackedLines(worktree.host, join54(cwd, entry.path));
120240
120228
  if (lines !== null) {
120241
120229
  entry.additions = lines;
120242
120230
  entry.deletions = 0;
@@ -120393,7 +120381,7 @@ init_src();
120393
120381
  init_errors6();
120394
120382
  init_local_host_policy();
120395
120383
  init_worktree_service();
120396
- var log79 = createLogger("direct-access");
120384
+ var log78 = createLogger("direct-access");
120397
120385
  var DEFAULT_TOKEN_TTL_MS2 = 10 * 6e4;
120398
120386
  function tokenTtlMs() {
120399
120387
  const ms = Number(process.env.BAND_DIRECT_TOKEN_TTL_MS);
@@ -120428,7 +120416,7 @@ var DirectAccessService = class {
120428
120416
  );
120429
120417
  return { hostId: hostId2, ...grant };
120430
120418
  } catch (err) {
120431
- log79.debug(
120419
+ log78.debug(
120432
120420
  { hostId: hostId2, worktreeId: worktreeId4, message: err instanceof Error ? err.message : String(err) },
120433
120421
  "no direct path to the worker"
120434
120422
  );
@@ -120440,7 +120428,7 @@ var directAccessService = new DirectAccessService();
120440
120428
 
120441
120429
  // ../../packages/worktree-ops/src/files.ts
120442
120430
  init_resolver();
120443
- import { dirname as dirname16, extname as extname3, join as join56, resolve as resolve13, sep as sep9 } from "node:path";
120431
+ import { dirname as dirname16, extname as extname3, join as join55, resolve as resolve13, sep as sep9 } from "node:path";
120444
120432
  var MAX_FILE_SIZE2 = 1024 * 1024;
120445
120433
  var LANG_MAP2 = {
120446
120434
  ".js": "javascript",
@@ -120507,7 +120495,7 @@ var FilesService = class {
120507
120495
  throw new WorktreeNotFoundError(worktreeId4);
120508
120496
  }
120509
120497
  const root = worktree.worktree.path;
120510
- const target = resolve13(join56(root, relative2));
120498
+ const target = resolve13(join55(root, relative2));
120511
120499
  const insideRoot = target === root || target.startsWith(root + sep9);
120512
120500
  if (!insideRoot) {
120513
120501
  throw new Error("Invalid path");
@@ -120688,7 +120676,7 @@ var filesService = new FilesService({
120688
120676
 
120689
120677
  // src/server/services/git-graph-service.ts
120690
120678
  init_src2();
120691
- import { createHash as createHash14 } from "node:crypto";
120679
+ import { createHash as createHash13 } from "node:crypto";
120692
120680
  init_errors6();
120693
120681
  init_worktree_service();
120694
120682
  var FS = "";
@@ -120760,7 +120748,7 @@ var GitGraphService = class {
120760
120748
  } catch {
120761
120749
  return "";
120762
120750
  }
120763
- return createHash14("sha1").update(out).digest("hex");
120751
+ return createHash13("sha1").update(out).digest("hex");
120764
120752
  }
120765
120753
  /**
120766
120754
  * One page of HEAD's history, newest first in topological order, so every
@@ -122804,7 +122792,7 @@ async function readBody2(req, max3) {
122804
122792
  // src/server/api/mcp-proxy/stdio.ts
122805
122793
  init_src();
122806
122794
  init_mcp_stdio_service();
122807
- var log80 = createLogger("mcp-proxy-stdio");
122795
+ var log79 = createLogger("mcp-proxy-stdio");
122808
122796
  var MAX_REQUEST_BYTES = 4 * 1024 * 1024;
122809
122797
  var sessionHeader = (req) => {
122810
122798
  const value = req.headers["mcp-session-id"];
@@ -122935,7 +122923,7 @@ data: ${JSON.stringify(message)}
122935
122923
  if (gone) {
122936
122924
  return sendJson3(res, 404, { error: "The stdio MCP server's session ended" });
122937
122925
  }
122938
- log80.warn(
122926
+ log79.warn(
122939
122927
  { server: server.name, err: err instanceof Error ? err.name : "unknown" },
122940
122928
  "no answer"
122941
122929
  );
@@ -122960,7 +122948,7 @@ data: ${JSON.stringify(message)}
122960
122948
  }
122961
122949
 
122962
122950
  // src/server/api/mcp-proxy/handler.ts
122963
- var log81 = createLogger("mcp-proxy");
122951
+ var log80 = createLogger("mcp-proxy");
122964
122952
  var MCP_PROXY_PREFIX = "/mcp-proxy/";
122965
122953
  var ROUTE = /^\/mcp-proxy\/([^/]+)\/?$/;
122966
122954
  var MAX_REQUEST_BYTES2 = 4 * 1024 * 1024;
@@ -123122,13 +123110,13 @@ async function handleMcpProxy(req, res) {
123122
123110
  try {
123123
123111
  upstream = await sendUpstream(server, { method, headers, body, signal: abort.signal });
123124
123112
  } catch (err) {
123125
- log81.warn({ server: name5, err: errorCode2(err) }, "upstream failed");
123113
+ log80.warn({ server: name5, err: errorCode2(err) }, "upstream failed");
123126
123114
  auditUnanswered(server, auth2.sessionId, plan, "upstream-unreachable");
123127
123115
  return sendJson3(res, 502, { error: "The upstream MCP server did not answer" });
123128
123116
  }
123129
123117
  if (upstream.status === 401 || upstream.status >= 300 && upstream.status < 400) {
123130
123118
  await upstream.body?.cancel().catch(() => void 0);
123131
- log81.warn({ server: name5, status: upstream.status }, "upstream refused the stored credential");
123119
+ log80.warn({ server: name5, status: upstream.status }, "upstream refused the stored credential");
123132
123120
  auditUnanswered(server, auth2.sessionId, plan, `upstream-${upstream.status}`);
123133
123121
  return sendJson3(res, 502, {
123134
123122
  error: upstream.status === 401 ? "The upstream MCP server rejected the stored credential" : "The upstream MCP server redirected, which the proxy does not follow"
@@ -123196,7 +123184,7 @@ async function handleMcpProxy(req, res) {
123196
123184
  } catch (err) {
123197
123185
  auditUnanswered(server, auth2.sessionId, plan, "stream-failed");
123198
123186
  if (!abort.signal.aborted) {
123199
- log81.warn(
123187
+ log80.warn(
123200
123188
  { server: name5, err: errorCode2(err) },
123201
123189
  err instanceof SseEventTooLargeError ? "event too large to inspect" : "proxy stream failed"
123202
123190
  );
@@ -123231,7 +123219,7 @@ function getScalarHtml(specUrl) {
123231
123219
  // src/server/api/pairing/handler.ts
123232
123220
  init_src();
123233
123221
  init_token_service();
123234
- var log82 = createLogger("pairing");
123222
+ var log81 = createLogger("pairing");
123235
123223
  var PAIR_EXCHANGE_PATH = "/api/pair/exchange";
123236
123224
  var MAX_BODY_BYTES2 = 4096;
123237
123225
  var PAIR_REFUSED_MESSAGE = "This link was already used or has expired. Ask for a new one in Settings > Devices.";
@@ -123323,7 +123311,7 @@ async function handlePairExchange(req, res) {
123323
123311
  send3(200, out, { "Set-Cookie": buildCookieHeader(out.token, isSecure(req)) });
123324
123312
  } catch (err) {
123325
123313
  if (!(err instanceof PairingExchangeError)) throw err;
123326
- log82.debug(`pairing exchange refused: ${err.reason}`);
123314
+ log81.debug(`pairing exchange refused: ${err.reason}`);
123327
123315
  send3(401, { error: PAIR_REFUSED_MESSAGE });
123328
123316
  }
123329
123317
  }
@@ -123331,7 +123319,7 @@ async function handlePairExchange(req, res) {
123331
123319
  // src/server/api/provisioning/handler.ts
123332
123320
  init_src();
123333
123321
  import { pipeline } from "node:stream";
123334
- var log83 = createLogger("provisioning");
123322
+ var log82 = createLogger("provisioning");
123335
123323
  var PROVISION_PREFIX = "/api/provision/";
123336
123324
  var MAX_EXCHANGE_BODY_BYTES2 = 4096;
123337
123325
  var MAX_LOG_BODY_BYTES = 128 * 1024;
@@ -123388,7 +123376,7 @@ async function handleProvision(req, res) {
123388
123376
  send3(200, provisioningService.exchange(code2), "text/plain; charset=utf-8");
123389
123377
  } catch (err) {
123390
123378
  if (!(err instanceof ProvisionExchangeError)) throw err;
123391
- log83.debug(`provisioning exchange refused: ${err.reason}`);
123379
+ log82.debug(`provisioning exchange refused: ${err.reason}`);
123392
123380
  refused();
123393
123381
  }
123394
123382
  return;
@@ -123524,7 +123512,7 @@ var OutputFlow = class {
123524
123512
  };
123525
123513
 
123526
123514
  // ../../packages/worktree-ops/src/terminal-socket.ts
123527
- var log84 = createLogger("terminal-ws");
123515
+ var log83 = createLogger("terminal-ws");
123528
123516
  var MAX_CLOSE_REASON_BYTES = 123;
123529
123517
  var HEARTBEAT_INTERVAL_MS2 = 3e4;
123530
123518
  function clampCloseReason(reason) {
@@ -123592,7 +123580,7 @@ function createInbox(ws) {
123592
123580
  };
123593
123581
  }
123594
123582
  function attachSession(backend, ws, inbox, terminalId, worktreeId4, isNew, pendingMessage) {
123595
- log84.debug(
123583
+ log83.debug(
123596
123584
  "Terminal %s: %s (worktree %s)",
123597
123585
  isNew ? "connected" : "reconnected",
123598
123586
  terminalId,
@@ -123612,7 +123600,7 @@ function attachSession(backend, ws, inbox, terminalId, worktreeId4, isNew, pendi
123612
123600
  });
123613
123601
  const unsubscribeExit = backend.onExit(terminalId, (event) => {
123614
123602
  unsubscribeTitle();
123615
- log84.debug("PTY exited with code %d for terminal %s", event.exitCode, terminalId);
123603
+ log83.debug("PTY exited with code %d for terminal %s", event.exitCode, terminalId);
123616
123604
  if (ws.readyState === ws.OPEN) {
123617
123605
  ws.close(1e3, "Terminal exited");
123618
123606
  }
@@ -123640,7 +123628,7 @@ function attachSession(backend, ws, inbox, terminalId, worktreeId4, isNew, pendi
123640
123628
  try {
123641
123629
  attached = await backend.attach(terminalId, dims);
123642
123630
  } catch (err) {
123643
- log84.error("Failed to attach terminal %s: %s", terminalId, err);
123631
+ log83.error("Failed to attach terminal %s: %s", terminalId, err);
123644
123632
  safeClose(ws, 1011, "Terminal attach failed");
123645
123633
  return;
123646
123634
  }
@@ -123682,7 +123670,7 @@ function attachSession(backend, ws, inbox, terminalId, worktreeId4, isNew, pendi
123682
123670
  const cols = Number.isFinite(parsed.cols) && parsed.cols > 0 ? parsed.cols : void 0;
123683
123671
  const rows = Number.isFinite(parsed.rows) && parsed.rows > 0 ? parsed.rows : void 0;
123684
123672
  void startReplay(cols, rows, parsed.flow === true).catch((err) => {
123685
- log84.error("Failed to replay terminal %s: %s", terminalId, err);
123673
+ log83.error("Failed to replay terminal %s: %s", terminalId, err);
123686
123674
  });
123687
123675
  return;
123688
123676
  }
@@ -123702,7 +123690,7 @@ function attachSession(backend, ws, inbox, terminalId, worktreeId4, isNew, pendi
123702
123690
  flow?.dispose();
123703
123691
  attachment?.detach();
123704
123692
  unsubscribeExit();
123705
- log84.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
123693
+ log83.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
123706
123694
  });
123707
123695
  if (pendingMessage) {
123708
123696
  processMessage(pendingMessage);
@@ -123725,7 +123713,7 @@ function handleMessage(backend, ws, terminalId, message) {
123725
123713
  }
123726
123714
  if (parsed.type === "close") {
123727
123715
  void backend.kill(terminalId).catch((err) => {
123728
- log84.error("Failed to kill terminal %s: %s", terminalId, err);
123716
+ log83.error("Failed to kill terminal %s: %s", terminalId, err);
123729
123717
  });
123730
123718
  ws.close(1e3, "Terminal closed by client");
123731
123719
  return;
@@ -123741,7 +123729,7 @@ function handleMessage(backend, ws, terminalId, message) {
123741
123729
 
123742
123730
  // src/server/api/terminals/ws.ts
123743
123731
  init_terminal_service();
123744
- var log85 = createLogger("terminal-ws");
123732
+ var log84 = createLogger("terminal-ws");
123745
123733
  async function handleTerminalConnection(ws, req) {
123746
123734
  if (!req.url) {
123747
123735
  safeClose(ws, 4e3, "Missing request URL");
@@ -123760,7 +123748,7 @@ async function handleTerminalConnection(ws, req) {
123760
123748
  existing = await terminalService.info(terminalId) !== null;
123761
123749
  } catch (err) {
123762
123750
  const msg = err instanceof Error ? err.message : String(err);
123763
- log85.error("Failed to look up terminal %s: %s", terminalId, msg);
123751
+ log84.error("Failed to look up terminal %s: %s", terminalId, msg);
123764
123752
  safeClose(ws, 1011, msg);
123765
123753
  return;
123766
123754
  }
@@ -123808,7 +123796,7 @@ async function handleTerminalConnection(ws, req) {
123808
123796
  await terminalService.spawn(worktreeId4, terminalId, spawnOpts);
123809
123797
  } catch (err) {
123810
123798
  const msg = err instanceof Error ? err.message : String(err);
123811
- log85.error("Failed to spawn terminal %s for worktree %s: %s", terminalId, worktreeId4, msg);
123799
+ log84.error("Failed to spawn terminal %s for worktree %s: %s", terminalId, worktreeId4, msg);
123812
123800
  safeClose(ws, 4001, msg);
123813
123801
  return;
123814
123802
  }
@@ -123908,14 +123896,14 @@ async function handleVoiceTranscribe(req, res) {
123908
123896
 
123909
123897
  // src/server/api/web-app-manifest.ts
123910
123898
  import { createReadStream as createReadStream5, statSync as statSync15 } from "node:fs";
123911
- import { join as join57 } from "node:path";
123899
+ import { join as join56 } from "node:path";
123912
123900
  var WEB_APP_MANIFEST_PATH = "/manifest.webmanifest";
123913
123901
  var ICON_FILES = ["band-192.png", "band-512.png", "apple-touch-icon.png"];
123914
123902
  function handleWebAppManifest(req, res, publicDir) {
123915
123903
  if (req.method !== "GET" && req.method !== "HEAD") return false;
123916
123904
  const pathname = req.url?.split("?")[0];
123917
123905
  if (pathname === WEB_APP_MANIFEST_PATH) {
123918
- sendFile(req, res, join57(publicDir, "manifest.webmanifest"), {
123906
+ sendFile(req, res, join56(publicDir, "manifest.webmanifest"), {
123919
123907
  "Content-Type": "application/manifest+json",
123920
123908
  "Cache-Control": "no-cache"
123921
123909
  });
@@ -123923,7 +123911,7 @@ function handleWebAppManifest(req, res, publicDir) {
123923
123911
  }
123924
123912
  const icon = ICON_FILES.find((name5) => pathname === `/icons/${name5}`);
123925
123913
  if (!icon) return false;
123926
- sendFile(req, res, join57(publicDir, "icons", icon), {
123914
+ sendFile(req, res, join56(publicDir, "icons", icon), {
123927
123915
  "Content-Type": "image/png",
123928
123916
  "Cache-Control": "public, max-age=86400"
123929
123917
  });
@@ -123947,7 +123935,7 @@ init_src();
123947
123935
  init_wrapper();
123948
123936
  init_browser_lookup();
123949
123937
  init_remote_cdp();
123950
- var log86 = createLogger("cdp-proxy");
123938
+ var log85 = createLogger("cdp-proxy");
123951
123939
  async function handleCdpConnection(ws, req) {
123952
123940
  const url3 = new URL(req.url ?? "", `http://${req.headers.host}`);
123953
123941
  const bandTabId = url3.searchParams.get("bandTabId");
@@ -123990,17 +123978,17 @@ async function handleCdpConnection(ws, req) {
123990
123978
  cdpTargetId = await ensureCdpTargetId(bandTabId);
123991
123979
  } catch (err) {
123992
123980
  const message = err instanceof Error ? err.message : String(err);
123993
- log86.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
123981
+ log85.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
123994
123982
  if (ws.readyState === ws.OPEN) {
123995
123983
  ws.close(4001, message.slice(0, 123));
123996
123984
  }
123997
123985
  return;
123998
123986
  }
123999
123987
  const upstreamUrl = `ws://${DESKTOP_CDP_HOST}:${DESKTOP_CDP_PORT}/devtools/page/${encodeURIComponent(cdpTargetId)}`;
124000
- log86.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
123988
+ log85.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
124001
123989
  upstream = new wrapper_default(upstreamUrl);
124002
123990
  upstream.on("open", () => {
124003
- log86.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
123991
+ log85.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
124004
123992
  for (const msg of pending2) {
124005
123993
  upstream?.send(msg);
124006
123994
  }
@@ -124012,20 +124000,20 @@ async function handleCdpConnection(ws, req) {
124012
124000
  }
124013
124001
  });
124014
124002
  upstream.on("error", (err) => {
124015
- log86.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
124003
+ log85.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
124016
124004
  markTargetDestroyed(bandTabId);
124017
124005
  if (ws.readyState === ws.OPEN) {
124018
124006
  ws.close(4001, `Desktop CDP error: ${err.message}`.slice(0, 123));
124019
124007
  }
124020
124008
  });
124021
124009
  upstream.on("close", (code) => {
124022
- log86.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
124010
+ log85.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
124023
124011
  if (ws.readyState === ws.OPEN) {
124024
124012
  ws.close(1e3, "Upstream closed");
124025
124013
  }
124026
124014
  });
124027
124015
  ws.on("close", () => {
124028
- log86.debug("CDP client closed bandTabId=%s", bandTabId);
124016
+ log85.debug("CDP client closed bandTabId=%s", bandTabId);
124029
124017
  if (upstream && (upstream.readyState === wrapper_default.OPEN || upstream.readyState === wrapper_default.CONNECTING)) {
124030
124018
  try {
124031
124019
  upstream.close();
@@ -124034,7 +124022,7 @@ async function handleCdpConnection(ws, req) {
124034
124022
  }
124035
124023
  });
124036
124024
  ws.on("error", (err) => {
124037
- log86.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
124025
+ log85.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
124038
124026
  try {
124039
124027
  upstream?.close();
124040
124028
  } catch {
@@ -124064,7 +124052,7 @@ async function bridgeRemote(ws, worktreeId4) {
124064
124052
  cdp = await openRemoteCdp(worktreeId4);
124065
124053
  } catch (err) {
124066
124054
  const message = err instanceof Error ? err.message : String(err);
124067
- log86.warn("remote CDP failed for worktree %s: %s", worktreeId4, message);
124055
+ log85.warn("remote CDP failed for worktree %s: %s", worktreeId4, message);
124068
124056
  if (ws.readyState === ws.OPEN)
124069
124057
  ws.close(4001, closeReason(`Remote browser unavailable: ${message}`));
124070
124058
  return true;
@@ -124088,7 +124076,7 @@ async function bridgeRemote(ws, worktreeId4) {
124088
124076
  if (ws.readyState === ws.OPEN) ws.send(message);
124089
124077
  }
124090
124078
  } catch (err) {
124091
- log86.debug("remote CDP stream ended for worktree %s: %s", worktreeId4, String(err));
124079
+ log85.debug("remote CDP stream ended for worktree %s: %s", worktreeId4, String(err));
124092
124080
  }
124093
124081
  if (ws.readyState === ws.OPEN) ws.close(1e3, "Upstream closed");
124094
124082
  })();
@@ -124098,7 +124086,7 @@ async function bridgeRemote(ws, worktreeId4) {
124098
124086
  // src/server/infra/browser-host/cdp-targets.ts
124099
124087
  init_src();
124100
124088
  init_wrapper();
124101
- var log87 = createLogger("cdp-targets");
124089
+ var log86 = createLogger("cdp-targets");
124102
124090
  var CdpUnreachableError = class extends Error {
124103
124091
  constructor(message) {
124104
124092
  super(message);
@@ -124154,7 +124142,7 @@ async function captureSnapshot(bandTabId) {
124154
124142
  });
124155
124143
  ws.on("error", (err) => {
124156
124144
  clearTimeout(timeout);
124157
- log87.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
124145
+ log86.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
124158
124146
  markTargetDestroyed(bandTabId);
124159
124147
  settle2(new CdpUnreachableError(err.message));
124160
124148
  });
@@ -124281,7 +124269,7 @@ var RfbClientFilter = class {
124281
124269
  };
124282
124270
 
124283
124271
  // src/server/infra/host/desktop-proxy.ts
124284
- var log88 = createLogger("desktop-proxy");
124272
+ var log87 = createLogger("desktop-proxy");
124285
124273
  var DESKTOP_PATH = /^\/api\/hosts\/([^/]+)\/desktop$/;
124286
124274
  function desktopHostId(pathname) {
124287
124275
  const match = DESKTOP_PATH.exec(pathname);
@@ -124330,7 +124318,7 @@ async function handleDesktopConnection(ws, req, hostId2) {
124330
124318
  );
124331
124319
  if (enabled !== null) {
124332
124320
  filter.viewOnly = !enabled;
124333
- log88.debug("desktop of host %s is now %s", hostId2, enabled ? "controlled" : "view-only");
124321
+ log87.debug("desktop of host %s is now %s", hostId2, enabled ? "controlled" : "view-only");
124334
124322
  }
124335
124323
  return;
124336
124324
  }
@@ -124365,7 +124353,7 @@ async function handleDesktopConnection(ws, req, hostId2) {
124365
124353
  opened = true;
124366
124354
  } catch (err) {
124367
124355
  const message = err instanceof Error ? err.message : String(err);
124368
- log88.warn("desktop of host %s is unavailable: %s", hostId2, message);
124356
+ log87.warn("desktop of host %s is unavailable: %s", hostId2, message);
124369
124357
  release();
124370
124358
  ws.close(4001, message.slice(0, 120));
124371
124359
  return;
@@ -124375,7 +124363,7 @@ async function handleDesktopConnection(ws, req, hostId2) {
124375
124363
  release();
124376
124364
  return;
124377
124365
  }
124378
- log88.debug("desktop viewer connected: %s (%s)", hostId2, req.socket.remoteAddress ?? "unknown");
124366
+ log87.debug("desktop viewer connected: %s (%s)", hostId2, req.socket.remoteAddress ?? "unknown");
124379
124367
  for (const chunk of pending2.splice(0)) desktop.write(chunk);
124380
124368
  try {
124381
124369
  for await (const bytes of desktop.output) {
@@ -124383,7 +124371,7 @@ async function handleDesktopConnection(ws, req, hostId2) {
124383
124371
  await new Promise((resolve15) => ws.send(bytes, { binary: true }, () => resolve15()));
124384
124372
  }
124385
124373
  } catch (err) {
124386
- log88.warn("desktop stream of host %s failed: %s", hostId2, err.message);
124374
+ log87.warn("desktop stream of host %s failed: %s", hostId2, err.message);
124387
124375
  } finally {
124388
124376
  if (opened) {
124389
124377
  desktop.close();
@@ -124401,7 +124389,7 @@ init_src();
124401
124389
  init_worktrees();
124402
124390
  init_registry();
124403
124391
  var worktreeQueries2 = new WorktreeQueries();
124404
- var log89 = createLogger("lsp-proxy");
124392
+ var log88 = createLogger("lsp-proxy");
124405
124393
  function frameMessage(json3) {
124406
124394
  const body = Buffer.from(json3, "utf-8");
124407
124395
  const header = `Content-Length: ${body.byteLength}\r
@@ -124419,7 +124407,7 @@ function createFrameParser(onMessage) {
124419
124407
  const headerStr = buffer.subarray(0, separatorIdx).toString("ascii");
124420
124408
  const match = headerStr.match(/Content-Length:\s*(\d+)/i);
124421
124409
  if (!match) {
124422
- log89.warn("Malformed LSP header: %s", headerStr);
124410
+ log88.warn("Malformed LSP header: %s", headerStr);
124423
124411
  buffer = buffer.subarray(separatorIdx + 4);
124424
124412
  continue;
124425
124413
  }
@@ -124464,7 +124452,7 @@ async function handleLspConnection(ws, req) {
124464
124452
  connection = await hostRegistry.hostFor(worktreeId4).lsp.connect({ worktreeId: worktreeId4, lang, root: worktree.worktreePath });
124465
124453
  } catch (err) {
124466
124454
  const message = err instanceof Error ? err.message : String(err);
124467
- log89.error("Failed to spawn %s language server for worktree %s: %s", lang, worktreeId4, message);
124455
+ log88.error("Failed to spawn %s language server for worktree %s: %s", lang, worktreeId4, message);
124468
124456
  ws.close(4001, message);
124469
124457
  return;
124470
124458
  }
@@ -124472,7 +124460,7 @@ async function handleLspConnection(ws, req) {
124472
124460
  connection.close();
124473
124461
  return;
124474
124462
  }
124475
- log89.debug("LSP client connected: %s/%s", worktreeId4, lang);
124463
+ log88.debug("LSP client connected: %s/%s", worktreeId4, lang);
124476
124464
  const pendingRequests = /* @__PURE__ */ new Map();
124477
124465
  const openDocuments = /* @__PURE__ */ new Set();
124478
124466
  const serverId = `${worktreeId4}:${lang}`;
@@ -124508,7 +124496,7 @@ async function handleLspConnection(ws, req) {
124508
124496
  const retriedIds = /* @__PURE__ */ new Set();
124509
124497
  const RETRY_DELAY_MS = 2e3;
124510
124498
  const parseFrame = createFrameParser((json3) => {
124511
- log89.debug(
124499
+ log88.debug(
124512
124500
  "LSP stdout [%s/%s]: %s",
124513
124501
  worktreeId4,
124514
124502
  lang,
@@ -124520,7 +124508,7 @@ async function handleLspConnection(ws, req) {
124520
124508
  const originalRequest = pendingRequests.get(msg.id);
124521
124509
  retriedIds.add(msg.id);
124522
124510
  pendingRequests.delete(msg.id);
124523
- log89.debug(
124511
+ log88.debug(
124524
124512
  "LSP retrying request %d after 'No Project' error [%s/%s]",
124525
124513
  msg.id,
124526
124514
  worktreeId4,
@@ -124551,16 +124539,16 @@ async function handleLspConnection(ws, req) {
124551
124539
  for await (const chunk of connection.output)
124552
124540
  parseFrame(Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength));
124553
124541
  } catch (err) {
124554
- log89.warn("LSP output stream failed [%s/%s]: %s", worktreeId4, lang, String(err));
124542
+ log88.warn("LSP output stream failed [%s/%s]: %s", worktreeId4, lang, String(err));
124555
124543
  }
124556
124544
  release();
124557
124545
  if (ws.readyState === ws.OPEN) {
124558
- log89.debug("LSP server exited, closing WebSocket");
124546
+ log88.debug("LSP server exited, closing WebSocket");
124559
124547
  ws.close(1e3, "Language server exited");
124560
124548
  }
124561
124549
  })();
124562
124550
  function forwardToStdin(json3) {
124563
- log89.debug(
124551
+ log88.debug(
124564
124552
  "LSP stdin [%s/%s]: %s",
124565
124553
  worktreeId4,
124566
124554
  lang,
@@ -124592,7 +124580,7 @@ async function handleLspConnection(ws, req) {
124592
124580
  ws.on("close", () => {
124593
124581
  release();
124594
124582
  connection.close();
124595
- log89.debug("LSP client disconnected: %s/%s (server kept alive)", worktreeId4, lang);
124583
+ log88.debug("LSP client disconnected: %s/%s (server kept alive)", worktreeId4, lang);
124596
124584
  });
124597
124585
  }
124598
124586
 
@@ -124601,8 +124589,8 @@ init_webhook();
124601
124589
 
124602
124590
  // src/server/services/_utils/hosted-file.ts
124603
124591
  init_registry();
124604
- import { basename as basename6, join as join58 } from "node:path";
124605
- async function openHostedFile(kind, worktreeId4, rawName) {
124592
+ import { basename as basename6, dirname as dirname17, join as join57 } from "node:path";
124593
+ async function openHostedFile(kind, worktreeId4, rawName, chatId) {
124606
124594
  const host = hostRegistry.hostFor(worktreeId4);
124607
124595
  if (host.id === hostRegistry.local.id) return null;
124608
124596
  let name5;
@@ -124615,7 +124603,9 @@ async function openHostedFile(kind, worktreeId4, rawName) {
124615
124603
  try {
124616
124604
  const dirs = (await host.info()).dirs;
124617
124605
  if (!dirs) return null;
124618
- const path2 = join58(dirs[kind], worktreeId4, name5);
124606
+ const path2 = chatId ? join57(dirs[kind], worktreeId4, chatId, name5) : join57(dirs[kind], worktreeId4, name5);
124607
+ const dir = await host.fs.realpath(dirname17(path2));
124608
+ if (!(await host.fs.realpath(path2)).startsWith(`${dir}/`)) return null;
124619
124609
  const stat7 = await host.fs.stat(path2, { followSymlinks: true });
124620
124610
  if (stat7.kind !== "file") return null;
124621
124611
  return { size: stat7.size, stream: host.fs.readStream(path2) };
@@ -132736,6 +132726,7 @@ async function listenWithFallback(server, startPort, attempts = 20) {
132736
132726
  }
132737
132727
 
132738
132728
  // start-server.ts
132729
+ init_shared_dir();
132739
132730
  init_agent_session_registry_service();
132740
132731
  init_branch_status_poller();
132741
132732
  init_browser_service();
@@ -132754,15 +132745,15 @@ init_src();
132754
132745
  init_registry();
132755
132746
  async function installSkills2(opts = {}) {
132756
132747
  const result = await hostRegistry.local.agentEnv.installSkills({ home: opts.home });
132757
- const log91 = opts.log;
132758
- if (log91) {
132759
- for (const warning of result.warnings) log91.warn(warning);
132760
- for (const path2 of result.written) log91.info("Installed skill at %s", path2);
132748
+ const log90 = opts.log;
132749
+ if (log90) {
132750
+ for (const warning of result.warnings) log90.warn(warning);
132751
+ for (const path2 of result.written) log90.info("Installed skill at %s", path2);
132761
132752
  for (const path2 of result.updated) {
132762
- log91.info("Updated skill at %s (content differed \u2014 shipped version reinstalled)", path2);
132753
+ log90.info("Updated skill at %s (content differed \u2014 shipped version reinstalled)", path2);
132763
132754
  }
132764
132755
  for (const conflict of result.conflicts) {
132765
- log91.warn("Skill symlink conflict \u2014 %s (left as-is; remove it manually to re-link)", conflict);
132756
+ log90.warn("Skill symlink conflict \u2014 %s (left as-is; remove it manually to re-link)", conflict);
132766
132757
  }
132767
132758
  }
132768
132759
  return result;
@@ -132775,7 +132766,7 @@ init_state();
132775
132766
  init_sync_service();
132776
132767
  init_worktree_group_service();
132777
132768
  init_worktree_service();
132778
- var log90 = createLogger("setup");
132769
+ var log89 = createLogger("setup");
132779
132770
  async function runFirstTimeSetup() {
132780
132771
  forgetLocalWorktrees();
132781
132772
  convertLegacyLabels();
@@ -132788,7 +132779,7 @@ async function runFirstTimeSetup() {
132788
132779
  ]);
132789
132780
  for (const r of results) {
132790
132781
  if (r.status === "rejected") {
132791
- log90.warn(
132782
+ log89.warn(
132792
132783
  "Setup step failed: %s",
132793
132784
  r.reason instanceof Error ? r.reason.message : String(r.reason)
132794
132785
  );
@@ -132802,7 +132793,7 @@ async function refreshAgentModelsInBackground() {
132802
132793
  const ok2 = results.filter((r) => !r.error).length;
132803
132794
  const failed = results.length - ok2;
132804
132795
  if (results.length > 0) {
132805
- log90.info(
132796
+ log89.info(
132806
132797
  "Background model refresh: %d/%d agents updated (%d failed)",
132807
132798
  ok2,
132808
132799
  results.length,
@@ -132810,7 +132801,7 @@ async function refreshAgentModelsInBackground() {
132810
132801
  );
132811
132802
  }
132812
132803
  } catch (err) {
132813
- log90.warn(
132804
+ log89.warn(
132814
132805
  "Background model refresh failed: %s",
132815
132806
  err instanceof Error ? err.message : String(err)
132816
132807
  );
@@ -132825,7 +132816,7 @@ async function ensureRepoRemotes() {
132825
132816
  try {
132826
132817
  await repoService.backfillRemotes();
132827
132818
  } catch (err) {
132828
- log90.warn(
132819
+ log89.warn(
132829
132820
  "Failed to record repo remotes at boot: %s",
132830
132821
  err instanceof Error ? err.message : String(err)
132831
132822
  );
@@ -132835,7 +132826,7 @@ function migrateRepoCronjobs() {
132835
132826
  try {
132836
132827
  cronjobService.migrateRepoJobs();
132837
132828
  } catch (err) {
132838
- log90.warn(
132829
+ log89.warn(
132839
132830
  "Failed to move repo-scoped cronjobs to worktrees at boot: %s",
132840
132831
  err instanceof Error ? err.message : String(err)
132841
132832
  );
@@ -132845,7 +132836,7 @@ function convertLegacyLabels() {
132845
132836
  try {
132846
132837
  worktreeGroupService.convertLegacyLabels();
132847
132838
  } catch (err) {
132848
- log90.warn(
132839
+ log89.warn(
132849
132840
  "Failed to convert repo labels to groups at boot: %s",
132850
132841
  err instanceof Error ? err.message : String(err)
132851
132842
  );
@@ -132855,7 +132846,7 @@ function forgetLocalWorktrees() {
132855
132846
  try {
132856
132847
  worktreeService.forgetLocalWorktrees();
132857
132848
  } catch (err) {
132858
- log90.warn(
132849
+ log89.warn(
132859
132850
  "Failed to forget local worktrees at boot: %s",
132860
132851
  err instanceof Error ? err.message : String(err)
132861
132852
  );
@@ -132865,7 +132856,7 @@ async function ensureRepoStateInSync() {
132865
132856
  try {
132866
132857
  await syncService.syncWorktrees();
132867
132858
  } catch (err) {
132868
- log90.warn(
132859
+ log89.warn(
132869
132860
  "Failed to sync repo state at boot: %s",
132870
132861
  err instanceof Error ? err.message : String(err)
132871
132862
  );
@@ -132876,22 +132867,22 @@ async function ensureCliInstalled() {
132876
132867
  try {
132877
132868
  cliStatus = await checkCli();
132878
132869
  } catch (err) {
132879
- log90.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
132870
+ log89.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
132880
132871
  return;
132881
132872
  }
132882
132873
  if (cliStatus === "Installed") {
132883
132874
  return;
132884
132875
  }
132885
132876
  if (cliStatus !== "NotInstalled") {
132886
- log90.warn("CLI not auto-installed (status: %s)", cliStatus);
132877
+ log89.warn("CLI not auto-installed (status: %s)", cliStatus);
132887
132878
  return;
132888
132879
  }
132889
- log90.info("Installing band CLI...");
132880
+ log89.info("Installing band CLI...");
132890
132881
  try {
132891
132882
  await installCli();
132892
- log90.info("CLI installed to %s", SYMLINK_PATH);
132883
+ log89.info("CLI installed to %s", SYMLINK_PATH);
132893
132884
  } catch (err) {
132894
- log90.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
132885
+ log89.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
132895
132886
  }
132896
132887
  }
132897
132888
  async function ensureDefaultCodingAgents() {
@@ -132900,17 +132891,17 @@ async function ensureDefaultCodingAgents() {
132900
132891
  if (Array.isArray(existing) && existing.length > 0) {
132901
132892
  return;
132902
132893
  }
132903
- log90.info("Detecting installed coding agents...");
132894
+ log89.info("Detecting installed coding agents...");
132904
132895
  const detected = [];
132905
132896
  for (const check3 of AGENT_CHECKS) {
132906
132897
  const path2 = await systemService.whichBinary(check3.binary);
132907
132898
  if (path2) {
132908
- log90.info("Detected coding agent: %s (%s)", check3.id, path2);
132899
+ log89.info("Detected coding agent: %s (%s)", check3.id, path2);
132909
132900
  detected.push({ id: check3.id, type: check3.type, label: check3.label });
132910
132901
  }
132911
132902
  }
132912
132903
  if (detected.length === 0) {
132913
- log90.info("No coding agent CLIs detected on PATH");
132904
+ log89.info("No coding agent CLIs detected on PATH");
132914
132905
  return;
132915
132906
  }
132916
132907
  const current3 = loadSettings();
@@ -132919,7 +132910,7 @@ async function ensureDefaultCodingAgents() {
132919
132910
  current3.defaultCodingAgent = detected[0].id;
132920
132911
  }
132921
132912
  saveSettings(current3);
132922
- log90.info("Enabled %d coding agent(s); default = %s", detected.length, current3.defaultCodingAgent);
132913
+ log89.info("Enabled %d coding agent(s); default = %s", detected.length, current3.defaultCodingAgent);
132923
132914
  }
132924
132915
  function ensureNotificationDefaults() {
132925
132916
  const settings3 = loadSettings();
@@ -132931,7 +132922,7 @@ function ensureNotificationDefaults() {
132931
132922
  ...settings3,
132932
132923
  notifications: { ...notifications, soundOnNeedsAttention: true }
132933
132924
  });
132934
- log90.info("Set default notifications.soundOnNeedsAttention = true");
132925
+ log89.info("Set default notifications.soundOnNeedsAttention = true");
132935
132926
  }
132936
132927
  function migrateAgentDefaultMode() {
132937
132928
  const settings3 = loadSettings();
@@ -132939,15 +132930,15 @@ function migrateAgentDefaultMode() {
132939
132930
  const mode = agentModeFromVia(settings3.cli?.defaultVia);
132940
132931
  if (!mode) return;
132941
132932
  saveSettings({ ...settings3, agents: { ...settings3.agents, defaultMode: mode } });
132942
- log90.info("Migrated cli.defaultVia to agents.defaultMode = %s", mode);
132933
+ log89.info("Migrated cli.defaultVia to agents.defaultMode = %s", mode);
132943
132934
  }
132944
132935
  async function ensureSkillsInstalled() {
132945
132936
  try {
132946
- const result = await installSkills2({ log: log90 });
132937
+ const result = await installSkills2({ log: log89 });
132947
132938
  const wrote = result.written.length + result.updated.length;
132948
132939
  const linkChange = result.linked.length;
132949
132940
  if (wrote > 0 || linkChange > 0 || result.conflicts.length > 0) {
132950
- log90.info(
132941
+ log89.info(
132951
132942
  "Synced CLI skills (shared: %d written, %d updated, %d unchanged; symlinks: %d created, %d already-linked, %d conflicts, %d skipped)",
132952
132943
  result.written.length,
132953
132944
  result.updated.length,
@@ -132959,7 +132950,7 @@ async function ensureSkillsInstalled() {
132959
132950
  );
132960
132951
  }
132961
132952
  } catch (err) {
132962
- log90.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
132953
+ log89.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
132963
132954
  }
132964
132955
  }
132965
132956
  var SetupService = class {
@@ -132980,7 +132971,7 @@ init_worktree_service();
132980
132971
  function logCrash(message) {
132981
132972
  try {
132982
132973
  mkdirSync11(bandHome(), { recursive: true });
132983
- appendFileSync2(join59(bandHome(), "server.log"), message, "utf-8");
132974
+ appendFileSync2(join58(bandHome(), "server.log"), message, "utf-8");
132984
132975
  } catch {
132985
132976
  }
132986
132977
  }
@@ -133020,9 +133011,9 @@ function resolveUiDir() {
133020
133011
  if (explicit) return resolve14(explicit);
133021
133012
  const candidates = [
133022
133013
  resolve14(SERVER_ROOT, "..", "..", "web", "dist", "client"),
133023
- join59(SERVER_ROOT, "client")
133014
+ join58(SERVER_ROOT, "client")
133024
133015
  ];
133025
- return candidates.find((dir) => existsSync18(join59(dir, "_shell.html"))) ?? candidates[1];
133016
+ return candidates.find((dir) => existsSync18(join58(dir, "_shell.html"))) ?? candidates[1];
133026
133017
  }
133027
133018
  var clientDir = resolveUiDir();
133028
133019
  var uiRoot = process.env.BAND_UI_ROOT ? resolve14(process.env.BAND_UI_ROOT) : resolve14(SERVER_ROOT, "..", "web");
@@ -133073,7 +133064,7 @@ function getOpenApiSpec() {
133073
133064
  if (isDev) {
133074
133065
  const { generateOpenAPIDocument } = await import("@trpc/openapi");
133075
133066
  const doc = await generateOpenAPIDocument(
133076
- join59(SERVER_ROOT, "src", "server", "api", "router.ts"),
133067
+ join58(SERVER_ROOT, "src", "server", "api", "router.ts"),
133077
133068
  {
133078
133069
  title: "Band API",
133079
133070
  version: "1.0.0"
@@ -133082,7 +133073,7 @@ function getOpenApiSpec() {
133082
133073
  doc.servers = [{ url: "/trpc" }];
133083
133074
  return JSON.stringify(doc, null, 2);
133084
133075
  }
133085
- const openApiDoc = JSON.parse(readFileSync12(join59(SERVER_ROOT, "openapi.json"), "utf-8"));
133076
+ const openApiDoc = JSON.parse(readFileSync12(join58(SERVER_ROOT, "openapi.json"), "utf-8"));
133086
133077
  openApiDoc.servers = [{ url: "/trpc" }];
133087
133078
  return JSON.stringify(openApiDoc, null, 2);
133088
133079
  })().catch((err) => {
@@ -133098,6 +133089,13 @@ function getCachedScalarHtml() {
133098
133089
  _scalarHtml = getScalarHtml("/api/openapi.json");
133099
133090
  return _scalarHtml;
133100
133091
  }
133092
+ function hostedFileHeaders(contentType) {
133093
+ const headers = { "X-Content-Type-Options": "nosniff" };
133094
+ if (/^(text\/html|image\/svg\+xml)\b/.test(contentType)) {
133095
+ headers["Content-Security-Policy"] = "sandbox allow-scripts";
133096
+ }
133097
+ return headers;
133098
+ }
133101
133099
  function serveStaticFile(res, root, subdir, rawFilename) {
133102
133100
  const filename = basename7(decodeURIComponent(rawFilename));
133103
133101
  if (!filename || filename.includes("..")) {
@@ -133105,14 +133103,21 @@ function serveStaticFile(res, root, subdir, rawFilename) {
133105
133103
  res.end("Bad request");
133106
133104
  return;
133107
133105
  }
133108
- const filePath = join59(root, subdir, filename);
133106
+ const filePath = join58(root, subdir, filename);
133109
133107
  try {
133108
+ const dir = realpathSync7(join58(root, subdir));
133109
+ if (!realpathSync7(filePath).startsWith(dir + sep10)) {
133110
+ res.writeHead(404);
133111
+ res.end("Not found");
133112
+ return;
133113
+ }
133110
133114
  const fileStat = statSync16(filePath);
133111
133115
  const contentType = mimeTypeFromFilename(filename);
133112
133116
  res.writeHead(200, {
133113
133117
  "Content-Type": contentType,
133114
133118
  "Content-Length": fileStat.size.toString(),
133115
- "Cache-Control": "private, max-age=86400"
133119
+ "Cache-Control": "private, max-age=86400",
133120
+ ...hostedFileHeaders(contentType)
133116
133121
  });
133117
133122
  createReadStream6(filePath).pipe(res);
133118
133123
  } catch {
@@ -133120,18 +133125,20 @@ function serveStaticFile(res, root, subdir, rawFilename) {
133120
133125
  res.end("Not found");
133121
133126
  }
133122
133127
  }
133123
- async function serveHostedFile(res, kind, worktreeId4, rawName) {
133128
+ async function serveHostedFile(res, kind, worktreeId4, rawName, chatId) {
133124
133129
  if (hostRegistry.hostFor(worktreeId4).id === hostRegistry.local.id) return false;
133125
- const file3 = await openHostedFile(kind, worktreeId4, rawName);
133130
+ const file3 = await openHostedFile(kind, worktreeId4, rawName, chatId);
133126
133131
  if (!file3) {
133127
133132
  res.writeHead(404);
133128
133133
  res.end("Not found");
133129
133134
  return true;
133130
133135
  }
133136
+ const contentType = mimeTypeFromFilename(basename7(decodeURIComponent(rawName)));
133131
133137
  res.writeHead(200, {
133132
- "Content-Type": mimeTypeFromFilename(basename7(decodeURIComponent(rawName))),
133138
+ "Content-Type": contentType,
133133
133139
  "Content-Length": file3.size.toString(),
133134
- "Cache-Control": "private, max-age=86400"
133140
+ "Cache-Control": "private, max-age=86400",
133141
+ ...hostedFileHeaders(contentType)
133135
133142
  });
133136
133143
  pipeline2(
133137
133144
  Readable2.from(file3.stream, { objectMode: false, highWaterMark: 64 * 1024 }),
@@ -133149,7 +133156,7 @@ async function serveWorktreeFile(res, worktreeId4, rawPath, extraHeaders = {}, v
133149
133156
  return;
133150
133157
  }
133151
133158
  const root = worktree.worktree.path;
133152
- const target = resolve14(join59(root, rawPath));
133159
+ const target = resolve14(join58(root, rawPath));
133153
133160
  if (!target.startsWith(root + sep10) && target !== root) {
133154
133161
  res.writeHead(400);
133155
133162
  res.end("Bad request");
@@ -133460,7 +133467,7 @@ async function main() {
133460
133467
  res.end(JSON.stringify({ status: "ok", app: "band-web-server" }));
133461
133468
  return;
133462
133469
  }
133463
- if (handleWebAppManifest(req, res, isDev ? join59(uiRoot, "public") : clientDir)) return;
133470
+ if (handleWebAppManifest(req, res, isDev ? join58(uiRoot, "public") : clientDir)) return;
133464
133471
  if (req.url?.split("?")[0] === WORKER_EXCHANGE_PATH) {
133465
133472
  await workerLinkService.handleExchange(req, res);
133466
133473
  return;
@@ -133559,21 +133566,17 @@ async function main() {
133559
133566
  return;
133560
133567
  }
133561
133568
  if (req.url?.startsWith("/api/shared/")) {
133562
- const rest = req.url.slice("/api/shared/".length).split("?")[0];
133563
- const slashIdx = rest.indexOf("/");
133564
- if (slashIdx === -1) {
133569
+ const parsed = parseSharedPath(req.url.slice("/api/shared/".length));
133570
+ if (!parsed) {
133565
133571
  res.writeHead(400);
133566
133572
  res.end("Bad request");
133567
133573
  return;
133568
133574
  }
133569
- const partition = basename7(decodeURIComponent(rest.slice(0, slashIdx)));
133570
- if (!partition || partition === ".." || partition === ".") {
133571
- res.writeHead(400);
133572
- res.end("Bad request");
133575
+ const encodedName = encodeURIComponent(parsed.name);
133576
+ if (await serveHostedFile(res, "shared", parsed.worktreeId, encodedName, parsed.chatId))
133573
133577
  return;
133574
- }
133575
- if (await serveHostedFile(res, "shared", partition, rest.slice(slashIdx + 1))) return;
133576
- serveStaticFile(res, bandHome(), join59("shared", partition), rest.slice(slashIdx + 1));
133578
+ const subdir = parsed.chatId ? join58("shared", parsed.worktreeId, parsed.chatId) : join58("shared", parsed.worktreeId);
133579
+ serveStaticFile(res, bandHome(), subdir, encodedName);
133577
133580
  return;
133578
133581
  }
133579
133582
  if (req.url?.startsWith("/api/worktree-file/")) {
@@ -133793,7 +133796,7 @@ async function main() {
133793
133796
  if (pathname.startsWith("/_shell")) res.setHeader("Cache-Control", "no-cache");
133794
133797
  }
133795
133798
  });
133796
- const shellPath2 = join59(clientDir, "_shell.html");
133799
+ const shellPath2 = join58(clientDir, "_shell.html");
133797
133800
  if (!existsSync18(shellPath2)) {
133798
133801
  throw new Error(
133799
133802
  `UI build not found at ${clientDir} (no _shell.html). Run \`pnpm build\` or pass --ui-dir <path>.`