@band-app/server 0.37.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/client/assets/{TerminalPanel-B6hpsMbz.js → TerminalPanel-BqGS7Si-.js} +1 -1
  2. package/dist/client/assets/_basePickBy-Df4zoLmW.js +1 -0
  3. package/dist/client/assets/_baseUniq-pZ22zVTR.js +1 -0
  4. package/dist/client/assets/{arc-CUv7R2hs.js → arc-D4-fzYcs.js} +1 -1
  5. package/dist/client/assets/{architectureDiagram-VXUJARFQ-p6VpjWC_.js → architectureDiagram-VXUJARFQ-hRvLVIOi.js} +1 -1
  6. package/dist/client/assets/{blockDiagram-VD42YOAC-BqO2dZTh.js → blockDiagram-VD42YOAC-DlrxWdeD.js} +5 -5
  7. package/dist/client/assets/{c4Diagram-YG6GDRKO-Dj3Q1dN_.js → c4Diagram-YG6GDRKO-QozBjQL2.js} +1 -1
  8. package/dist/client/assets/channel-Cu7vVxQn.js +1 -0
  9. package/dist/client/assets/{chunk-4BX2VUAB-ZCRzpI76.js → chunk-4BX2VUAB-CY2qSpSb.js} +1 -1
  10. package/dist/client/assets/{chunk-55IACEB6-N8w7W4nW.js → chunk-55IACEB6-CjUB8kSn.js} +1 -1
  11. package/dist/client/assets/{chunk-B4BG7PRW-Bd2C6K3g.js → chunk-B4BG7PRW-S28craty.js} +4 -4
  12. package/dist/client/assets/{chunk-DI55MBZ5-CSmsIkhT.js → chunk-DI55MBZ5-Ch7fqNOv.js} +3 -3
  13. package/dist/client/assets/{chunk-FMBD7UC4-CSFx-rdE.js → chunk-FMBD7UC4-C5tYQ2HW.js} +1 -1
  14. package/dist/client/assets/{chunk-QN33PNHL-OZhPV9ZW.js → chunk-QN33PNHL-BvKrzk9H.js} +1 -1
  15. package/dist/client/assets/{chunk-QZHKN3VN-CmQTIqBs.js → chunk-QZHKN3VN-CJNlpZ9I.js} +1 -1
  16. package/dist/client/assets/{chunk-TZMSLE5B-CZXFZkbf.js → chunk-TZMSLE5B-t1JjfsIz.js} +1 -1
  17. package/dist/client/assets/classDiagram-2ON5EDUG-DTE6cfNE.js +1 -0
  18. package/dist/client/assets/classDiagram-v2-WZHVMYZB-DTE6cfNE.js +1 -0
  19. package/dist/client/assets/clone-mH0modHk.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-S5V4N54A-D2ZJ7fd6.js → cose-bilkent-S5V4N54A-Dm9u8tTF.js} +1 -1
  21. package/dist/client/assets/{dagre-6UL2VRFP-DWWSarQ5.js → dagre-6UL2VRFP-US7QmcF4.js} +2 -2
  22. package/dist/client/assets/{diagram-PSM6KHXK-Brpmw2Hy.js → diagram-PSM6KHXK-CVeCV7mq.js} +1 -1
  23. package/dist/client/assets/{diagram-QEK2KX5R-ChxL1lOj.js → diagram-QEK2KX5R-BhoeOCj6.js} +2 -2
  24. package/dist/client/assets/diagram-S2PKOQOG-BtpZHT_5.js +24 -0
  25. package/dist/client/assets/{erDiagram-Q2GNP2WA-TKtLKYBO.js → erDiagram-Q2GNP2WA-QD8wIbtv.js} +3 -3
  26. package/dist/client/assets/{flowDiagram-NV44I4VS-CNkvODlq.js → flowDiagram-NV44I4VS-DnO2HK4L.js} +3 -3
  27. package/dist/client/assets/{ganttDiagram-JELNMOA3-GpiTT-6g.js → ganttDiagram-JELNMOA3-DenfnmcJ.js} +4 -4
  28. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-CWE6IXKZ.js +65 -0
  29. package/dist/client/assets/{graph-BJfBQ-lk.js → graph-Du-tWUki.js} +1 -1
  30. package/dist/client/assets/{highlighted-body-B3W2YXNL-Dcw7_8Mg.js → highlighted-body-B3W2YXNL-DkKe4_lW.js} +1 -1
  31. package/dist/client/assets/{index-Bf0KQTWS.js → index-4qtUUsyR.js} +1 -1
  32. package/dist/client/assets/{index-B8-bfanc.js → index-8_VqKw79.js} +1 -1
  33. package/dist/client/assets/{index-D6AQfoh3.js → index-B5m5EpLO.js} +1 -1
  34. package/dist/client/assets/{index-Bw0gx-LL.js → index-C50rCeQ5.js} +1 -1
  35. package/dist/client/assets/{index-B55cfwG2.js → index-CkKNvKwc.js} +1 -1
  36. package/dist/client/assets/{index-BqB0fXhh.js → index-CvOpnBBP.js} +1 -1
  37. package/dist/client/assets/{index-DNCwYJJi.js → index-D--YjNCY.js} +1 -1
  38. package/dist/client/assets/{index-D4kWf9j1.js → index-D8Aai7_C.js} +1 -1
  39. package/dist/client/assets/{index-D7ptzMHA.js → index-DcZZQTJ5.js} +1 -1
  40. package/dist/client/assets/{index-BBjfnWP1.js → index-DmWhyvdt.js} +1 -1
  41. package/dist/client/assets/{index-BVmOFLZL.js → index-Do260hvq.js} +1 -1
  42. package/dist/client/assets/{index-GWun5iKj.js → index-DsJgsgfy.js} +1 -1
  43. package/dist/client/assets/{index-C04T_A2n.js → index-eISr6luQ.js} +1 -1
  44. package/dist/client/assets/{infoDiagram-HS3SLOUP-yepsEzeD.js → infoDiagram-HS3SLOUP-CDlEX-yd.js} +1 -1
  45. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-Ah-IVMRC.js → journeyDiagram-XKPGCS4Q-CU-wiyuW.js} +3 -3
  46. package/dist/client/assets/{kanban-definition-3W4ZIXB7-4lmmn3Kf.js → kanban-definition-3W4ZIXB7-B4FL-uOU.js} +8 -8
  47. package/dist/client/assets/{layout-WnM58jJN.js → layout-DBljznmo.js} +1 -1
  48. package/dist/client/assets/main-DNMM1VMB.css +1 -0
  49. package/dist/client/assets/{main-D7maoxCk.js → main-ckjLRaX4.js} +275 -275
  50. package/dist/client/assets/{mindmap-definition-VGOIOE7T-CW03vZML.js → mindmap-definition-VGOIOE7T-C6h8wUik.js} +1 -1
  51. package/dist/client/assets/{pieDiagram-ADFJNKIX-b38HzvV9.js → pieDiagram-ADFJNKIX-fb7OxArD.js} +2 -2
  52. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-D7COvUcB.js → quadrantDiagram-AYHSOK5B-WpaJk0Mx.js} +1 -1
  53. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-Dbo91lMQ.js → requirementDiagram-UZGBJVZJ-D0MTsYyH.js} +1 -1
  54. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-DPpuI6f6.js → sankeyDiagram-TZEHDZUN-D4Wnx9yr.js} +4 -4
  55. package/dist/client/assets/{sequenceDiagram-WL72ISMW-osyniVrm.js → sequenceDiagram-WL72ISMW-Cznoju1W.js} +1 -1
  56. package/dist/client/assets/{stateDiagram-FKZM4ZOC-CEtXxDG2.js → stateDiagram-FKZM4ZOC-sEaTrNvF.js} +1 -1
  57. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-CoxzauPD.js +1 -0
  58. package/dist/client/assets/{timeline-definition-IT6M3QCI-Bbim-hJj.js → timeline-definition-IT6M3QCI-DYiFR9am.js} +3 -3
  59. package/dist/client/assets/{treemap-GDKQZRPO-Bo5jz1c4.js → treemap-GDKQZRPO-5A1XFZnN.js} +1 -1
  60. package/dist/client/assets/{workspace._workspaceId-Dx3IQ0uo.js → workspace._workspaceId-B24EYb-h.js} +1 -1
  61. package/dist/client/assets/workspace._workspaceId-C1kbIL__.js +1 -0
  62. package/dist/client/assets/{xychartDiagram-PRI3JC2R-CwV1AnKv.js → xychartDiagram-PRI3JC2R-Bf73MIHj.js} +1 -1
  63. package/dist/openapi.json +146 -36
  64. package/dist/server/assets/{TerminalPanel-oz5y-mkP.js → TerminalPanel-LnJKpZua.js} +1 -1
  65. package/dist/server/assets/{_basePickBy-DEzTaMUa.js → _basePickBy-D1Sq5tmW.js} +2 -2
  66. package/dist/server/assets/{_baseUniq-CnsXScTA.js → _baseUniq-CXf-AOaj.js} +1 -1
  67. package/dist/server/assets/_tanstack-start-manifest_v-C6liq9wJ.js +4 -0
  68. package/dist/server/assets/{arc-DFOFayWx.js → arc-CPt_NgW_.js} +1 -1
  69. package/dist/server/assets/{architecture-7HQA4BMR-n9VmbCuR.js → architecture-7HQA4BMR-k85NMTZg.js} +6 -6
  70. package/dist/server/assets/{architectureDiagram-VXUJARFQ-IeNkR88v.js → architectureDiagram-VXUJARFQ-roiNUC45.js} +6 -6
  71. package/dist/server/assets/{blockDiagram-VD42YOAC-CWXr6KW7.js → blockDiagram-VD42YOAC-BxP67mFW.js} +6 -6
  72. package/dist/server/assets/{c4Diagram-YG6GDRKO-DIRimETA.js → c4Diagram-YG6GDRKO-C6w3T8mD.js} +2 -2
  73. package/dist/server/assets/{channel-Cdqq5j16.js → channel-BZQ1WHCU.js} +1 -1
  74. package/dist/server/assets/{chunk-4BX2VUAB-Cozm9hqk.js → chunk-4BX2VUAB-CTG3wXJI.js} +1 -1
  75. package/dist/server/assets/{chunk-55IACEB6-DRjrJM1L.js → chunk-55IACEB6-CQ0u7epy.js} +1 -1
  76. package/dist/server/assets/{chunk-B4BG7PRW-BwiA7gAZ.js → chunk-B4BG7PRW-BFwRmZtp.js} +4 -4
  77. package/dist/server/assets/{chunk-DI55MBZ5-DYx-lIkt.js → chunk-DI55MBZ5-CIVuy-eK.js} +3 -3
  78. package/dist/server/assets/{chunk-FMBD7UC4-Bd38Wnw9.js → chunk-FMBD7UC4-DwV7_wWU.js} +1 -1
  79. package/dist/server/assets/{chunk-QN33PNHL-ONbSMsSY.js → chunk-QN33PNHL-CMhl56TR.js} +1 -1
  80. package/dist/server/assets/{chunk-QZHKN3VN-fU_vVgPJ.js → chunk-QZHKN3VN-CVMD8gie.js} +1 -1
  81. package/dist/server/assets/{chunk-TZMSLE5B-BBpSfNKJ.js → chunk-TZMSLE5B-h-H4xmaW.js} +1 -1
  82. package/dist/server/assets/{classDiagram-v2-WZHVMYZB-BLteCxZe.js → classDiagram-2ON5EDUG-Cv3ZsERj.js} +5 -5
  83. package/dist/server/assets/{classDiagram-2ON5EDUG-BLteCxZe.js → classDiagram-v2-WZHVMYZB-Cv3ZsERj.js} +5 -5
  84. package/dist/server/assets/{clone-DHWXuNGD.js → clone-z99e_n3P.js} +1 -1
  85. package/dist/server/assets/{cose-bilkent-S5V4N54A-Dqv8g3XR.js → cose-bilkent-S5V4N54A-DuTXMNzv.js} +1 -1
  86. package/dist/server/assets/{dagre-6UL2VRFP-DvvoFaVJ.js → dagre-6UL2VRFP-gs6MZCiN.js} +6 -6
  87. package/dist/server/assets/{diagram-PSM6KHXK-CbKKlJvK.js → diagram-PSM6KHXK-BZViCdTp.js} +7 -7
  88. package/dist/server/assets/{diagram-QEK2KX5R-GLrYhnWw.js → diagram-QEK2KX5R-DCByAB7U.js} +6 -6
  89. package/dist/server/assets/{diagram-S2PKOQOG-uaww8JQd.js → diagram-S2PKOQOG-CjlCQK76.js} +6 -6
  90. package/dist/server/assets/{erDiagram-Q2GNP2WA-CBpgZJNk.js → erDiagram-Q2GNP2WA-CxmLvzaS.js} +4 -4
  91. package/dist/server/assets/{flowDiagram-NV44I4VS-DwqeGUt2.js → flowDiagram-NV44I4VS-B8Qebojb.js} +5 -5
  92. package/dist/server/assets/{ganttDiagram-JELNMOA3-CSDzrG3u.js → ganttDiagram-JELNMOA3-IT9RZV2z.js} +93 -93
  93. package/dist/server/assets/{gitGraph-G5XIXVHT-CI6QTqC-.js → gitGraph-G5XIXVHT-h1gm9b66.js} +6 -6
  94. package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-4Hraf1YX.js → gitGraphDiagram-V2S2FVAM-DdPXfV0J.js} +7 -7
  95. package/dist/server/assets/{graph-BKeol0ik.js → graph-Cwrzze_v.js} +2 -2
  96. package/dist/server/assets/{highlighted-body-B3W2YXNL-C_Th2vxh.js → highlighted-body-B3W2YXNL-gpUVL7_H.js} +1 -1
  97. package/dist/server/assets/{index-BmH5PL3t.js → index-5goe_Qxf.js} +1 -1
  98. package/dist/server/assets/{index-CoOBJObR.js → index-BUwTvxqa.js} +1 -1
  99. package/dist/server/assets/{index-BtAQWAP4.js → index-BcliGgbP.js} +1 -1
  100. package/dist/server/assets/{index-BVY32Ndh.js → index-BffAB596.js} +1 -1
  101. package/dist/server/assets/{index-SeV-ZdZi.js → index-BiVfgqb5.js} +1 -1
  102. package/dist/server/assets/{index-WYUrghvu.js → index-ByA4PzKy.js} +1 -1
  103. package/dist/server/assets/{index-DOtn1sP2.js → index-C6qGxPOi.js} +1 -1
  104. package/dist/server/assets/{index-CXm0C-yc.js → index-CB-SPHLN.js} +1 -1
  105. package/dist/server/assets/{index-B-VeeFTd.js → index-CMvKdbDj.js} +1 -1
  106. package/dist/server/assets/{index-dS3n7bt3.js → index-C_-JZgLl.js} +1 -1
  107. package/dist/server/assets/{index-KTMc95HN.js → index-DRthBXgF.js} +1 -1
  108. package/dist/server/assets/{index-CklLNUhb.js → index-DTF2dDu2.js} +1 -1
  109. package/dist/server/assets/{index-BQEmg9fY.js → index-Dn-KmqbG.js} +1 -1
  110. package/dist/server/assets/{info-VBDWY6EO-qXtU7fls.js → info-VBDWY6EO-BCD07kIN.js} +6 -6
  111. package/dist/server/assets/{infoDiagram-HS3SLOUP-Bnhyc8dm.js → infoDiagram-HS3SLOUP-DoCRX3L6.js} +5 -5
  112. package/dist/server/assets/{journeyDiagram-XKPGCS4Q-DCeht2II.js → journeyDiagram-XKPGCS4Q-lQnoUHtC.js} +4 -4
  113. package/dist/server/assets/{kanban-definition-3W4ZIXB7-D2wyptyQ.js → kanban-definition-3W4ZIXB7-C9Nu1gsI.js} +2 -2
  114. package/dist/server/assets/{layout-D8oV2IEs.js → layout-D3n_Tmn-.js} +4 -4
  115. package/dist/server/assets/{mermaid-3ZIDBTTL-BLpPLDqd.js → mermaid-3ZIDBTTL-rQ6WF_37.js} +1 -1
  116. package/dist/server/assets/{mermaid-parser.core-BbOvn3Uv.js → mermaid-parser.core-DNT4pdMq.js} +11 -11
  117. package/dist/server/assets/{mindmap-definition-VGOIOE7T-CKJkiH58.js → mindmap-definition-VGOIOE7T-D0Rt8hFl.js} +3 -3
  118. package/dist/server/assets/{packet-DYOGHKS2-CnxepCEW.js → packet-DYOGHKS2-DgvmWMo0.js} +6 -6
  119. package/dist/server/assets/{pie-VRWISCQL-KXauGON3.js → pie-VRWISCQL-D-2Fk1lp.js} +6 -6
  120. package/dist/server/assets/{pieDiagram-ADFJNKIX-B8juLdbl.js → pieDiagram-ADFJNKIX-Bp7EHNsN.js} +7 -7
  121. package/dist/server/assets/{quadrantDiagram-AYHSOK5B-CLY3QLCC.js → quadrantDiagram-AYHSOK5B-Dwf7kfmm.js} +1 -1
  122. package/dist/server/assets/{radar-ZZBFDIW7-CIRaA_9T.js → radar-ZZBFDIW7-BmPb-FT1.js} +6 -6
  123. package/dist/server/assets/{requirementDiagram-UZGBJVZJ-CgDmK30l.js → requirementDiagram-UZGBJVZJ-BhU97uqr.js} +3 -3
  124. package/dist/server/assets/{router-G1mE-O-Q.js → router-BwecRQjR.js} +139090 -137922
  125. package/dist/server/assets/{sankeyDiagram-TZEHDZUN-B9355ZLW.js → sankeyDiagram-TZEHDZUN-DCVgtpAB.js} +1 -1
  126. package/dist/server/assets/{sequenceDiagram-WL72ISMW-SyLdlVhU.js → sequenceDiagram-WL72ISMW-CwXr5Ska.js} +3 -3
  127. package/dist/server/assets/{stateDiagram-FKZM4ZOC-B8krws9Z.js → stateDiagram-FKZM4ZOC-BfVSbVFi.js} +8 -8
  128. package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-CqkUhCge.js → stateDiagram-v2-4FDKWEC3-CHjeA5KM.js} +4 -4
  129. package/dist/server/assets/{timeline-definition-IT6M3QCI-eG_EzXZg.js → timeline-definition-IT6M3QCI-sd3euZCd.js} +2 -2
  130. package/dist/server/assets/{treemap-GDKQZRPO-DS3w9TMX.js → treemap-GDKQZRPO-DZbOv3VW.js} +6 -6
  131. package/dist/server/assets/workspace._workspaceId-BQIneK3E.js +39 -0
  132. package/dist/server/assets/{workspace._workspaceId-DMYkHS43.js → workspace._workspaceId-ktgJ6SeK.js} +1 -1
  133. package/dist/server/assets/{xychartDiagram-PRI3JC2R-DAi7zkg3.js → xychartDiagram-PRI3JC2R-BsR3utmM.js} +1 -1
  134. package/dist/server/server.js +2 -2
  135. package/dist/start-server.mjs +354 -75
  136. package/dist/terminal-daemon.mjs +1 -0
  137. package/package.json +4 -4
  138. package/dist/client/assets/_basePickBy-DCmd5ciV.js +0 -1
  139. package/dist/client/assets/_baseUniq-D9VK2Z8h.js +0 -1
  140. package/dist/client/assets/channel-30zU4uX-.js +0 -1
  141. package/dist/client/assets/classDiagram-2ON5EDUG-xMXNI9Qc.js +0 -1
  142. package/dist/client/assets/classDiagram-v2-WZHVMYZB-xMXNI9Qc.js +0 -1
  143. package/dist/client/assets/clone-D1RDOFVG.js +0 -1
  144. package/dist/client/assets/diagram-S2PKOQOG-CWk5ucVa.js +0 -24
  145. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-Dka5-Ebv.js +0 -65
  146. package/dist/client/assets/main-C-PIkr2h.css +0 -1
  147. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-DtnGHNEG.js +0 -1
  148. package/dist/client/assets/workspace._workspaceId-BAa7JD1w.js +0 -1
  149. package/dist/server/assets/_tanstack-start-manifest_v-CGO9e_6B.js +0 -4
  150. package/dist/server/assets/workspace._workspaceId-Bd4v7PwG.js +0 -330
