agent-tower 0.7.3 → 0.7.4-beta.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 (294) hide show
  1. package/dist/git/worktree.manager.d.ts +2 -0
  2. package/dist/git/worktree.manager.d.ts.map +1 -1
  3. package/dist/git/worktree.manager.js +29 -8
  4. package/dist/git/worktree.manager.js.map +1 -1
  5. package/dist/git/worktree.manager.test.js +38 -0
  6. package/dist/git/worktree.manager.test.js.map +1 -1
  7. package/dist/mcp/http-client.d.ts +3 -1
  8. package/dist/mcp/http-client.d.ts.map +1 -1
  9. package/dist/mcp/http-client.js +6 -0
  10. package/dist/mcp/http-client.js.map +1 -1
  11. package/dist/mcp/tools/__tests__/tasks.test.js +33 -1
  12. package/dist/mcp/tools/__tests__/tasks.test.js.map +1 -1
  13. package/dist/mcp/tools/tasks.d.ts.map +1 -1
  14. package/dist/mcp/tools/tasks.js +30 -2
  15. package/dist/mcp/tools/tasks.js.map +1 -1
  16. package/dist/mcp/types.d.ts +24 -0
  17. package/dist/mcp/types.d.ts.map +1 -1
  18. package/dist/mcp/types.js +12 -1
  19. package/dist/mcp/types.js.map +1 -1
  20. package/dist/prompts/task-handoff.d.ts +6 -0
  21. package/dist/prompts/task-handoff.d.ts.map +1 -0
  22. package/dist/prompts/task-handoff.js +18 -0
  23. package/dist/prompts/task-handoff.js.map +1 -0
  24. package/dist/prompts/task-handoff.test.d.ts +2 -0
  25. package/dist/prompts/task-handoff.test.d.ts.map +1 -0
  26. package/dist/prompts/task-handoff.test.js +27 -0
  27. package/dist/prompts/task-handoff.test.js.map +1 -0
  28. package/dist/prompts/workspace-background-service-policy.d.ts +6 -0
  29. package/dist/prompts/workspace-background-service-policy.d.ts.map +1 -1
  30. package/dist/prompts/workspace-background-service-policy.js +2 -1
  31. package/dist/prompts/workspace-background-service-policy.js.map +1 -1
  32. package/dist/routes/__tests__/sessions-runtime.test.js +2 -0
  33. package/dist/routes/__tests__/sessions-runtime.test.js.map +1 -1
  34. package/dist/routes/__tests__/task-handoff.test.d.ts +2 -0
  35. package/dist/routes/__tests__/task-handoff.test.d.ts.map +1 -0
  36. package/dist/routes/__tests__/task-handoff.test.js +185 -0
  37. package/dist/routes/__tests__/task-handoff.test.js.map +1 -0
  38. package/dist/routes/__tests__/tasks.test.js +64 -0
  39. package/dist/routes/__tests__/tasks.test.js.map +1 -1
  40. package/dist/routes/__tests__/workspace-history.test.d.ts +2 -0
  41. package/dist/routes/__tests__/workspace-history.test.d.ts.map +1 -0
  42. package/dist/routes/__tests__/workspace-history.test.js +174 -0
  43. package/dist/routes/__tests__/workspace-history.test.js.map +1 -0
  44. package/dist/routes/sessions.d.ts.map +1 -1
  45. package/dist/routes/sessions.js +10 -0
  46. package/dist/routes/sessions.js.map +1 -1
  47. package/dist/routes/tasks.d.ts.map +1 -1
  48. package/dist/routes/tasks.js +67 -2
  49. package/dist/routes/tasks.js.map +1 -1
  50. package/dist/runtime/__tests__/cli-driver-lifecycle.test.js +84 -0
  51. package/dist/runtime/__tests__/cli-driver-lifecycle.test.js.map +1 -1
  52. package/dist/runtime/cli-driver.js +11 -8
  53. package/dist/runtime/cli-driver.js.map +1 -1
  54. package/dist/services/__tests__/session-manager.lifecycle.test.js +171 -1
  55. package/dist/services/__tests__/session-manager.lifecycle.test.js.map +1 -1
  56. package/dist/services/__tests__/task.service.test.js +152 -76
  57. package/dist/services/__tests__/task.service.test.js.map +1 -1
  58. package/dist/services/__tests__/workspace-background-service.service.test.js +74 -26
  59. package/dist/services/__tests__/workspace-background-service.service.test.js.map +1 -1
  60. package/dist/services/__tests__/workspace.service.test.js +100 -5
  61. package/dist/services/__tests__/workspace.service.test.js.map +1 -1
  62. package/dist/services/message-delivery.service.d.ts +3 -0
  63. package/dist/services/message-delivery.service.d.ts.map +1 -1
  64. package/dist/services/project.service.d.ts +2 -0
  65. package/dist/services/project.service.d.ts.map +1 -1
  66. package/dist/services/session-manager.d.ts +12 -1
  67. package/dist/services/session-manager.d.ts.map +1 -1
  68. package/dist/services/session-manager.js +21 -3
  69. package/dist/services/session-manager.js.map +1 -1
  70. package/dist/services/session-resource-cleanup.d.ts +5 -0
  71. package/dist/services/session-resource-cleanup.d.ts.map +1 -1
  72. package/dist/services/session-resource-cleanup.js +7 -0
  73. package/dist/services/session-resource-cleanup.js.map +1 -1
  74. package/dist/services/task-cleanup.service.d.ts +4 -0
  75. package/dist/services/task-cleanup.service.d.ts.map +1 -1
  76. package/dist/services/task-cleanup.service.js +6 -2
  77. package/dist/services/task-cleanup.service.js.map +1 -1
  78. package/dist/services/task-handoff.service.d.ts +18 -0
  79. package/dist/services/task-handoff.service.d.ts.map +1 -0
  80. package/dist/services/task-handoff.service.js +87 -0
  81. package/dist/services/task-handoff.service.js.map +1 -0
  82. package/dist/services/task.service.d.ts +46 -10
  83. package/dist/services/task.service.d.ts.map +1 -1
  84. package/dist/services/task.service.js +258 -170
  85. package/dist/services/task.service.js.map +1 -1
  86. package/dist/services/team-run.service.d.ts +2 -0
  87. package/dist/services/team-run.service.d.ts.map +1 -1
  88. package/dist/services/team-task-input.service.d.ts +2 -0
  89. package/dist/services/team-task-input.service.d.ts.map +1 -1
  90. package/dist/services/workspace-background-service.service.d.ts +1 -3
  91. package/dist/services/workspace-background-service.service.d.ts.map +1 -1
  92. package/dist/services/workspace-background-service.service.js +17 -65
  93. package/dist/services/workspace-background-service.service.js.map +1 -1
  94. package/dist/services/workspace.service.d.ts +20 -7
  95. package/dist/services/workspace.service.d.ts.map +1 -1
  96. package/dist/services/workspace.service.js +197 -82
  97. package/dist/services/workspace.service.js.map +1 -1
  98. package/dist/web/assets/AgentDemoPage-DiHEh1iv.js +1 -0
  99. package/dist/web/assets/{AgentEnvironmentSettingsPage-CvvkMKT1.js → AgentEnvironmentSettingsPage-B_Xk7Bef.js} +1 -1
  100. package/dist/web/assets/AttachmentPreview-BngGSahV.js +2 -0
  101. package/dist/web/assets/{BranchSelect-Cv92vEjG.js → BranchSelect-BgVKUnxj.js} +1 -1
  102. package/dist/web/assets/BrandLogo-CBahjTd7.js +1 -0
  103. package/dist/web/assets/ConversationPage-kgJIlyS5.js +1 -0
  104. package/dist/web/assets/CreateTaskInput-Cllw4abW.js +1 -0
  105. package/dist/web/assets/{DemoPage-CpYNBQhA.js → DemoPage-CkS__9CE.js} +3 -3
  106. package/dist/web/assets/{DesignSystemPage-DLeH6DnV.js → DesignSystemPage-BklN99GA.js} +3 -3
  107. package/dist/web/assets/{ExecutionPermissionSelector-IoWR9YLb.js → ExecutionPermissionSelector-Bsi1aa7q.js} +1 -1
  108. package/dist/web/assets/{GeneralSettingsPage-BAYgxCqx.js → GeneralSettingsPage-BC9TUWiu.js} +1 -1
  109. package/dist/web/assets/{LoadingPreviewPage-CumrzyxW.js → LoadingPreviewPage-Dx8Si6-g.js} +1 -1
  110. package/dist/web/assets/{McpSettingsPage-CFNwxT9Y.js → McpSettingsPage-fqXRGtFu.js} +1 -1
  111. package/dist/web/assets/{MemberAvatar-BVXD0jTy.js → MemberAvatar-CZ3F53Ep.js} +1 -1
  112. package/dist/web/assets/MobileTaskDetail-B68iYPOI.js +3 -0
  113. package/dist/web/assets/{NotificationSettingsPage-B0s5YbG3.js → NotificationSettingsPage-D9KGIFVA.js} +1 -1
  114. package/dist/web/assets/{ProfileSettingsPage-BuhoF-mL.js → ProfileSettingsPage-D_Hw5lpd.js} +2 -2
  115. package/dist/web/assets/ProjectKanbanPage-CUX0Kh-t.js +12 -0
  116. package/dist/web/assets/{ProjectSettingsPage-DDMg6axy.js → ProjectSettingsPage-CJANCPJX.js} +2 -2
  117. package/dist/web/assets/{ProviderSettingsPage-DRt9m4mF.js → ProviderSettingsPage-B6Ro5PQa.js} +2 -2
  118. package/dist/web/assets/{SettingsMasterDetail-D7vStQjR.js → SettingsMasterDetail-Q-049Dvh.js} +1 -1
  119. package/dist/web/assets/TaskDetail-DBtWf0YV.js +1 -0
  120. package/dist/web/assets/TaskHandoffPanel-BpGiZ5eT.js +70 -0
  121. package/dist/web/assets/TeamSettingsPage-DbKgqEO_.js +1 -0
  122. package/dist/web/assets/{TranslationSettingsPage-D2oks6OM.js → TranslationSettingsPage-Ba-iypOV.js} +1 -1
  123. package/dist/web/assets/{arc-vYWCZsE_.js → arc-SOqs3Svk.js} +1 -1
  124. package/dist/web/assets/{architectureDiagram-3BPJPVTR-Cu1VIpcJ.js → architectureDiagram-3BPJPVTR-BH25ukq_.js} +1 -1
  125. package/dist/web/assets/{at-sign-BhSPafOS.js → at-sign-CEsum1vJ.js} +1 -1
  126. package/dist/web/assets/{blockDiagram-GPEHLZMM-C4x_nj5S.js → blockDiagram-GPEHLZMM-CKA17iNP.js} +1 -1
  127. package/dist/web/assets/{c4Diagram-AAUBKEIU-jHOo5lal.js → c4Diagram-AAUBKEIU-DnZ_8oOf.js} +1 -1
  128. package/dist/web/assets/channel-xU45IQlP.js +1 -0
  129. package/dist/web/assets/check-DUA2DjGH.js +1 -0
  130. package/dist/web/assets/{chevron-down-BoS08pMa.js → chevron-down-Bmwy-nvS.js} +1 -1
  131. package/dist/web/assets/{chevron-up-BWtKfdKT.js → chevron-up-CClL6-SF.js} +1 -1
  132. package/dist/web/assets/{chip-Ck4dqxR3.js → chip-BSMT2uT1.js} +1 -1
  133. package/dist/web/assets/{chunk-2J33WTMH-BZcpjmfm.js → chunk-2J33WTMH-BrtUyBDF.js} +1 -1
  134. package/dist/web/assets/{chunk-4BX2VUAB-DZGB3q-I.js → chunk-4BX2VUAB-DZDNetDC.js} +1 -1
  135. package/dist/web/assets/{chunk-55IACEB6-CcNrOmyy.js → chunk-55IACEB6-xVa3bJqv.js} +1 -1
  136. package/dist/web/assets/{chunk-727SXJPM-dWrxio8O.js → chunk-727SXJPM-B7n9vxY4.js} +1 -1
  137. package/dist/web/assets/{chunk-AQP2D5EJ-K4gkVzqE.js → chunk-AQP2D5EJ-DQd4G76y.js} +1 -1
  138. package/dist/web/assets/{chunk-FMBD7UC4-CnHyY4qD.js → chunk-FMBD7UC4-CXyP08kl.js} +1 -1
  139. package/dist/web/assets/{chunk-ND2GUHAM-CHUmcyDv.js → chunk-ND2GUHAM-BtnIS-HK.js} +1 -1
  140. package/dist/web/assets/{chunk-QZHKN3VN-Bzzjd-Qt.js → chunk-QZHKN3VN-D4D-V_ex.js} +1 -1
  141. package/dist/web/assets/classDiagram-4FO5ZUOK-pvRulc6s.js +1 -0
  142. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-pvRulc6s.js +1 -0
  143. package/dist/web/assets/{code-block-OCS4YCEC-B2hHBO_G.js → code-block-OCS4YCEC-DfERo9L1.js} +1 -1
  144. package/dist/web/assets/confirm-dialog-8ItnHBi0.js +1 -0
  145. package/dist/web/assets/{content-D0qmHfHK.js → content-DrW8KnXu.js} +2 -2
  146. package/dist/web/assets/{copy-C4WnOY6Y.js → copy-prrQrInw.js} +1 -1
  147. package/dist/web/assets/{cose-bilkent-S5V4N54A-Dcn8tOhb.js → cose-bilkent-S5V4N54A-CXdH8Idq.js} +1 -1
  148. package/dist/web/assets/cssMode-CJ6_f10q.js +1 -0
  149. package/dist/web/assets/{dagre-BM42HDAG-DWBV4UfP.js → dagre-BM42HDAG-XZydDwXe.js} +1 -1
  150. package/dist/web/assets/{diagram-2AECGRRQ-CnNTJQ3q.js → diagram-2AECGRRQ-CofEe0Fr.js} +1 -1
  151. package/dist/web/assets/{diagram-5GNKFQAL-DlXJFzDF.js → diagram-5GNKFQAL-BbTtW5WH.js} +1 -1
  152. package/dist/web/assets/{diagram-KO2AKTUF-DZ22YV4n.js → diagram-KO2AKTUF-BJHZXpUM.js} +1 -1
  153. package/dist/web/assets/{diagram-LMA3HP47-B4pQJjG9.js → diagram-LMA3HP47-DN7A27YU.js} +1 -1
  154. package/dist/web/assets/{diagram-OG6HWLK6-DJBLjtgL.js → diagram-OG6HWLK6-4IdYadiw.js} +1 -1
  155. package/dist/web/assets/{dialog-1o8KQWoQ.js → dialog-BUsI4h2U.js} +2 -2
  156. package/dist/web/assets/{erDiagram-TEJ5UH35-CDsfoJUT.js → erDiagram-TEJ5UH35-BFijhCWv.js} +1 -1
  157. package/dist/web/assets/{file-6qwbIga1.js → file-C6QMUr5_.js} +1 -1
  158. package/dist/web/assets/{flowDiagram-I6XJVG4X-CuGOAYmY.js → flowDiagram-I6XJVG4X-D9MxC-El.js} +1 -1
  159. package/dist/web/assets/{folder-picker-Cj1VZOZU.js → folder-picker-CBdw-4v3.js} +1 -1
  160. package/dist/web/assets/{freemarker2-BG8VyI2V.js → freemarker2-CJVobC22.js} +2 -2
  161. package/dist/web/assets/{ganttDiagram-6RSMTGT7-BjrSOqAM.js → ganttDiagram-6RSMTGT7-BijCAyPQ.js} +1 -1
  162. package/dist/web/assets/{gitGraphDiagram-PVQCEYII-4VVr4F8_.js → gitGraphDiagram-PVQCEYII-AvI5QqxQ.js} +1 -1
  163. package/dist/web/assets/{globe-CxeM27yy.js → globe-BOfcTsvL.js} +1 -1
  164. package/dist/web/assets/handlebars-DTqWmI25.js +1 -0
  165. package/dist/web/assets/html-Bx7L8DX_.js +1 -0
  166. package/dist/web/assets/htmlMode-D_S0NjZc.js +1 -0
  167. package/dist/web/assets/{index-hHrknzh7.js → index-BClyhWqz.js} +1 -1
  168. package/dist/web/assets/index-BDON669P.css +1 -0
  169. package/dist/web/assets/{index-DVdiOmqt.js → index-BFcDmhr0.js} +1 -1
  170. package/dist/web/assets/index-BRu1Yhrx.js +122 -0
  171. package/dist/web/assets/{index-Db28hRe8.js → index-Bg8TlDo_.js} +1 -1
  172. package/dist/web/assets/{index-Da2mWAtm.js → index-COigMgrJ.js} +1 -1
  173. package/dist/web/assets/{index-cu8sedJH.js → index-Cdmj8aPv.js} +1 -1
  174. package/dist/web/assets/index-CtOu4p9B.js +1 -0
  175. package/dist/web/assets/{index-CrKx8Yaz.js → index-DUmVscrR.js} +4 -4
  176. package/dist/web/assets/{index-C1lMEjmZ.js → index-JXcQeorP.js} +1 -1
  177. package/dist/web/assets/{infoDiagram-5YYISTIA-Cy9ntb6t.js → infoDiagram-5YYISTIA-76JLqjJ0.js} +1 -1
  178. package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-D6UiVzRz.js → ishikawaDiagram-YF4QCWOH-CXHFTVly.js} +1 -1
  179. package/dist/web/assets/javascript-80FDzX3y.js +1 -0
  180. package/dist/web/assets/{journeyDiagram-JHISSGLW-owdKzZoh.js → journeyDiagram-JHISSGLW-6SDJs9C5.js} +1 -1
  181. package/dist/web/assets/jsonMode-BGg9MhFR.js +7 -0
  182. package/dist/web/assets/{kanban-definition-UN3LZRKU-v5TBnyp0.js → kanban-definition-UN3LZRKU-C0Y3zy1P.js} +1 -1
  183. package/dist/web/assets/{kbd-Cl4AzzJp.js → kbd-D4KIW7lm.js} +1 -1
  184. package/dist/web/assets/{key-round-CnYjSrCz.js → key-round-C4vhwqUu.js} +1 -1
  185. package/dist/web/assets/{layers-XImbMX-P.js → layers-BBHgMnhN.js} +1 -1
  186. package/dist/web/assets/{linear-DNlKYt8R.js → linear-CjeIgBwO.js} +1 -1
  187. package/dist/web/assets/{link-DQk-Vapq.js → link-C-Jq7dnc.js} +1 -1
  188. package/dist/web/assets/liquid-guocpCJB.js +1 -0
  189. package/dist/web/assets/{lspLanguageFeatures-DD_y1bZa.js → lspLanguageFeatures-CPXERxVW.js} +1 -1
  190. package/dist/web/assets/mdx-DA4ymd3l.js +1 -0
  191. package/dist/web/assets/{menu-DXF6iUsq.js → menu-BgtmXAzT.js} +1 -1
  192. package/dist/web/assets/{mermaid-NOHMQCX5-CG_LpwAI.js → mermaid-NOHMQCX5-XQbfQDGS.js} +49 -49
  193. package/dist/web/assets/{message-square-BviHdb67.js → message-square-DIFv9yrO.js} +1 -1
  194. package/dist/web/assets/{mindmap-definition-RKZ34NQL-Bn_rnnGT.js → mindmap-definition-RKZ34NQL-6ucD61UV.js} +1 -1
  195. package/dist/web/assets/modal-Dx4N46s5.js +1 -0
  196. package/dist/web/assets/{monaco-yuGji-2E.js → monaco-Mn1xgio_.js} +3 -3
  197. package/dist/web/assets/nav-row-DwEkbw3N.js +1 -0
  198. package/dist/web/assets/{paperclip-D9ka2IAB.js → paperclip-CdQvl5ee.js} +1 -1
  199. package/dist/web/assets/{pencil-isP1rXC-.js → pencil-ChX7G9j9.js} +1 -1
  200. package/dist/web/assets/{people-CbmH8m4i.js → people-D_VwidfV.js} +1 -1
  201. package/dist/web/assets/{pieDiagram-4H26LBE5-DIE_f9W_.js → pieDiagram-4H26LBE5-KVvAyrIn.js} +1 -1
  202. package/dist/web/assets/{popover-D8VtO5qF.js → popover-CGEFZKuu.js} +1 -1
  203. package/dist/web/assets/python-BzNNRn8W.js +1 -0
  204. package/dist/web/assets/{quadrantDiagram-W4KKPZXB-CavFxJCk.js → quadrantDiagram-W4KKPZXB-ClVzvpE7.js} +1 -1
  205. package/dist/web/assets/razor-DF2ZxqCE.js +1 -0
  206. package/dist/web/assets/{requirementDiagram-4Y6WPE33-Dm1FwUUh.js → requirementDiagram-4Y6WPE33-uXN6Uoln.js} +1 -1
  207. package/dist/web/assets/{sankeyDiagram-5OEKKPKP-qeqcO27M.js → sankeyDiagram-5OEKKPKP-Bi3Tc0wR.js} +1 -1
  208. package/dist/web/assets/{search-DOMr5jPS.js → search--FRFbCre.js} +1 -1
  209. package/dist/web/assets/{select-Cw5BaOLQ.js → select-D0sHgfcU.js} +1 -1
  210. package/dist/web/assets/{select-CzZNbe1Z.js → select-c5IIpQj0.js} +1 -1
  211. package/dist/web/assets/{sequenceDiagram-3UESZ5HK-Dqtb3BYG.js → sequenceDiagram-3UESZ5HK-CLdrO2PY.js} +1 -1
  212. package/dist/web/assets/{server-u-PC-CcX.js → server-Dr_6KJFM.js} +1 -1
  213. package/dist/web/assets/{stateDiagram-AJRCARHV-C_MqF9Fy.js → stateDiagram-AJRCARHV-BGInldGc.js} +1 -1
  214. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-D44x8SXb.js +1 -0
  215. package/dist/web/assets/{textarea-xt2hLb-d.js → textarea-W-xQPto3.js} +1 -1
  216. package/dist/web/assets/{timeline-definition-PNZ67QCA-Bzov6t31.js → timeline-definition-PNZ67QCA-BUp6Qykc.js} +1 -1
  217. package/dist/web/assets/{toggles-B6E1UBYN.js → toggles-Bgp7vdwg.js} +1 -1
  218. package/dist/web/assets/tooltip-DZcaSN1F.js +1 -0
  219. package/dist/web/assets/{track-BeqaPopG.js → track-Cj1Ogapu.js} +1 -1
  220. package/dist/web/assets/{trash-2-5jI3_KHh.js → trash-2-DmFXzIhh.js} +1 -1
  221. package/dist/web/assets/tsMode-CSHMQttX.js +11 -0
  222. package/dist/web/assets/typescript-CyQKmnN-.js +1 -0
  223. package/dist/web/assets/{upload-DUteazR7.js → upload-C-4QDrwN.js} +1 -1
  224. package/dist/web/assets/use-profiles-D5mIgeQU.js +1 -0
  225. package/dist/web/assets/{use-providers-CQwBj9hp.js → use-providers-BViTes-6.js} +1 -1
  226. package/dist/web/assets/{use-translation-settings-DBzFqP-d.js → use-translation-settings-Dgw0oKP1.js} +1 -1
  227. package/dist/web/assets/{useNormalizedLogs-DsdwmfS7.js → useNormalizedLogs-BX7pMg0-.js} +1 -1
  228. package/dist/web/assets/useTokenUsage-T03faPfn.js +1 -0
  229. package/dist/web/assets/{vennDiagram-CIIHVFJN-BqxICvT_.js → vennDiagram-CIIHVFJN-iQYnP9Ux.js} +1 -1
  230. package/dist/web/assets/{wardley-L42UT6IY-BTdLPFcA.js → wardley-L42UT6IY-J7vXwA5J.js} +1 -1
  231. package/dist/web/assets/{wardleyDiagram-YWT4CUSO-icnFsFn4.js → wardleyDiagram-YWT4CUSO-CdtM5GJv.js} +1 -1
  232. package/dist/web/assets/xml-C79KdvcD.js +1 -0
  233. package/dist/web/assets/{xychartDiagram-2RQKCTM6-BN2_ducK.js → xychartDiagram-2RQKCTM6-B3gcBChQ.js} +1 -1
  234. package/dist/web/assets/yaml-C1WLpuVe.js +1 -0
  235. package/dist/web/index.html +2 -2
  236. package/node_modules/@agent-tower/shared/dist/index.d.ts +2 -0
  237. package/node_modules/@agent-tower/shared/dist/index.d.ts.map +1 -1
  238. package/node_modules/@agent-tower/shared/dist/index.js +2 -0
  239. package/node_modules/@agent-tower/shared/dist/index.js.map +1 -1
  240. package/node_modules/@agent-tower/shared/dist/task-handoff.d.ts +12 -0
  241. package/node_modules/@agent-tower/shared/dist/task-handoff.d.ts.map +1 -0
  242. package/node_modules/@agent-tower/shared/dist/task-handoff.js +2 -0
  243. package/node_modules/@agent-tower/shared/dist/task-handoff.js.map +1 -0
  244. package/node_modules/@agent-tower/shared/dist/task-hierarchy.d.ts +17 -0
  245. package/node_modules/@agent-tower/shared/dist/task-hierarchy.d.ts.map +1 -0
  246. package/node_modules/@agent-tower/shared/dist/task-hierarchy.js +12 -0
  247. package/node_modules/@agent-tower/shared/dist/task-hierarchy.js.map +1 -0
  248. package/node_modules/@agent-tower/shared/dist/types.d.ts +22 -1
  249. package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -1
  250. package/node_modules/@agent-tower/shared/dist/types.js.map +1 -1
  251. package/package.json +1 -1
  252. package/prisma/migrations/20261023010000_add_subtasks/migration.sql +2 -0
  253. package/prisma/migrations/20261026000000_add_task_handoff/migration.sql +1 -0
  254. package/prisma/migrations/20261027000000_preserve_workspace_history/migration.sql +2 -0
  255. package/prisma/schema.prisma +7 -0
  256. package/dist/web/assets/AgentDemoPage-Dwux6TyV.js +0 -1
  257. package/dist/web/assets/AttachmentPreview-CFJ6MZ1f.js +0 -2
  258. package/dist/web/assets/BrandLogo-H4nCbVzs.js +0 -1
  259. package/dist/web/assets/ConversationPage-CZzGME21.js +0 -1
  260. package/dist/web/assets/CreateTaskInput-BM2tx4hJ.js +0 -1
  261. package/dist/web/assets/EditableTaskTitle-BEsiULnD.js +0 -70
  262. package/dist/web/assets/MobileTaskDetail-IOQ1WnS8.js +0 -3
  263. package/dist/web/assets/ProjectKanbanPage-DMtv15rq.js +0 -12
  264. package/dist/web/assets/TaskDetail-DzKbs5Jt.js +0 -1
  265. package/dist/web/assets/TeamSettingsPage-fjlaqaLo.js +0 -1
  266. package/dist/web/assets/channel-D1cEj22-.js +0 -1
  267. package/dist/web/assets/check-D_VFGpIy.js +0 -1
  268. package/dist/web/assets/classDiagram-4FO5ZUOK-DIrDMefa.js +0 -1
  269. package/dist/web/assets/classDiagram-v2-Q7XG4LA2-DIrDMefa.js +0 -1
  270. package/dist/web/assets/confirm-dialog-CL_1pF4K.js +0 -1
  271. package/dist/web/assets/cssMode-CXBMyfYY.js +0 -1
  272. package/dist/web/assets/handlebars-Ci38FPsA.js +0 -1
  273. package/dist/web/assets/html-5hdYEgVF.js +0 -1
  274. package/dist/web/assets/htmlMode-BzU9qsw0.js +0 -1
  275. package/dist/web/assets/icon-button-BmrJtYFC.js +0 -1
  276. package/dist/web/assets/index-BR3Wg2fS.js +0 -122
  277. package/dist/web/assets/index-DSy5JLC1.js +0 -1
  278. package/dist/web/assets/index-DZLg4-xM.css +0 -1
  279. package/dist/web/assets/javascript-Ib060GQ8.js +0 -1
  280. package/dist/web/assets/jsonMode-CLmu6gzc.js +0 -7
  281. package/dist/web/assets/liquid-Bc7OSAPR.js +0 -1
  282. package/dist/web/assets/mdx-CxJNHHTn.js +0 -1
  283. package/dist/web/assets/modal-D496f1fE.js +0 -1
  284. package/dist/web/assets/python-C0E43gUo.js +0 -1
  285. package/dist/web/assets/razor-xarhYR9V.js +0 -1
  286. package/dist/web/assets/stateDiagram-v2-BHNVJYJU-BxmbGAhh.js +0 -1
  287. package/dist/web/assets/tooltip-C8--8CNX.js +0 -1
  288. package/dist/web/assets/tsMode-uT3sMVHt.js +0 -11
  289. package/dist/web/assets/typescript-Dkdj2ks0.js +0 -1
  290. package/dist/web/assets/use-profiles-T3saKiBg.js +0 -1
  291. package/dist/web/assets/useTokenUsage-Drh3v3kx.js +0 -1
  292. package/dist/web/assets/xml-BO8gYu0L.js +0 -1
  293. package/dist/web/assets/yaml-DlovbQzw.js +0 -1
  294. /package/dist/web/assets/{EditableTaskTitle-DcpNTP1B.css → TaskHandoffPanel-DcpNTP1B.css} +0 -0