@@ -92313,11 +92313,17 @@ function notify(chatId) {
92313
92313
  }
92314
92314
  function cloneMessage(msg) {
92315
92315
  return {
92316
- id: msg.id,
92317
- text: msg.text,
92316
+ ...msg,
92318
92317
  files: msg.files ? msg.files.map((f2) => ({ ...f2 })) : void 0
92319
92318
  };
92320
92319
  }
92320
+ function turnOptions(input) {
92321
+ return {
92322
+ ...input.mode !== void 0 && { mode: input.mode },
92323
+ ...input.model !== void 0 && { model: input.model },
92324
+ ...input.codingAgentId !== void 0 && { codingAgentId: input.codingAgentId }
92325
+ };
92326
+ }
92321
92327
  function subscribeQueue(listener) {
92322
92328
  queueListeners.add(listener);
92323
92329
  return () => {
@@ -92328,7 +92334,8 @@ function pushQueuedMessage(chatId, input) {
92328
92334
  const message = {
92329
92335
  id: randomUUID(),
92330
92336
  text: input.text,
92331
- files: input.files && input.files.length > 0 ? input.files.map((f2) => ({ ...f2 })) : void 0
92337
+ files: input.files && input.files.length > 0 ? input.files.map((f2) => ({ ...f2 })) : void 0,
92338
+ ...turnOptions(input)
92332
92339
  };
92333
92340
  const msgs = store.get(chatId);
92334
92341
  if (msgs) {
@@ -92343,11 +92350,17 @@ function setQueuedMessages(chatId, messages) {
92343
92350
  if (messages.length === 0) {
92344
92351
  store.delete(chatId);
92345
92352
  } else {
92346
- const stored = messages.map((m3) => ({
92347
- id: m3.id ?? randomUUID(),
92348
- text: m3.text,
92349
- files: m3.files && m3.files.length > 0 ? m3.files.map((f2) => ({ ...f2 })) : void 0
92350
- }));
92353
+ const previous = new Map((store.get(chatId) ?? []).map((m3) => [m3.id, m3]));
92354
+ const stored = messages.map((m3) => {
92355
+ const kept = m3.id !== void 0 ? previous.get(m3.id) : void 0;
92356
+ return {
92357
+ id: m3.id ?? randomUUID(),
92358
+ text: m3.text,
92359
+ files: m3.files && m3.files.length > 0 ? m3.files.map((f2) => ({ ...f2 })) : void 0,
92360
+ ...kept && turnOptions(kept),
92361
+ ...turnOptions(m3)
92362
+ };
92363
+ });
92351
92364
  store.set(chatId, stored);
92352
92365
  }
92353
92366
  notify(chatId);
@@ -92355,6 +92368,13 @@ function setQueuedMessages(chatId, messages) {
92355
92368
  function getQueuedMessages(chatId) {
92356
92369
  return (store.get(chatId) ?? []).map(cloneMessage);
92357
92370
  }
92371
+ function hasQueuedMessages(chatId) {
92372
+ return (store.get(chatId)?.length ?? 0) > 0;
92373
+ }
92374
+ function peekQueuedMessage(chatId) {
92375
+ const first = store.get(chatId)?.[0];
92376
+ return first ? cloneMessage(first) : null;
92377
+ }
92358
92378
  function shiftQueuedMessage(chatId) {
92359
92379
  const msgs = store.get(chatId);
92360
92380
  if (!msgs || msgs.length === 0) return null;
@@ -107359,8 +107379,42 @@ var CLIENT_CAPABILITIES = {
107359
107379
  // Claude Code's AskUserQuestion arrives as a form elicitation, and is
107360
107380
  // disabled when the client can't render one.
107361
107381
  elicitation: { form: {} },
107362
- session: { notices: {} }
107363
- };
107382
+ session: { notices: {} },
107383
+ // JetBrains AIR extension: the Claude adapter reports background work
107384
+ // (background Bash, Monitor, workflows) as `async_task_*` updates only to
107385
+ // a client that lists `asyncTasks`. Band uses them to keep the process
107386
+ // alive while that work runs.
107387
+ _meta: { jetbrains: { air: { version: 1, capabilities: ["asyncTasks"] } } }
107388
+ };
107389
+ function asAsyncTaskNotification(message) {
107390
+ if (!message || typeof message !== "object") return null;
107391
+ const m3 = message;
107392
+ if (m3.method !== methods.client.session.update) return null;
107393
+ const params = m3.params;
107394
+ const update = params?.update;
107395
+ if (typeof params?.sessionId !== "string" || typeof update?.sessionUpdate !== "string" || !update.sessionUpdate.startsWith("async_task_") || typeof update.asyncTaskId !== "string") {
107396
+ return null;
107397
+ }
107398
+ return params;
107399
+ }
107400
+ function splitAsyncTasks(readable, onAsyncTask) {
107401
+ return readable.pipeThrough(
107402
+ new TransformStream({
107403
+ transform(message, controller) {
107404
+ const task = asAsyncTaskNotification(message);
107405
+ if (!task) {
107406
+ controller.enqueue(message);
107407
+ return;
107408
+ }
107409
+ try {
107410
+ onAsyncTask(task);
107411
+ } catch (err) {
107412
+ log.warn({ err }, "async task handler threw");
107413
+ }
107414
+ }
107415
+ })
107416
+ );
107417
+ }
107364
107418
  function stderrTail() {
107365
107419
  let buf = "";
107366
107420
  return {
@@ -107426,10 +107480,14 @@ var AcpAgentProcess = class _AcpAgentProcess {
107426
107480
  } catch (err) {
107427
107481
  throw new Error(`Could not start ${label}: ${err.message}`);
107428
107482
  }
107429
- const stream = ndJsonStream2(
107483
+ const wire = ndJsonStream2(
107430
107484
  Writable.toWeb(child.stdin),
107431
107485
  Readable.toWeb(child.stdout)
107432
107486
  );
107487
+ const stream = {
107488
+ writable: wire.writable,
107489
+ readable: splitAsyncTasks(wire.readable, (n) => handlers3.onAsyncTask?.(n))
107490
+ };
107433
107491
  const connection = client({ name: "band" }).onNotification(methods.client.session.update, (ctx) => {
107434
107492
  handlers3.onUpdate(ctx.params);
107435
107493
  }).onRequest(methods.client.session.requestPermission, async (ctx) => ({
@@ -107801,11 +107859,11 @@ function resumeCliInvocation(agentType, sessionId, opts) {
107801
107859
  var CLAUDE_CODE_INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
107802
107860
  function mapClaudeCodeHookStatus(payload) {
107803
107861
  const hookEvent = typeof payload.hook_event_name === "string" ? payload.hook_event_name : "";
107804
- const toolName = typeof payload.tool_name === "string" ? payload.tool_name : "";
107862
+ const toolName2 = typeof payload.tool_name === "string" ? payload.tool_name : "";
107805
107863
  if (hookEvent === "Stop") {
107806
107864
  return "needs_attention";
107807
107865
  }
107808
- if ((hookEvent === "PreToolUse" || hookEvent === "PermissionRequest") && CLAUDE_CODE_INTERACTIVE_TOOLS.has(toolName)) {
107866
+ if ((hookEvent === "PreToolUse" || hookEvent === "PermissionRequest") && CLAUDE_CODE_INTERACTIVE_TOOLS.has(toolName2)) {
107809
107867
  return "needs_attention";
107810
107868
  }
107811
107869
  return "working";
@@ -116936,6 +116994,101 @@ var ChatEventQueries = class {
116936
116994
  }
116937
116995
  };
116938
116996
 
116997
+ // src/server/services/_utils/agent-pending-work.ts
116998
+ var MAX_HOLD_MS = 8 * 60 * 6e4;
116999
+ var MONITOR_DEFAULT_TIMEOUT_MS = 5 * 6e4;
117000
+ function toolName(update) {
117001
+ const meta2 = update._meta;
117002
+ const name3 = meta2?.claudeCode?.toolName ?? update.name;
117003
+ return typeof name3 === "string" ? name3 : void 0;
117004
+ }
117005
+ function finiteNumber(value) {
117006
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
117007
+ }
117008
+ var PendingWork = class {
117009
+ holds = /* @__PURE__ */ new Map();
117010
+ /** Tool calls an async task was announced for. */
117011
+ taskToolCalls = /* @__PURE__ */ new Set();
117012
+ /** Notes what a `session/update` starts or ends. `inTurn` is whether a
117013
+ * Band-started turn is running. */
117014
+ observeUpdate(update, inTurn, now = Date.now()) {
117015
+ if (update.sessionUpdate !== "tool_call" && update.sessionUpdate !== "tool_call_update") return;
117016
+ const key2 = `tool:${update.toolCallId}`;
117017
+ if (this.taskToolCalls.has(update.toolCallId)) return;
117018
+ if (update.status === "failed") {
117019
+ this.holds.delete(key2);
117020
+ return;
117021
+ }
117022
+ const held = this.holds.get(key2);
117023
+ if (update.status === "completed") {
117024
+ if (held?.untilCompleted) this.holds.delete(key2);
117025
+ return;
117026
+ }
117027
+ if (held) return;
117028
+ const hold = this.toolHold(update, now);
117029
+ if (hold) {
117030
+ this.set(key2, hold, now);
117031
+ return;
117032
+ }
117033
+ if (!inTurn && update.sessionUpdate === "tool_call") {
117034
+ this.set(key2, { reason: "tool call", until: now + MAX_HOLD_MS, untilCompleted: true }, now);
117035
+ }
117036
+ }
117037
+ /** Notes an AIR async task starting or ending. */
117038
+ observeAsyncTask(update, now = Date.now()) {
117039
+ const key2 = `task:${update.asyncTaskId}`;
117040
+ if (update.sessionUpdate === "async_task_spawned") {
117041
+ if (update.toolCallId) {
117042
+ this.taskToolCalls.add(update.toolCallId);
117043
+ this.holds.delete(`tool:${update.toolCallId}`);
117044
+ }
117045
+ this.set(
117046
+ key2,
117047
+ { reason: `${update.taskType ?? "background"} task`, until: now + MAX_HOLD_MS },
117048
+ now
117049
+ );
117050
+ } else if (update.sessionUpdate === "async_task_state_update" && (update.state === "completed" || update.state === "failed" || update.state === "stopped")) {
117051
+ this.holds.delete(key2);
117052
+ if (update.toolCallId) this.holds.delete(`tool:${update.toolCallId}`);
117053
+ }
117054
+ }
117055
+ /** The holds still in force, dropping the ones that lapsed. */
117056
+ outstanding(now = Date.now()) {
117057
+ for (const [key2, hold] of this.holds) {
117058
+ if (hold.until <= now) this.holds.delete(key2);
117059
+ }
117060
+ return [...this.holds.values()];
117061
+ }
117062
+ clear() {
117063
+ this.holds.clear();
117064
+ this.taskToolCalls.clear();
117065
+ }
117066
+ toolHold(update, now) {
117067
+ const input = update.rawInput;
117068
+ if (!input || typeof input !== "object") return null;
117069
+ switch (toolName(update)) {
117070
+ case "ScheduleWakeup": {
117071
+ const delaySeconds = finiteNumber(input.delaySeconds);
117072
+ return delaySeconds === void 0 ? null : { reason: "scheduled wakeup", until: now + delaySeconds * 1e3 };
117073
+ }
117074
+ case "CronCreate":
117075
+ return { reason: "cron job", until: now + MAX_HOLD_MS };
117076
+ case "Monitor": {
117077
+ const timeout = finiteNumber(input.timeout_ms) ?? MONITOR_DEFAULT_TIMEOUT_MS;
117078
+ return { reason: "monitor", until: now + timeout };
117079
+ }
117080
+ case "Bash":
117081
+ case "PowerShell":
117082
+ return input.run_in_background === true ? { reason: "background command", until: now + MAX_HOLD_MS, untilCompleted: true } : null;
117083
+ default:
117084
+ return null;
117085
+ }
117086
+ }
117087
+ set(key2, hold, now) {
117088
+ this.holds.set(key2, { ...hold, until: Math.min(hold.until, now + MAX_HOLD_MS) });
117089
+ }
117090
+ };
117091
+
116939
117092
  // src/server/services/_utils/chat-log-replay.ts
116940
117093
  function textChunk(row) {
116941
117094
  const event = row.event;
@@ -131567,9 +131720,11 @@ var import_react29 = __toESM(require_react(), 1);
131567
131720
 
131568
131721
  // src/dashboard/lib/checks-tab.ts
131569
131722
  var CHECKS_SIDE_TAB = "plugin:github.pull-request";
131570
- function showChecksTab() {
131723
+ function showChecksTab(workspaceId2) {
131571
131724
  window.dispatchEvent(
131572
- new CustomEvent("band:right-sidepanel-set-tab", { detail: { tab: CHECKS_SIDE_TAB } })
131725
+ new CustomEvent("band:right-sidepanel-set-tab", {
131726
+ detail: { tab: CHECKS_SIDE_TAB, workspaceId: workspaceId2 }
131727
+ })
131573
131728
  );
131574
131729
  window.dispatchEvent(new CustomEvent("band:show-right-panel"));
131575
131730
  }
@@ -131895,9 +132050,23 @@ function WorkspaceLabel({
131895
132050
  const nameClass = tone === "switcher" ? `text-foreground ${isActive ? "font-semibold" : "font-medium"}` : isActive ? "font-bold text-foreground" : "font-medium text-foreground/75";
131896
132051
  const projectClass = tone === "switcher" ? "text-foreground/70" : isActive ? "text-foreground/80" : "text-foreground/60";
131897
132052
  const isSidebar = tone === "sidebar";
131898
- return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { className: "flex flex-col min-w-0 leading-tight", children: [
131899
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: cn(isSidebar ? "text-[13px]" : "text-sm", "truncate", nameClass), children: name3 }),
131900
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)("span", { className: cn(isSidebar ? "text-[11px]" : "text-xs", "truncate", projectClass), children: projectName })
132053
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)("div", { "data-testid": "workspace-label", className: "flex flex-col min-w-0 leading-tight", children: [
132054
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
132055
+ "span",
132056
+ {
132057
+ "data-testid": "workspace-label__name",
132058
+ className: cn(isSidebar ? "text-[13px]" : "text-sm", "truncate", nameClass),
132059
+ children: name3
132060
+ }
132061
+ ),
132062
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(
132063
+ "span",
132064
+ {
132065
+ "data-testid": "workspace-label__project",
132066
+ className: cn(isSidebar ? "text-[11px]" : "text-xs", "truncate", projectClass),
132067
+ children: projectName
132068
+ }
132069
+ )
131901
132070
  ] });
131902
132071
  }
131903
132072
 
@@ -131968,7 +132137,7 @@ var WorkspaceCard = (0, import_react29.memo)(function WorkspaceCard2({
131968
132137
  };
131969
132138
  const handleOpenChecks = () => {
131970
132139
  if (isDeleting) return;
131971
- showChecksTab();
132140
+ showChecksTab(workspaceId2);
131972
132141
  if (!isActive) handleClick();
131973
132142
  };
131974
132143
  const className = `@container group flex flex-row items-center justify-between rounded-md pl-3 pr-2 py-1 min-h-9 min-w-0 overflow-hidden select-none touch-manipulation transition-colors ${isDeleting ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-accent/50"} [@media(pointer:coarse)]:min-h-11 [@media(pointer:coarse)]:py-2 ${isActive ? "bg-primary/15 hover:bg-primary/15" : isFocused ? "bg-accent" : ""} ${href ? "no-underline text-inherit" : ""}`;
@@ -141001,11 +141170,11 @@ var WorkspaceStatusSourceQueries = class {
141001
141170
  /** Every source in the workspace. */
141002
141171
  listForWorkspace(workspaceId2) {
141003
141172
  const db = getDb();
141004
- return db.select({
141005
- sourceId: workspaceStatusSources.sourceId,
141006
- status: workspaceStatusSources.status,
141007
- updatedAt: workspaceStatusSources.updatedAt
141008
- }).from(workspaceStatusSources).where(eq(workspaceStatusSources.workspaceId, workspaceId2)).all();
141173
+ return db.select().from(workspaceStatusSources).where(eq(workspaceStatusSources.workspaceId, workspaceId2)).all();
141174
+ }
141175
+ /** Every source in every workspace. */
141176
+ listAll() {
141177
+ return getDb().select().from(workspaceStatusSources).all();
141009
141178
  }
141010
141179
  /** Delete one source; returns whether a row existed. */
141011
141180
  remove(workspaceId2, sourceId) {
@@ -141341,10 +141510,21 @@ function worktreesDir() {
141341
141510
  return settingsService.worktreesDir();
141342
141511
  }
141343
141512
  function loadCurrentStatuses() {
141344
- return workspaceStatusQueries.loadCurrent();
141513
+ const sourcesByWorkspace = /* @__PURE__ */ new Map();
141514
+ for (const source of statusSourceQueries.listAll()) {
141515
+ const list3 = sourcesByWorkspace.get(source.workspaceId);
141516
+ if (list3) list3.push(source);
141517
+ else sourcesByWorkspace.set(source.workspaceId, [source]);
141518
+ }
141519
+ return workspaceStatusQueries.loadCurrent().map((status) => ({
141520
+ ...status,
141521
+ tabStatuses: toTabStatuses(sourcesByWorkspace.get(status.workspaceId) ?? [])
141522
+ }));
141345
141523
  }
141346
141524
  function getWorkspaceStatus(workspaceId2) {
141347
- return workspaceStatusQueries.getByWorkspaceId(workspaceId2);
141525
+ const status = workspaceStatusQueries.getByWorkspaceId(workspaceId2);
141526
+ if (!status) return null;
141527
+ return { ...status, tabStatuses: listTabStatuses(workspaceId2) };
141348
141528
  }
141349
141529
  function upsertWorkspaceStatus(workspaceId2, agent) {
141350
141530
  const existing = workspaceStatusQueries.findRow(workspaceId2);
@@ -141412,7 +141592,8 @@ function upsertWorkspaceStatus(workspaceId2, agent) {
141412
141592
  lastActivity: mergedAgent.agentLastActivity,
141413
141593
  summary: mergedAgent.agentSummary ?? void 0,
141414
141594
  codingAgentId: mergedAgent.codingAgentId ?? void 0
141415
- }
141595
+ },
141596
+ tabStatuses: listTabStatuses(workspaceId2)
141416
141597
  };
141417
141598
  }
141418
141599
  function resolveWorkspaceIdByCwd(cwd) {
@@ -141428,21 +141609,50 @@ function resolveWorkspaceIdByCwd(cwd) {
141428
141609
  }
141429
141610
  var STALE_HOOK_WORKING_MS = 15 * 6e4;
141430
141611
  var STATUS_PRIORITY = { needs_attention: 3, working: 2, waiting: 1 };
141612
+ var CHAT_SOURCE_PREFIX = "chat:";
141431
141613
  function chatStatusSource(chatId) {
141432
- return `chat:${chatId}`;
141614
+ return `${CHAT_SOURCE_PREFIX}${chatId}`;
141433
141615
  }
141434
141616
  var MANUAL_STATUS_SOURCE = "manual";
141617
+ function isStaleSource({ sourceId, status, updatedAt }, staleBefore) {
141618
+ return sourceId.startsWith("hook:") && status === "working" && updatedAt < staleBefore;
141619
+ }
141435
141620
  function deriveWorkspaceStatus(workspaceId2) {
141436
141621
  const staleBefore = Date.now() - STALE_HOOK_WORKING_MS;
141437
141622
  let best = null;
141438
- for (const { sourceId, status, updatedAt } of statusSourceQueries.listForWorkspace(workspaceId2)) {
141439
- if (sourceId.startsWith("hook:") && status === "working" && updatedAt < staleBefore) continue;
141623
+ for (const source of statusSourceQueries.listForWorkspace(workspaceId2)) {
141624
+ if (isStaleSource(source, staleBefore)) continue;
141625
+ const { status } = source;
141440
141626
  if (best === null || (STATUS_PRIORITY[status] ?? 0) > (STATUS_PRIORITY[best] ?? 0)) {
141441
141627
  best = status;
141442
141628
  }
141443
141629
  }
141444
141630
  return best ?? "waiting";
141445
141631
  }
141632
+ function toTabStatuses(sources) {
141633
+ const staleBefore = Date.now() - STALE_HOOK_WORKING_MS;
141634
+ const byTab = /* @__PURE__ */ new Map();
141635
+ for (const source of sources) {
141636
+ const { status } = source;
141637
+ if (status !== "working" && status !== "needs_attention") continue;
141638
+ if (isStaleSource(source, staleBefore)) continue;
141639
+ let tab3;
141640
+ if (source.sourceId.startsWith(CHAT_SOURCE_PREFIX)) {
141641
+ tab3 = { chatId: source.sourceId.slice(CHAT_SOURCE_PREFIX.length), status };
141642
+ } else if (source.terminalId) {
141643
+ tab3 = { terminalId: source.terminalId, status };
141644
+ } else {
141645
+ continue;
141646
+ }
141647
+ const key2 = tab3.chatId ? `chat:${tab3.chatId}` : `terminal:${tab3.terminalId}`;
141648
+ const prev = byTab.get(key2);
141649
+ if (!prev || STATUS_PRIORITY[status] > STATUS_PRIORITY[prev.status]) byTab.set(key2, tab3);
141650
+ }
141651
+ return [...byTab.values()];
141652
+ }
141653
+ function listTabStatuses(workspaceId2) {
141654
+ return toTabStatuses(statusSourceQueries.listForWorkspace(workspaceId2));
141655
+ }
141446
141656
  function setWorkspaceSourceStatus(workspaceId2, sourceId, agent) {
141447
141657
  statusSourceQueries.upsert({
141448
141658
  workspaceId: workspaceId2,
@@ -143655,6 +143865,7 @@ var TerminalPool = class {
143655
143865
  delete env.FORCE_COLOR;
143656
143866
  delete env.CLICOLOR;
143657
143867
  env.COLORFGBG = "15;0";
143868
+ env.CLAUDE_CODE_FORCE_SYNC_OUTPUT = "1";
143658
143869
  delete env.PORT;
143659
143870
  if (options2?.env) {
143660
143871
  Object.assign(env, options2.env);
@@ -145503,6 +145714,25 @@ function submitTask(options2) {
145503
145714
  });
145504
145715
  return toTaskInfo(task);
145505
145716
  }
145717
+ function submitOrQueueTask(options2) {
145718
+ const { workspaceId: workspaceId2, chatId } = options2;
145719
+ if (!workspaceService.resolve(workspaceId2)) {
145720
+ throw new WorkspaceNotFoundError(workspaceId2);
145721
+ }
145722
+ const running = tasks2.get(chatId)?.status === "running";
145723
+ if (!running && !hasQueuedMessages(chatId)) {
145724
+ return { queued: false, task: submitTask(options2) };
145725
+ }
145726
+ const queued = pushQueuedMessage(chatId, {
145727
+ text: options2.prompt,
145728
+ files: options2.attachments,
145729
+ mode: options2.mode,
145730
+ model: options2.model,
145731
+ codingAgentId: options2.codingAgentId
145732
+ });
145733
+ if (!running) drainQueue(workspaceId2, chatId);
145734
+ return { queued: true, queuedMessageId: queued.id };
145735
+ }
145506
145736
  async function runTask(task) {
145507
145737
  const { chatId } = task;
145508
145738
  chatService.updateStatus(chatId, "running");
@@ -145632,7 +145862,7 @@ function finishTask(task, outcome) {
145632
145862
  task.completedAt = Date.now();
145633
145863
  persistTask(task);
145634
145864
  if (tasks2.get(task.chatId) === task) tasks2.delete(task.chatId);
145635
- if (status === "completed" && drainQueue(task)) return;
145865
+ if (status === "completed" && drainQueue(task.workspaceId, task.chatId)) return;
145636
145866
  chatService.updateStatus(task.chatId, status === "completed" ? "idle" : "error");
145637
145867
  const stopped = outcome === "cancelled" || task.cancelRequested === true;
145638
145868
  const updated = setWorkspaceSourceStatus(task.workspaceId, chatStatusSource(task.chatId), {
@@ -145640,20 +145870,24 @@ function finishTask(task, outcome) {
145640
145870
  });
145641
145871
  emit({ kind: "update", status: updated });
145642
145872
  }
145643
- function drainQueue(task) {
145644
- const queued = shiftQueuedMessage(task.chatId);
145873
+ function drainQueue(workspaceId2, chatId) {
145874
+ const queued = peekQueuedMessage(chatId);
145645
145875
  if (!queued) return false;
145646
145876
  try {
145647
145877
  const attachments = (queued.files ?? []).filter((f2) => f2.path).map((f2) => ({ path: f2.path, mediaType: f2.mediaType, url: f2.url, filename: f2.filename }));
145648
145878
  submitTask({
145649
- workspaceId: task.workspaceId,
145650
- chatId: task.chatId,
145879
+ workspaceId: workspaceId2,
145880
+ chatId,
145651
145881
  prompt: queued.text,
145652
- attachments
145882
+ attachments,
145883
+ mode: queued.mode,
145884
+ model: queued.model,
145885
+ codingAgentId: queued.codingAgentId
145653
145886
  });
145887
+ removeQueuedMessage(chatId, queued.id);
145654
145888
  return true;
145655
145889
  } catch (err) {
145656
- log19.warn({ chatId: task.chatId, err }, "failed to auto-start queued task");
145890
+ log19.warn({ chatId, err }, "failed to auto-start queued task");
145657
145891
  return false;
145658
145892
  }
145659
145893
  }
@@ -145700,6 +145934,9 @@ var TaskService = class {
145700
145934
  submitTask(options2) {
145701
145935
  return submitTask(options2);
145702
145936
  }
145937
+ submitOrQueueTask(options2) {
145938
+ return submitOrQueueTask(options2);
145939
+ }
145703
145940
  abortTask(chatId) {
145704
145941
  return abortTask(chatId);
145705
145942
  }
@@ -149584,6 +149821,7 @@ var chatService = new ChatService();
149584
149821
  var log31 = createLogger("agent-sessions");
149585
149822
  var IDLE_TIMEOUT_MS = 15 * 6e4;
149586
149823
  var CANCEL_GRACE_MS = 15e3;
149824
+ var MAX_TIMER_MS = 2 ** 31 - 1;
149587
149825
  var PROBE_SETTLE_MS = 1500;
149588
149826
  var events = new ChatEventQueries();
149589
149827
  var settings = new SettingsQueries();
@@ -149662,6 +149900,7 @@ function runtimeFor(chat, def2) {
149662
149900
  turnSeq: 0,
149663
149901
  live: emptyLive(),
149664
149902
  pending: /* @__PURE__ */ new Map(),
149903
+ work: new PendingWork(),
149665
149904
  idleTimer: null,
149666
149905
  claudeCli: null
149667
149906
  };
@@ -149677,19 +149916,41 @@ function stopRuntime(rt) {
149677
149916
  rt.sessionId = null;
149678
149917
  runtimes.delete(rt.chatId);
149679
149918
  }
149680
- function scheduleIdle(rt) {
149919
+ function idleTimeoutMs() {
149920
+ const override = Number(process.env.BAND_AGENT_IDLE_TIMEOUT_MS);
149921
+ return Number.isFinite(override) && override > 0 ? override : IDLE_TIMEOUT_MS;
149922
+ }
149923
+ function scheduleIdle(rt, delayMs = idleTimeoutMs()) {
149681
149924
  if (rt.idleTimer) clearTimeout(rt.idleTimer);
149925
+ const delay2 = Math.min(delayMs, MAX_TIMER_MS);
149682
149926
  rt.idleTimer = setTimeout(() => {
149683
149927
  rt.idleTimer = null;
149684
149928
  if (rt.inTurn || rt.pending.size > 0 || rt.attaching) return;
149929
+ const now = Date.now();
149930
+ const holds = rt.work.outstanding(now);
149931
+ if (holds.length > 0) {
149932
+ const until = Math.max(...holds.map((h) => h.until));
149933
+ log31.info(
149934
+ {
149935
+ chatId: rt.chatId,
149936
+ work: holds.map((h) => ({ reason: h.reason, until: new Date(h.until).toISOString() }))
149937
+ },
149938
+ "idle agent has pending work; not stopping it"
149939
+ );
149940
+ scheduleIdle(rt, until - now + idleTimeoutMs());
149941
+ return;
149942
+ }
149685
149943
  log31.info({ chatId: rt.chatId }, "stopping idle agent");
149686
149944
  rt.process?.close();
149687
149945
  rt.process = null;
149688
149946
  rt.sessionId = null;
149689
149947
  if (runtimes.get(rt.chatId) === rt) runtimes.delete(rt.chatId);
149690
- }, IDLE_TIMEOUT_MS);
149948
+ }, delay2);
149691
149949
  rt.idleTimer.unref?.();
149692
149950
  }
149951
+ function agentActive(rt) {
149952
+ if (!rt.inTurn && !rt.attaching && rt.process) scheduleIdle(rt);
149953
+ }
149693
149954
  function record2(rt, event, turnStart = false) {
149694
149955
  if (!rt.sessionId) {
149695
149956
  broadcastTransient(rt.chatId, event);
@@ -149805,6 +150066,10 @@ function routeUpdate(rt, notification) {
149805
150066
  }
149806
150067
  const update = notification.update;
149807
150068
  applyLive(rt, update);
150069
+ if (!rt.attaching) {
150070
+ rt.work.observeUpdate(update, rt.inTurn);
150071
+ agentActive(rt);
150072
+ }
149808
150073
  if (rt.routing === "drop") return;
149809
150074
  if (update.sessionUpdate === "user_message_chunk") {
149810
150075
  if (rt.inTurn) return;
@@ -149875,6 +150140,11 @@ function requestElicitation(rt, request, signal) {
149875
150140
  function handlersFor(rt, generation) {
149876
150141
  return {
149877
150142
  onUpdate: (n) => routeUpdate(rt, n),
150143
+ onAsyncTask: (n) => {
150144
+ if (n.sessionId !== rt.sessionId || rt.attaching) return;
150145
+ rt.work.observeAsyncTask(n.update);
150146
+ agentActive(rt);
150147
+ },
149878
150148
  onPermission: (req, signal) => requestPermission(rt, req, signal),
149879
150149
  onElicitation: (req, signal) => requestElicitation(rt, req, signal),
149880
150150
  onExit: (code, stderr) => {
@@ -149882,6 +150152,7 @@ function handlersFor(rt, generation) {
149882
150152
  log31.info({ chatId: rt.chatId, code }, "agent exited");
149883
150153
  log31.debug({ chatId: rt.chatId, stderr: stderr.slice(-500) }, "agent stderr");
149884
150154
  for (const p3 of [...rt.pending.values()]) p3.cancel();
150155
+ rt.work.clear();
149885
150156
  rt.process = null;
149886
150157
  rt.starting = null;
149887
150158
  }
@@ -150844,7 +151115,7 @@ async function handleChatSubmit(req, res, chatId) {
150844
151115
  }));
150845
151116
  }
150846
151117
  try {
150847
- taskService.submitTask({
151118
+ const result = taskService.submitOrQueueTask({
150848
151119
  workspaceId: workspaceId2,
150849
151120
  chatId,
150850
151121
  prompt: text3,
@@ -150854,18 +151125,12 @@ async function handleChatSubmit(req, res, chatId) {
150854
151125
  model,
150855
151126
  codingAgentId
150856
151127
  });
150857
- log33.info({ chatId, workspaceId: workspaceId2 }, "chat-submit: task started");
150858
- sendJson2(res, 200, { ok: true, queued: false });
151128
+ log33.info(
151129
+ { chatId, workspaceId: workspaceId2 },
151130
+ result.queued ? "chat-submit: chat busy, message queued" : "chat-submit: task started"
151131
+ );
151132
+ sendJson2(res, 200, { ok: true, queued: result.queued });
150859
151133
  } catch (err) {
150860
- if (err instanceof TaskConflictError) {
150861
- pushQueuedMessage(chatId, {
150862
- text: text3,
150863
- ...attachments.length > 0 && { files: attachments }
150864
- });
150865
- log33.info({ chatId, workspaceId: workspaceId2 }, "chat-submit: task busy, message queued");
150866
- sendJson2(res, 200, { ok: true, queued: true });
150867
- return;
150868
- }
150869
151134
  if (err instanceof WorkspaceNotFoundError) {
150870
151135
  sendJson2(res, 404, { error: err.message });
150871
151136
  return;
@@ -155807,7 +156072,7 @@ var McpServer = class {
155807
156072
  /**
155808
156073
  * Validates tool input arguments against the tool's input schema.
155809
156074
  */
155810
- async validateToolInput(tool, args, toolName) {
156075
+ async validateToolInput(tool, args, toolName2) {
155811
156076
  if (!tool.inputSchema) {
155812
156077
  return void 0;
155813
156078
  }
@@ -155817,14 +156082,14 @@ var McpServer = class {
155817
156082
  if (!parseResult.success) {
155818
156083
  const error40 = "error" in parseResult ? parseResult.error : "Unknown error";
155819
156084
  const errorMessage = getParseErrorMessage(error40);
155820
- throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`);
156085
+ throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName2}: ${errorMessage}`);
155821
156086
  }
155822
156087
  return parseResult.data;
155823
156088
  }
155824
156089
  /**
155825
156090
  * Validates tool output against the tool's output schema.
155826
156091
  */
155827
- async validateToolOutput(tool, result, toolName) {
156092
+ async validateToolOutput(tool, result, toolName2) {
155828
156093
  if (!tool.outputSchema) {
155829
156094
  return;
155830
156095
  }
@@ -155835,14 +156100,14 @@ var McpServer = class {
155835
156100
  return;
155836
156101
  }
155837
156102
  if (!result.structuredContent) {
155838
- throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`);
156103
+ throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName2} has an output schema but no structured content was provided`);
155839
156104
  }
155840
156105
  const outputObj = normalizeObjectSchema(tool.outputSchema);
155841
156106
  const parseResult = await safeParseAsync3(outputObj, result.structuredContent);
155842
156107
  if (!parseResult.success) {
155843
156108
  const error40 = "error" in parseResult ? parseResult.error : "Unknown error";
155844
156109
  const errorMessage = getParseErrorMessage(error40);
155845
- throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage}`);
156110
+ throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName2}: ${errorMessage}`);
155846
156111
  }
155847
156112
  }
155848
156113
  /**
@@ -158627,23 +158892,25 @@ var chatsRouter = t3.router({
158627
158892
  if (!chat) {
158628
158893
  chat = chatService.create(input.workspaceId, { id: input.chatId, name: "Chat" });
158629
158894
  }
158630
- try {
158631
- const task = taskService.submitTask({
158632
- workspaceId: chat.workspaceId,
158633
- chatId: chat.id,
158634
- prompt: input.message,
158635
- sessionId: input.sessionId
158636
- });
158637
- return { taskId: task.id, sessionId: task.sessionId };
158638
- } catch (err) {
158639
- if (err instanceof TaskConflictError) {
158640
- throw new TRPCError({
158641
- code: "CONFLICT",
158642
- message: "Task already running for this chat pane"
158643
- });
158644
- }
158645
- throw err;
158895
+ const result = taskService.submitOrQueueTask({
158896
+ workspaceId: chat.workspaceId,
158897
+ chatId: chat.id,
158898
+ prompt: input.message,
158899
+ sessionId: input.sessionId
158900
+ });
158901
+ if (result.queued) {
158902
+ return {
158903
+ queued: true,
158904
+ queuedMessageId: result.queuedMessageId,
158905
+ taskId: null,
158906
+ sessionId: null
158907
+ };
158646
158908
  }
158909
+ return {
158910
+ queued: false,
158911
+ taskId: result.task.id,
158912
+ sessionId: result.task.sessionId
158913
+ };
158647
158914
  }),
158648
158915
  stop: publicProcedure.input(external_exports2.object({ chatId: external_exports2.string() })).mutation(({ input }) => {
158649
158916
  taskService.abortTask(input.chatId);
@@ -162148,7 +162415,7 @@ var tasksRouter = t3.router({
162148
162415
  }));
162149
162416
  }
162150
162417
  try {
162151
- const task = taskService.submitTask({
162418
+ const result = taskService.submitOrQueueTask({
162152
162419
  workspaceId: input.workspaceId,
162153
162420
  chatId,
162154
162421
  prompt: input.prompt,
@@ -162158,7 +162425,19 @@ var tasksRouter = t3.router({
162158
162425
  model: input.model,
162159
162426
  codingAgentId: input.codingAgentId
162160
162427
  });
162428
+ if (result.queued) {
162429
+ return {
162430
+ queued: true,
162431
+ id: null,
162432
+ queuedMessageId: result.queuedMessageId,
162433
+ workspaceId: input.workspaceId,
162434
+ chatId,
162435
+ sessionId: null
162436
+ };
162437
+ }
162438
+ const { task } = result;
162161
162439
  return {
162440
+ queued: false,
162162
162441
  id: task.id,
162163
162442
  workspaceId: task.workspaceId,
162164
162443
  chatId: task.chatId,
@@ -164993,10 +165272,10 @@ function discoverProcedures() {
164993
165272
  for (const [path, procedure] of Object.entries(procRecord)) {
164994
165273
  const type = procedure._def.type;
164995
165274
  if (type === "subscription") continue;
164996
- const toolName = `band_${path.replace(/\./g, "_")}`;
165275
+ const toolName2 = `band_${path.replace(/\./g, "_")}`;
164997
165276
  const inputs = procedure._def.inputs;
164998
165277
  const inputSchema = inputs.length > 0 ? inputs[0] : void 0;
164999
- procedures.push({ path, toolName, type, inputSchema });
165278
+ procedures.push({ path, toolName: toolName2, type, inputSchema });
165000
165279
  }
165001
165280
  return procedures;
165002
165281
  }