@@ -131,9 +131,11 @@ export declare class WorkspaceService {
131
131
  updatedAt: Date;
132
132
  title: string;
133
133
  deletedAt: Date | null;
134
+ handoff: string | null;
134
135
  baseBranch: string | null;
135
136
  position: number;
136
137
  projectId: string;
138
+ parentTaskId: string | null;
137
139
  };
138
140
  sessions: {
139
141
  agentType: string;
@@ -166,6 +168,7 @@ export declare class WorkspaceService {
166
168
  commitMessage: string | null;
167
169
  previewTarget: string | null;
168
170
  hibernatedAt: Date | null;
171
+ cleanedAt: Date | null;
169
172
  }) | null>;
170
173
  /**
171
174
  * 获取 Task 下所有 Workspace
@@ -202,6 +205,7 @@ export declare class WorkspaceService {
202
205
  commitMessage: string | null;
203
206
  previewTarget: string | null;
204
207
  hibernatedAt: Date | null;
208
+ cleanedAt: Date | null;
205
209
  })[]>;
206
210
  getSetupProgress(taskId: string): Promise<WorkspaceSetupProgressPayload[]>;
207
211
  listVerdicts(workspaceId: string): Promise<WorkspaceVerdict[]>;
@@ -261,9 +265,11 @@ export declare class WorkspaceService {
261
265
  updatedAt: Date;
262
266
  title: string;
263
267
  deletedAt: Date | null;
268
+ handoff: string | null;
264
269
  baseBranch: string | null;
265
270
  position: number;
266
271
  projectId: string;
272
+ parentTaskId: string | null;
267
273
  };
268
274
  sessions: {
269
275
  agentType: string;
@@ -296,6 +302,7 @@ export declare class WorkspaceService {
296
302
  commitMessage: string | null;
297
303
  previewTarget: string | null;
298
304
  hibernatedAt: Date | null;
305
+ cleanedAt: Date | null;
299
306
  }>;
300
307
  getOrCreateDedicatedWorkspace(teamRunId: string, memberId: string): Promise<{
301
308
  task: {
@@ -327,9 +334,11 @@ export declare class WorkspaceService {
327
334
  updatedAt: Date;
328
335
  title: string;
329
336
  deletedAt: Date | null;
337
+ handoff: string | null;
330
338
  baseBranch: string | null;
331
339
  position: number;
332
340
  projectId: string;
341
+ parentTaskId: string | null;
333
342
  };
334
343
  sessions: {
335
344
  agentType: string;
@@ -362,6 +371,7 @@ export declare class WorkspaceService {
362
371
  commitMessage: string | null;
363
372
  previewTarget: string | null;
364
373
  hibernatedAt: Date | null;
374
+ cleanedAt: Date | null;
365
375
  }>;
366
376
  private findOrCreateMainWorkspace;
367
377
  private findOrCreateDedicatedWorkspace;
@@ -373,12 +383,8 @@ export declare class WorkspaceService {
373
383
  private ensureActiveWorkspaceWorktree;
374
384
  private restoreInactiveWorkspace;
375
385
  /**
376
- * 删除 Workspace
377
- *
378
- * - 删除前检查是否有 RUNNING 状态的 Session,有则拒绝删除
379
- * - 删除时先停止所有关联 Session 的进程
380
- * - 删除时调用 WorktreeManager.remove 清理 worktree
381
- * - worktree 清理失败时仍然删除数据库记录(记录警告日志)
386
+ * 回收 Workspace 的运行资源,保留任务下的会话历史。
387
+ * 只有任务/项目硬删除才级联删除 Workspace 和 Session。
382
388
  */
383
389
  delete(id: string): Promise<boolean>;
384
390
  private deleteWithLifecycle;
@@ -446,9 +452,11 @@ export declare class WorkspaceService {
446
452
  updatedAt: Date;
447
453
  title: string;
448
454
  deletedAt: Date | null;
455
+ handoff: string | null;
449
456
  baseBranch: string | null;
450
457
  position: number;
451
458
  projectId: string;
459
+ parentTaskId: string | null;
452
460
  };
453
461
  sessions: {
454
462
  agentType: string;
@@ -497,6 +505,7 @@ export declare class WorkspaceService {
497
505
  commitMessage: string | null;
498
506
  previewTarget: string | null;
499
507
  hibernatedAt: Date | null;
508
+ cleanedAt: Date | null;
500
509
  }>;
501
510
  private archiveWithLifecycle;
502
511
  /**
@@ -538,9 +547,11 @@ export declare class WorkspaceService {
538
547
  updatedAt: Date;
539
548
  title: string;
540
549
  deletedAt: Date | null;
550
+ handoff: string | null;
541
551
  baseBranch: string | null;
542
552
  position: number;
543
553
  projectId: string;
554
+ parentTaskId: string | null;
544
555
  };
545
556
  sessions: {
546
557
  agentType: string;
@@ -573,6 +584,7 @@ export declare class WorkspaceService {
573
584
  commitMessage: string | null;
574
585
  previewTarget: string | null;
575
586
  hibernatedAt: Date | null;
587
+ cleanedAt: Date | null;
576
588
  }>;
577
589
  private cleanupCreatedWorktree;
578
590
  private cleanupRestoredWorktree;
@@ -591,11 +603,12 @@ export declare class WorkspaceService {
591
603
  */
592
604
  private autoCommitIfDirty;
593
605
  /**
594
- * 清理所有 ABANDONED/MERGED 状态且关联 Task 为 DONE 的 Workspace
606
+ * 回收已完成任务的 ABANDONED/MERGED Workspace 资源,保留会话历史。
595
607
  *
596
608
  * @returns 被清理的 Workspace 数量
597
609
  */
598
610
  cleanup(): Promise<number>;
611
+ private cleanupWorkspaceBranch;
599
612
  private assertWorktreeWorkspace;
600
613
  /**
601
614
  * 复制项目配置的文件到 worktree
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.service.d.ts","sourceRoot":"","sources":["../../src/services/workspace.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspace.service.d.ts","sourceRoot":"","sources":["../../src/services/workspace.service.ts"],"names":[],"mappings":"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"}
@@ -1013,6 +1013,7 @@ export class WorkspaceService {
1013
1013
  ownerMemberId: options.ownerMemberId,
1014
1014
  workspaceKind: WorkspaceKind.WORKTREE,
1015
1015
  status: { in: [WorkspaceStatus.MERGED, WorkspaceStatus.HIBERNATED] },
1016
+ cleanedAt: null,
1016
1017
  },
1017
1018
  orderBy: { updatedAt: 'desc' },
1018
1019
  });
@@ -1344,7 +1345,26 @@ export class WorkspaceService {
1344
1345
  if (workspace.status === WorkspaceStatus.HIBERNATED) {
1345
1346
  return this.restoreInactiveWorkspace(workspace);
1346
1347
  }
1347
- if (workspace.status === WorkspaceStatus.MERGED) {
1348
+ if (workspace.status === WorkspaceStatus.MERGED
1349
+ || (workspace.status === WorkspaceStatus.ABANDONED && workspace.cleanedAt)) {
1350
+ if (workspace.cleanedAt) {
1351
+ return defaultWorkspaceLifecycleBarrier.withWorkspaces([workspace.id, mainWorkspace.id], async () => {
1352
+ const current = await prisma.workspace.findUnique({
1353
+ where: { id: workspace.id }, include: { task: { include: { project: true } } },
1354
+ });
1355
+ if (!current)
1356
+ throw new NotFoundError('Workspace', workspace.id);
1357
+ ensureTaskNotDeleted(current.task);
1358
+ const activeMain = await prisma.workspace.findFirst({
1359
+ where: { id: mainWorkspace.id, status: WorkspaceStatus.ACTIVE, cleanedAt: null, task: { deletedAt: null } },
1360
+ });
1361
+ if (!activeMain)
1362
+ throw new ServiceError('TeamRun main workspace is no longer active', 'WORKSPACE_NOT_ACTIVE', 409);
1363
+ if (!current.cleanedAt)
1364
+ return this.activateDedicatedWorkspace(current, mainWorkspace);
1365
+ return this.resetMergedDedicatedWorkspace(current, mainWorkspace);
1366
+ });
1367
+ }
1348
1368
  return this.resetMergedDedicatedWorkspace(workspace, mainWorkspace);
1349
1369
  }
1350
1370
  throw new ServiceError(`Cannot reuse dedicated workspace in ${workspace.status} status`, 'DEDICATED_WORKSPACE_UNAVAILABLE', 409);
@@ -1353,41 +1373,61 @@ export class WorkspaceService {
1353
1373
  this.assertWorktreeWorkspace(workspace);
1354
1374
  this.assertWorktreeWorkspace(mainWorkspace);
1355
1375
  const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
1356
- const worktreePath = await worktreeManager.ensureWorktreeExists(workspace.branchName);
1357
- if (!(await worktreeManager.isWorktreeClean(worktreePath))) {
1358
- throw new ServiceError(`Cannot start new work from merged workspace ${workspace.id} because it has uncommitted changes`, 'MERGED_WORKSPACE_DIRTY', 409);
1359
- }
1360
- const mainHead = (await execGit(mainWorkspace.worktreePath, ['rev-parse', 'HEAD'])).trim();
1361
- await execGit(worktreePath, ['reset', '--hard', mainHead]);
1362
- const actualHead = (await execGit(worktreePath, ['rev-parse', 'HEAD'])).trim();
1363
- if (!mainHead || actualHead !== mainHead || !(await worktreeManager.isWorktreeClean(worktreePath))) {
1364
- throw new ServiceError(`Merged workspace ${workspace.id} could not be aligned to the TeamRun main workspace`, 'MERGED_WORKSPACE_RESET_FAILED', 500);
1376
+ // The retained record still occupies the member's unique workspace slot.
1377
+ // Rebuild its resources with a fresh branch; the previous name is no longer owned.
1378
+ const branchName = workspace.cleanedAt ? `${workspace.branchName}-${randomUUID().slice(0, 8)}` : workspace.branchName;
1379
+ const worktreePath = workspace.cleanedAt
1380
+ ? await worktreeManager.create(branchName, mainWorkspace.branchName)
1381
+ : await worktreeManager.ensureWorktreeExists(branchName);
1382
+ let resourcesBound = false;
1383
+ try {
1384
+ if (!(await worktreeManager.isWorktreeClean(worktreePath))) {
1385
+ throw new ServiceError(`Cannot start new work from merged workspace ${workspace.id} because it has uncommitted changes`, 'MERGED_WORKSPACE_DIRTY', 409);
1386
+ }
1387
+ const mainHead = (await execGit(mainWorkspace.worktreePath, ['rev-parse', 'HEAD'])).trim();
1388
+ await execGit(worktreePath, ['reset', '--hard', mainHead]);
1389
+ const actualHead = (await execGit(worktreePath, ['rev-parse', 'HEAD'])).trim();
1390
+ if (!mainHead || actualHead !== mainHead || !(await worktreeManager.isWorktreeClean(worktreePath))) {
1391
+ throw new ServiceError(`Merged workspace ${workspace.id} could not be aligned to the TeamRun main workspace`, 'MERGED_WORKSPACE_RESET_FAILED', 500);
1392
+ }
1393
+ const updateResult = await prisma.workspace.updateMany({
1394
+ where: {
1395
+ id: workspace.id,
1396
+ status: workspace.status,
1397
+ cleanedAt: workspace.cleanedAt,
1398
+ task: { deletedAt: null },
1399
+ },
1400
+ data: {
1401
+ status: WorkspaceStatus.ACTIVE,
1402
+ branchName,
1403
+ baseBranch: mainWorkspace.branchName,
1404
+ worktreePath,
1405
+ workingDir: worktreePath,
1406
+ hibernatedAt: null,
1407
+ commitMessage: null,
1408
+ cleanedAt: null,
1409
+ },
1410
+ });
1411
+ if (updateResult.count !== 1) {
1412
+ throw new ServiceError(`Merged workspace ${workspace.id} changed state while starting new work`, 'MERGED_WORKSPACE_STATE_CHANGED', 409);
1413
+ }
1414
+ resourcesBound = true;
1415
+ this.runCopyFiles(workspace.task.project.repoPath, worktreePath, workspace.task.project.copyFiles);
1416
+ this.fireSetupScript(workspace.id, workspace.taskId, worktreePath, workspace.task.project.setupScript);
1417
+ const activated = await prisma.workspace.findUniqueOrThrow({
1418
+ where: { id: workspace.id },
1419
+ include: { sessions: visibleSessionsFilter, task: { include: { project: true } } },
1420
+ });
1421
+ return activated;
1365
1422
  }
1366
- const updateResult = await prisma.workspace.updateMany({
1367
- where: {
1368
- id: workspace.id,
1369
- status: WorkspaceStatus.MERGED,
1370
- task: { deletedAt: null },
1371
- },
1372
- data: {
1373
- status: WorkspaceStatus.ACTIVE,
1374
- baseBranch: mainWorkspace.branchName,
1375
- worktreePath,
1376
- workingDir: worktreePath,
1377
- hibernatedAt: null,
1378
- commitMessage: null,
1379
- },
1380
- });
1381
- if (updateResult.count !== 1) {
1382
- throw new ServiceError(`Merged workspace ${workspace.id} changed state while starting new work`, 'MERGED_WORKSPACE_STATE_CHANGED', 409);
1423
+ catch (error) {
1424
+ if (workspace.cleanedAt && !resourcesBound) {
1425
+ await this.cleanupCreatedWorktree(worktreeManager, worktreePath, branchName, [
1426
+ workspace.task.project.mainBranch, mainWorkspace.branchName,
1427
+ ]);
1428
+ }
1429
+ throw error;
1383
1430
  }
1384
- this.runCopyFiles(workspace.task.project.repoPath, worktreePath, workspace.task.project.copyFiles);
1385
- this.fireSetupScript(workspace.id, workspace.taskId, worktreePath, workspace.task.project.setupScript);
1386
- const activated = await prisma.workspace.findUniqueOrThrow({
1387
- where: { id: workspace.id },
1388
- include: { sessions: visibleSessionsFilter, task: { include: { project: true } } },
1389
- });
1390
- return activated;
1391
1431
  }
1392
1432
  async waitForWorkspaceReady(workspace) {
1393
1433
  if (workspace.branchName) {
@@ -1457,12 +1497,8 @@ export class WorkspaceService {
1457
1497
  }
1458
1498
  // ── Delete ───────────────────────────────────────────────────────────────────
1459
1499
  /**
1460
- * 删除 Workspace
1461
- *
1462
- * - 删除前检查是否有 RUNNING 状态的 Session,有则拒绝删除
1463
- * - 删除时先停止所有关联 Session 的进程
1464
- * - 删除时调用 WorktreeManager.remove 清理 worktree
1465
- * - worktree 清理失败时仍然删除数据库记录(记录警告日志)
1500
+ * 回收 Workspace 的运行资源,保留任务下的会话历史。
1501
+ * 只有任务/项目硬删除才级联删除 Workspace 和 Session。
1466
1502
  */
1467
1503
  async delete(id) {
1468
1504
  return withSessionResourceCleanup({ workspaceId: id }, () => (defaultWorkspaceLifecycleBarrier.withWorkspace(id, () => this.deleteWithLifecycle(id))));
@@ -1479,25 +1515,44 @@ export class WorkspaceService {
1479
1515
  throw new NotFoundError('Workspace', id);
1480
1516
  }
1481
1517
  ensureProjectIsMutable(workspace.task.project, 'delete workspaces');
1518
+ ensureTaskNotDeleted(workspace.task);
1519
+ if (workspace.cleanedAt)
1520
+ return true;
1482
1521
  // A completed ACP turn may still own a reusable adapter process.
1483
1522
  for (const session of workspace.sessions) {
1484
1523
  await stopSessionForResourceCleanup(this.sessionService, session.id);
1485
1524
  }
1486
1525
  await this.backgroundService.stopAllForWorkspace(id);
1487
- if (isWorktreeWorkspace(workspace) && workspace.worktreePath) {
1488
- // 清理 worktree
1489
- try {
1490
- const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
1491
- await worktreeManager.remove(workspace.worktreePath);
1492
- }
1493
- catch (err) {
1494
- // worktree 清理失败时记录警告但不阻断删除
1495
- console.warn(`[WorkspaceService] Failed to remove worktree for workspace ${id}: ${err instanceof Error ? err.message : err}`);
1526
+ const worktreeManager = isWorktreeWorkspace(workspace)
1527
+ ? new WorktreeManager(workspace.task.project.repoPath) : null;
1528
+ if (worktreeManager && workspace.worktreePath) {
1529
+ const result = await worktreeManager.remove(workspace.worktreePath);
1530
+ if (result.status === 'unregistered') {
1531
+ throw new ServiceError('Workspace directory could not be safely removed', 'WORKSPACE_CLEANUP_PENDING', 409);
1496
1532
  }
1497
1533
  }
1498
- // 删除数据库记录(级联删除 sessions/services)
1499
1534
  await this.backgroundService.releaseLogsForWorkspace?.(id);
1500
- await prisma.workspace.delete({ where: { id } });
1535
+ await prisma.workspace.update({
1536
+ where: { id },
1537
+ data: {
1538
+ status: workspace.status === WorkspaceStatus.MERGED ? WorkspaceStatus.MERGED : WorkspaceStatus.ABANDONED,
1539
+ worktreePath: '',
1540
+ workingDir: '',
1541
+ previewTarget: null,
1542
+ hibernatedAt: null,
1543
+ },
1544
+ });
1545
+ try {
1546
+ // Preserve branch ownership for retry if another task still needs it.
1547
+ if (!worktreeManager || await this.cleanupWorkspaceBranch(workspace, worktreeManager)) {
1548
+ await prisma.workspace.update({ where: { id }, data: { cleanedAt: new Date() } });
1549
+ }
1550
+ }
1551
+ finally {
1552
+ this.eventBus.emit('task:updated', {
1553
+ taskId: workspace.taskId, projectId: workspace.task.projectId, status: workspace.task.status,
1554
+ });
1555
+ }
1501
1556
  return true;
1502
1557
  }
1503
1558
  // ── Diff ─────────────────────────────────────────────────────────────────────
@@ -1597,7 +1652,18 @@ export class WorkspaceService {
1597
1652
  await worktreeManager.abortOperation(workspace.worktreePath);
1598
1653
  }
1599
1654
  async merge(id, commitMessageOrOptions) {
1600
- return defaultWorkspaceLifecycleBarrier.withWorkspace(id, async () => {
1655
+ const source = await prisma.workspace.findUnique({ where: { id }, include: { task: true } });
1656
+ if (!source || source.task.deletedAt)
1657
+ throw new NotFoundError('Workspace', id);
1658
+ const target = source.parentWorkspaceId || !source.baseBranch ? null : await prisma.workspace.findFirst({
1659
+ where: {
1660
+ id: { not: id }, branchName: source.baseBranch, status: WorkspaceStatus.ACTIVE,
1661
+ parentWorkspaceId: null, workspaceKind: WorkspaceKind.WORKTREE,
1662
+ task: { projectId: source.task.projectId, deletedAt: null },
1663
+ },
1664
+ include: { task: { include: { project: true } } },
1665
+ });
1666
+ return defaultWorkspaceLifecycleBarrier.withWorkspaces([id, ...(target ? [target.id] : [])], async () => {
1601
1667
  const options = typeof commitMessageOrOptions === 'string'
1602
1668
  ? { commitMessage: commitMessageOrOptions }
1603
1669
  : (commitMessageOrOptions ?? {});
@@ -1605,18 +1671,32 @@ export class WorkspaceService {
1605
1671
  where: { id },
1606
1672
  include: { task: { include: { project: true, teamRun: true } } },
1607
1673
  });
1608
- if (!workspace) {
1674
+ if (!workspace || workspace.task.deletedAt) {
1609
1675
  throw new NotFoundError('Workspace', id);
1610
1676
  }
1677
+ if (workspace.baseBranch !== source.baseBranch) {
1678
+ throw new ServiceError('Merge target changed. Refresh before merging.', 'MERGE_TARGET_CHANGED', 409);
1679
+ }
1680
+ const currentTarget = target ? await prisma.workspace.findUnique({
1681
+ where: { id: target.id }, include: { task: { include: { project: true } } },
1682
+ }) : null;
1683
+ if (target && (!currentTarget || currentTarget.task.deletedAt || currentTarget.status !== WorkspaceStatus.ACTIVE
1684
+ || currentTarget.branchName !== workspace.baseBranch)) {
1685
+ throw new ServiceError('Merge target changed. Refresh before merging.', 'MERGE_TARGET_CHANGED', 409);
1686
+ }
1687
+ if (currentTarget) {
1688
+ await this.assertNoActiveWriteSessions(currentTarget.id);
1689
+ await this.assertNoActiveBackgroundServices(currentTarget.id);
1690
+ }
1611
1691
  ensureProjectIsMutable(workspace.task.project, 'merge workspaces');
1612
1692
  this.assertWorktreeWorkspace(workspace);
1613
1693
  if (!options.stopActiveServices) {
1614
1694
  await this.assertNoActiveBackgroundServices(workspace.id);
1615
1695
  }
1616
- return this.withMergeTargetLock(this.getMergeLockTarget(workspace), options.lockOwnerId, () => this.mergeWithLock(workspace, options));
1696
+ return this.withMergeTargetLock(currentTarget ? this.getParentWorkspaceMergeLockTarget(currentTarget.id) : this.getMergeLockTarget(workspace), options.lockOwnerId, () => this.mergeWithLock(workspace, options, currentTarget));
1617
1697
  });
1618
1698
  }
1619
- async mergeWithLock(workspace, options) {
1699
+ async mergeWithLock(workspace, options, targetWorkspace = null) {
1620
1700
  if (this.isTeamRunDedicatedChildWorkspace(workspace) && workspace.status === WorkspaceStatus.MERGED) {
1621
1701
  if (!workspace.worktreePath) {
1622
1702
  return '';
@@ -1645,7 +1725,7 @@ export class WorkspaceService {
1645
1725
  if (parentWorkspace) {
1646
1726
  return this.mergeChildIntoParent(workspace, parentWorkspace, options.commitMessage);
1647
1727
  }
1648
- return this.mergeRootWorkspaceToMain(workspace, options.commitMessage);
1728
+ return this.mergeRootWorkspaceToMain(workspace, options.commitMessage, targetWorkspace);
1649
1729
  }
1650
1730
  isTeamRunDedicatedChildWorkspace(workspace) {
1651
1731
  return Boolean(workspace.task.teamRun
@@ -1774,17 +1854,22 @@ export class WorkspaceService {
1774
1854
  });
1775
1855
  return sha;
1776
1856
  }
1777
- async mergeRootWorkspaceToMain(workspace, commitMessage) {
1857
+ async mergeRootWorkspaceToMain(workspace, commitMessage, targetWorkspace = null) {
1778
1858
  this.assertWorktreeWorkspace(workspace);
1779
1859
  const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
1780
1860
  let sha;
1781
1861
  const targetBranch = this.getBaseBranch(workspace);
1782
1862
  try {
1783
- ({ sha } = await worktreeManager.merge(workspace.worktreePath, targetBranch, { commitMessage: commitMessage || workspace.commitMessage || undefined }));
1863
+ ({ sha } = await worktreeManager.merge(workspace.worktreePath, targetBranch, { commitMessage: commitMessage || workspace.commitMessage || undefined,
1864
+ ...(targetWorkspace ? { targetWorktreePath: targetWorkspace.worktreePath }
1865
+ : workspace.task.parentTaskId ? { restoreOriginalBranch: true } : {}),
1866
+ }));
1784
1867
  }
1785
1868
  catch (error) {
1786
1869
  if (error instanceof MergeConflictError) {
1787
1870
  error.sourceWorkspaceId = workspace.id;
1871
+ if (targetWorkspace)
1872
+ error.targetWorkspaceId = targetWorkspace.id;
1788
1873
  error.sourceWorktreePath ??= workspace.worktreePath;
1789
1874
  error.sourceBranch ??= workspace.branchName;
1790
1875
  error.targetBranch ??= targetBranch;
@@ -2124,7 +2209,7 @@ export class WorkspaceService {
2124
2209
  }
2125
2210
  // ── Cleanup ──────────────────────────────────────────────────────────────────
2126
2211
  /**
2127
- * 清理所有 ABANDONED/MERGED 状态且关联 Task 为 DONE 的 Workspace
2212
+ * 回收已完成任务的 ABANDONED/MERGED Workspace 资源,保留会话历史。
2128
2213
  *
2129
2214
  * @returns 被清理的 Workspace 数量
2130
2215
  */
@@ -2132,56 +2217,86 @@ export class WorkspaceService {
2132
2217
  const workspaces = await prisma.workspace.findMany({
2133
2218
  where: {
2134
2219
  status: { in: [WorkspaceStatus.ABANDONED, WorkspaceStatus.MERGED] },
2135
- task: { status: TaskStatus.DONE },
2220
+ cleanedAt: null,
2221
+ task: { status: TaskStatus.DONE, deletedAt: null },
2136
2222
  },
2137
- include: { task: { include: { project: true } } },
2223
+ select: { id: true },
2138
2224
  });
2139
2225
  let cleaned = 0;
2140
- for (const workspace of workspaces) {
2226
+ for (const candidate of workspaces) {
2141
2227
  try {
2142
- await withSessionResourceCleanup({ workspaceId: workspace.id }, () => (defaultWorkspaceLifecycleBarrier.withWorkspace(workspace.id, async () => {
2228
+ await withSessionResourceCleanup({ workspaceId: candidate.id }, () => (defaultWorkspaceLifecycleBarrier.withWorkspace(candidate.id, async () => {
2229
+ // Recheck after acquiring the lifecycle lock: another cleanup or
2230
+ // reactivation may have already consumed this candidate.
2231
+ const workspace = await prisma.workspace.findFirst({
2232
+ where: {
2233
+ id: candidate.id, cleanedAt: null,
2234
+ status: { in: [WorkspaceStatus.ABANDONED, WorkspaceStatus.MERGED] },
2235
+ task: { status: TaskStatus.DONE, deletedAt: null },
2236
+ },
2237
+ include: { task: { include: { project: true } } },
2238
+ });
2239
+ if (!workspace)
2240
+ return;
2143
2241
  const sessions = await prisma.session.findMany({ where: { workspaceId: workspace.id }, select: { id: true } });
2144
2242
  for (const session of sessions) {
2145
2243
  await stopSessionForResourceCleanup(this.sessionService, session.id);
2146
2244
  }
2147
2245
  await this.backgroundService.stopAllForWorkspace(workspace.id);
2148
- if (isMainDirectoryWorkspace(workspace)) {
2149
- await this.backgroundService.releaseLogsForWorkspace?.(workspace.id);
2150
- await prisma.workspace.delete({ where: { id: workspace.id } });
2151
- cleaned++;
2152
- return;
2153
- }
2154
- const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
2246
+ const worktreeManager = isWorktreeWorkspace(workspace)
2247
+ ? new WorktreeManager(workspace.task.project.repoPath) : null;
2155
2248
  // 清理残留 worktree(如果还存在)
2156
- if (workspace.worktreePath) {
2249
+ if (worktreeManager && workspace.worktreePath) {
2157
2250
  const removeResult = await worktreeManager.remove(workspace.worktreePath);
2158
2251
  if (removeResult.status === 'unregistered') {
2159
2252
  console.warn(`[WorkspaceService] cleanup: workspace ${workspace.id} path is unregistered or unsafe to remove: ${removeResult.path}`);
2160
2253
  return;
2161
2254
  }
2162
2255
  }
2163
- // Task 已 DONE,branch 不再需要,删除。安全 helper 会跳过 base/main/master/current/missing。
2164
- const branchDeleteResult = await worktreeManager.deleteBranchIfSafe(workspace.branchName, {
2165
- protectedBranches: [workspace.task.project.mainBranch, workspace.baseBranch],
2256
+ // Clear live paths even when branch reclamation needs a later retry.
2257
+ // MAIN_DIRECTORY releases its binding without removing project files.
2258
+ await this.backgroundService.releaseLogsForWorkspace?.(workspace.id);
2259
+ await prisma.workspace.update({
2260
+ where: { id: workspace.id },
2261
+ data: { worktreePath: '', workingDir: '', previewTarget: null },
2166
2262
  });
2167
- if (branchDeleteResult.status === 'failed') {
2168
- console.warn(`[WorkspaceService] cleanup: failed to delete branch ${branchDeleteResult.branchName} for workspace ${workspace.id}: ${branchDeleteResult.reason}`);
2263
+ const cleanupComplete = !worktreeManager || await this.cleanupWorkspaceBranch(workspace, worktreeManager);
2264
+ if (cleanupComplete) {
2265
+ await prisma.workspace.update({ where: { id: workspace.id }, data: { cleanedAt: new Date() } });
2169
2266
  }
2170
- else if (branchDeleteResult.status === 'checked_out') {
2171
- console.warn(`[WorkspaceService] cleanup: skipped checked-out branch ${branchDeleteResult.branchName} for workspace ${workspace.id}: ${branchDeleteResult.reason}`);
2267
+ if (cleanupComplete || getWorkspaceWorkingDir(workspace)) {
2268
+ cleaned++;
2269
+ this.eventBus.emit('task:updated', {
2270
+ taskId: workspace.taskId, projectId: workspace.task.projectId, status: workspace.task.status,
2271
+ });
2172
2272
  }
2173
- await this.backgroundService.releaseLogsForWorkspace?.(workspace.id);
2174
- await prisma.workspace.delete({ where: { id: workspace.id } });
2175
- cleaned++;
2176
2273
  })));
2177
2274
  }
2178
2275
  catch (err) {
2179
2276
  // Keep process evidence and directory resources for a later retry.
2180
- console.warn(`[WorkspaceService] cleanup: failed for workspace ${workspace.id}: ${err instanceof Error ? err.message : err}`);
2277
+ console.warn(`[WorkspaceService] cleanup: failed for workspace ${candidate.id}: ${err instanceof Error ? err.message : err}`);
2181
2278
  }
2182
2279
  }
2183
2280
  return cleaned;
2184
2281
  }
2282
+ async cleanupWorkspaceBranch(workspace, worktreeManager) {
2283
+ const referencedByTask = await prisma.task.findFirst({
2284
+ where: { projectId: workspace.task.projectId, id: { not: workspace.taskId }, deletedAt: null, OR: [
2285
+ { baseBranch: workspace.branchName },
2286
+ { workspaces: { some: { baseBranch: workspace.branchName, cleanedAt: null } } },
2287
+ ] }, select: { id: true },
2288
+ });
2289
+ if (referencedByTask)
2290
+ return false;
2291
+ const result = await worktreeManager.deleteBranchIfSafe(workspace.branchName, {
2292
+ protectedBranches: [workspace.task.project.mainBranch, workspace.baseBranch],
2293
+ });
2294
+ if (result.status === 'failed' || result.status === 'checked_out') {
2295
+ console.warn(`[WorkspaceService] cleanup: branch ${result.branchName} retained for workspace ${workspace.id}: ${result.reason}`);
2296
+ return false;
2297
+ }
2298
+ return true;
2299
+ }
2185
2300
  // ── Startup Prune ────────────────────────────────────────────────────────────
2186
2301
  assertWorktreeWorkspace(workspace) {
2187
2302
  if (isWorktreeWorkspace(workspace))