agent-tower 0.7.4-beta.0 → 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.
- package/dist/mcp/tools/tasks.js +2 -2
- package/dist/mcp/tools/tasks.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/prompts/task-handoff.d.ts.map +1 -1
- package/dist/prompts/task-handoff.js +2 -1
- package/dist/prompts/task-handoff.js.map +1 -1
- package/dist/routes/__tests__/sessions-runtime.test.js +2 -0
- package/dist/routes/__tests__/sessions-runtime.test.js.map +1 -1
- package/dist/routes/__tests__/tasks.test.js +41 -0
- package/dist/routes/__tests__/tasks.test.js.map +1 -1
- package/dist/routes/__tests__/workspace-history.test.d.ts +2 -0
- package/dist/routes/__tests__/workspace-history.test.d.ts.map +1 -0
- package/dist/routes/__tests__/workspace-history.test.js +174 -0
- package/dist/routes/__tests__/workspace-history.test.js.map +1 -0
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +10 -0
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/tasks.d.ts.map +1 -1
- package/dist/routes/tasks.js +8 -0
- package/dist/routes/tasks.js.map +1 -1
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.js +84 -0
- package/dist/runtime/__tests__/cli-driver-lifecycle.test.js.map +1 -1
- package/dist/runtime/cli-driver.js +11 -8
- package/dist/runtime/cli-driver.js.map +1 -1
- package/dist/services/__tests__/task.service.test.js +63 -10
- package/dist/services/__tests__/task.service.test.js.map +1 -1
- package/dist/services/__tests__/workspace.service.test.js +64 -5
- package/dist/services/__tests__/workspace.service.test.js.map +1 -1
- package/dist/services/message-delivery.service.d.ts +1 -0
- package/dist/services/message-delivery.service.d.ts.map +1 -1
- package/dist/services/session-manager.d.ts +4 -0
- package/dist/services/session-manager.d.ts.map +1 -1
- package/dist/services/session-manager.js +3 -1
- package/dist/services/session-manager.js.map +1 -1
- package/dist/services/session-resource-cleanup.d.ts +5 -0
- package/dist/services/session-resource-cleanup.d.ts.map +1 -1
- package/dist/services/session-resource-cleanup.js +7 -0
- package/dist/services/session-resource-cleanup.js.map +1 -1
- package/dist/services/task-cleanup.service.d.ts +2 -0
- package/dist/services/task-cleanup.service.d.ts.map +1 -1
- package/dist/services/task-cleanup.service.js +4 -0
- package/dist/services/task-cleanup.service.js.map +1 -1
- package/dist/services/task.service.d.ts +12 -1
- package/dist/services/task.service.d.ts.map +1 -1
- package/dist/services/task.service.js +67 -21
- package/dist/services/task.service.js.map +1 -1
- package/dist/services/workspace.service.d.ts +10 -7
- package/dist/services/workspace.service.d.ts.map +1 -1
- package/dist/services/workspace.service.js +160 -88
- package/dist/services/workspace.service.js.map +1 -1
- package/dist/web/assets/{AgentDemoPage-JXetlNBf.js → AgentDemoPage-DiHEh1iv.js} +1 -1
- package/dist/web/assets/{AgentEnvironmentSettingsPage-CdYyUCwJ.js → AgentEnvironmentSettingsPage-B_Xk7Bef.js} +1 -1
- package/dist/web/assets/{AttachmentPreview-DMS-PM-1.js → AttachmentPreview-BngGSahV.js} +2 -2
- package/dist/web/assets/{BranchSelect-BAq4L2ZS.js → BranchSelect-BgVKUnxj.js} +1 -1
- package/dist/web/assets/{BrandLogo--kWXXJtZ.js → BrandLogo-CBahjTd7.js} +1 -1
- package/dist/web/assets/{ConversationPage-CvC4RyB5.js → ConversationPage-kgJIlyS5.js} +1 -1
- package/dist/web/assets/{CreateTaskInput-DjVxCAfc.js → CreateTaskInput-Cllw4abW.js} +1 -1
- package/dist/web/assets/{DemoPage-cDVTGOp8.js → DemoPage-CkS__9CE.js} +1 -1
- package/dist/web/assets/{DesignSystemPage-BI54IkKi.js → DesignSystemPage-BklN99GA.js} +1 -1
- package/dist/web/assets/{ExecutionPermissionSelector-f1UYIm1z.js → ExecutionPermissionSelector-Bsi1aa7q.js} +1 -1
- package/dist/web/assets/{GeneralSettingsPage-C0yto6C_.js → GeneralSettingsPage-BC9TUWiu.js} +1 -1
- package/dist/web/assets/{LoadingPreviewPage-BiJSaHUi.js → LoadingPreviewPage-Dx8Si6-g.js} +1 -1
- package/dist/web/assets/{McpSettingsPage-BbHwZtyj.js → McpSettingsPage-fqXRGtFu.js} +1 -1
- package/dist/web/assets/{MemberAvatar-BLezO3vS.js → MemberAvatar-CZ3F53Ep.js} +1 -1
- package/dist/web/assets/MobileTaskDetail-B68iYPOI.js +3 -0
- package/dist/web/assets/{NotificationSettingsPage-CiKoL2Kv.js → NotificationSettingsPage-D9KGIFVA.js} +1 -1
- package/dist/web/assets/{ProfileSettingsPage-DCB48cPS.js → ProfileSettingsPage-D_Hw5lpd.js} +1 -1
- package/dist/web/assets/ProjectKanbanPage-CUX0Kh-t.js +12 -0
- package/dist/web/assets/{ProjectSettingsPage-COvIVq1h.js → ProjectSettingsPage-CJANCPJX.js} +1 -1
- package/dist/web/assets/{ProviderSettingsPage-CPuJcZDg.js → ProviderSettingsPage-B6Ro5PQa.js} +2 -2
- package/dist/web/assets/{SettingsMasterDetail-Cv7YaRJB.js → SettingsMasterDetail-Q-049Dvh.js} +1 -1
- package/dist/web/assets/TaskDetail-DBtWf0YV.js +1 -0
- package/dist/web/assets/{TaskHandoffPanel-CxH3Mgyd.js → TaskHandoffPanel-BpGiZ5eT.js} +20 -20
- package/dist/web/assets/{TeamSettingsPage-D-XDefNd.js → TeamSettingsPage-DbKgqEO_.js} +1 -1
- package/dist/web/assets/{TranslationSettingsPage-BPHI-SZW.js → TranslationSettingsPage-Ba-iypOV.js} +1 -1
- package/dist/web/assets/{arc-CC81aLuf.js → arc-SOqs3Svk.js} +1 -1
- package/dist/web/assets/{architectureDiagram-3BPJPVTR-DL08XGaN.js → architectureDiagram-3BPJPVTR-BH25ukq_.js} +1 -1
- package/dist/web/assets/{at-sign-DYPIlD6D.js → at-sign-CEsum1vJ.js} +1 -1
- package/dist/web/assets/{blockDiagram-GPEHLZMM-B4IW5WxI.js → blockDiagram-GPEHLZMM-CKA17iNP.js} +1 -1
- package/dist/web/assets/{c4Diagram-AAUBKEIU-Cj4d_FqK.js → c4Diagram-AAUBKEIU-DnZ_8oOf.js} +1 -1
- package/dist/web/assets/channel-xU45IQlP.js +1 -0
- package/dist/web/assets/check-DUA2DjGH.js +1 -0
- package/dist/web/assets/{chevron-down-DNhYsNAt.js → chevron-down-Bmwy-nvS.js} +1 -1
- package/dist/web/assets/{chevron-up-CjrLieBR.js → chevron-up-CClL6-SF.js} +1 -1
- package/dist/web/assets/{chip-Cf92J-pQ.js → chip-BSMT2uT1.js} +1 -1
- package/dist/web/assets/{chunk-2J33WTMH-DeCj8QSD.js → chunk-2J33WTMH-BrtUyBDF.js} +1 -1
- package/dist/web/assets/{chunk-4BX2VUAB-k-6rzQmQ.js → chunk-4BX2VUAB-DZDNetDC.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-qMTCQ5bX.js → chunk-55IACEB6-xVa3bJqv.js} +1 -1
- package/dist/web/assets/{chunk-727SXJPM-CMnu18d1.js → chunk-727SXJPM-B7n9vxY4.js} +1 -1
- package/dist/web/assets/{chunk-AQP2D5EJ-C0mFbUMn.js → chunk-AQP2D5EJ-DQd4G76y.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-u6-_M137.js → chunk-FMBD7UC4-CXyP08kl.js} +1 -1
- package/dist/web/assets/{chunk-ND2GUHAM-DHrIE_8H.js → chunk-ND2GUHAM-BtnIS-HK.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-aTyC0wZq.js → chunk-QZHKN3VN-D4D-V_ex.js} +1 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-pvRulc6s.js +1 -0
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-pvRulc6s.js +1 -0
- package/dist/web/assets/{code-block-OCS4YCEC-CBIOQOMH.js → code-block-OCS4YCEC-DfERo9L1.js} +1 -1
- package/dist/web/assets/{confirm-dialog-DWeBZLJW.js → confirm-dialog-8ItnHBi0.js} +1 -1
- package/dist/web/assets/{content-JM9E1MeD.js → content-DrW8KnXu.js} +2 -2
- package/dist/web/assets/{copy-D0gl9kF8.js → copy-prrQrInw.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-xLyliSgU.js → cose-bilkent-S5V4N54A-CXdH8Idq.js} +1 -1
- package/dist/web/assets/{cssMode-DO5UnQ64.js → cssMode-CJ6_f10q.js} +1 -1
- package/dist/web/assets/{dagre-BM42HDAG-CbNpoO2d.js → dagre-BM42HDAG-XZydDwXe.js} +1 -1
- package/dist/web/assets/{diagram-2AECGRRQ-CG3hKxAX.js → diagram-2AECGRRQ-CofEe0Fr.js} +1 -1
- package/dist/web/assets/{diagram-5GNKFQAL-mQu9M28s.js → diagram-5GNKFQAL-BbTtW5WH.js} +1 -1
- package/dist/web/assets/{diagram-KO2AKTUF-BSeEp_Uw.js → diagram-KO2AKTUF-BJHZXpUM.js} +1 -1
- package/dist/web/assets/{diagram-LMA3HP47-D6yRdao-.js → diagram-LMA3HP47-DN7A27YU.js} +1 -1
- package/dist/web/assets/{diagram-OG6HWLK6-BUBUW9wD.js → diagram-OG6HWLK6-4IdYadiw.js} +1 -1
- package/dist/web/assets/{dialog-D1lkhqVL.js → dialog-BUsI4h2U.js} +1 -1
- package/dist/web/assets/{erDiagram-TEJ5UH35-BQSZgRqq.js → erDiagram-TEJ5UH35-BFijhCWv.js} +1 -1
- package/dist/web/assets/{file-BijjwxRR.js → file-C6QMUr5_.js} +1 -1
- package/dist/web/assets/{flowDiagram-I6XJVG4X-D-eqyr5Y.js → flowDiagram-I6XJVG4X-D9MxC-El.js} +1 -1
- package/dist/web/assets/{folder-picker-Czxm0_S9.js → folder-picker-CBdw-4v3.js} +1 -1
- package/dist/web/assets/{freemarker2-B4RvEa_U.js → freemarker2-CJVobC22.js} +1 -1
- package/dist/web/assets/{ganttDiagram-6RSMTGT7-BWGkCt_x.js → ganttDiagram-6RSMTGT7-BijCAyPQ.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PVQCEYII-DGVc49pR.js → gitGraphDiagram-PVQCEYII-AvI5QqxQ.js} +1 -1
- package/dist/web/assets/{globe-Ce01-45x.js → globe-BOfcTsvL.js} +1 -1
- package/dist/web/assets/{handlebars-oyT7drqS.js → handlebars-DTqWmI25.js} +1 -1
- package/dist/web/assets/{html-CxxWf2Qk.js → html-Bx7L8DX_.js} +1 -1
- package/dist/web/assets/{htmlMode-RfAHh5Jj.js → htmlMode-D_S0NjZc.js} +1 -1
- package/dist/web/assets/{index-Disv1kQS.js → index-BClyhWqz.js} +1 -1
- package/dist/web/assets/index-BDON669P.css +1 -0
- package/dist/web/assets/{index-DWrSDMX2.js → index-BFcDmhr0.js} +1 -1
- package/dist/web/assets/index-BRu1Yhrx.js +122 -0
- package/dist/web/assets/{index-hpHE1jXY.js → index-Bg8TlDo_.js} +1 -1
- package/dist/web/assets/{index-DyJfPc4O.js → index-COigMgrJ.js} +1 -1
- package/dist/web/assets/{index-Pt4TsHjm.js → index-Cdmj8aPv.js} +1 -1
- package/dist/web/assets/{index-BMZFF1UJ.js → index-CtOu4p9B.js} +1 -1
- package/dist/web/assets/{index-Dh-tgeaL.js → index-DUmVscrR.js} +4 -4
- package/dist/web/assets/{index-T38iVLEb.js → index-JXcQeorP.js} +1 -1
- package/dist/web/assets/{infoDiagram-5YYISTIA-DLPs3dV_.js → infoDiagram-5YYISTIA-76JLqjJ0.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-d_OrnwDY.js → ishikawaDiagram-YF4QCWOH-CXHFTVly.js} +1 -1
- package/dist/web/assets/javascript-80FDzX3y.js +1 -0
- package/dist/web/assets/{journeyDiagram-JHISSGLW-EtU1st_0.js → journeyDiagram-JHISSGLW-6SDJs9C5.js} +1 -1
- package/dist/web/assets/{jsonMode-Bqh5vIxx.js → jsonMode-BGg9MhFR.js} +1 -1
- package/dist/web/assets/{kanban-definition-UN3LZRKU-ZWzUnsFK.js → kanban-definition-UN3LZRKU-C0Y3zy1P.js} +1 -1
- package/dist/web/assets/{kbd-IjDGsZ2B.js → kbd-D4KIW7lm.js} +1 -1
- package/dist/web/assets/{key-round-CbnAuUxp.js → key-round-C4vhwqUu.js} +1 -1
- package/dist/web/assets/{layers-Pdy9vZ6K.js → layers-BBHgMnhN.js} +1 -1
- package/dist/web/assets/{linear-D7n23wcA.js → linear-CjeIgBwO.js} +1 -1
- package/dist/web/assets/{link-Bl1ZbjFh.js → link-C-Jq7dnc.js} +1 -1
- package/dist/web/assets/{liquid-Ds47iVLN.js → liquid-guocpCJB.js} +1 -1
- package/dist/web/assets/{lspLanguageFeatures-Dcch3bsp.js → lspLanguageFeatures-CPXERxVW.js} +1 -1
- package/dist/web/assets/{mdx-CM7ky-2B.js → mdx-DA4ymd3l.js} +1 -1
- package/dist/web/assets/{menu-DubntFHq.js → menu-BgtmXAzT.js} +1 -1
- package/dist/web/assets/{mermaid-NOHMQCX5-nBsnjgeU.js → mermaid-NOHMQCX5-XQbfQDGS.js} +4 -4
- package/dist/web/assets/{message-square-BE-pW0m_.js → message-square-DIFv9yrO.js} +1 -1
- package/dist/web/assets/{mindmap-definition-RKZ34NQL-ClHORNTt.js → mindmap-definition-RKZ34NQL-6ucD61UV.js} +1 -1
- package/dist/web/assets/{modal-CHLtZWvx.js → modal-Dx4N46s5.js} +1 -1
- package/dist/web/assets/{monaco-BbAmalE2.js → monaco-Mn1xgio_.js} +3 -3
- package/dist/web/assets/{nav-row-DH7rNq1V.js → nav-row-DwEkbw3N.js} +1 -1
- package/dist/web/assets/{paperclip-YP3Bk1lI.js → paperclip-CdQvl5ee.js} +1 -1
- package/dist/web/assets/{pencil-BFDuhbtW.js → pencil-ChX7G9j9.js} +1 -1
- package/dist/web/assets/{people-DEeNaaLt.js → people-D_VwidfV.js} +1 -1
- package/dist/web/assets/{pieDiagram-4H26LBE5-BUOaKIyP.js → pieDiagram-4H26LBE5-KVvAyrIn.js} +1 -1
- package/dist/web/assets/{popover-CUmBEXxL.js → popover-CGEFZKuu.js} +1 -1
- package/dist/web/assets/{python-BODTtU6m.js → python-BzNNRn8W.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-W4KKPZXB-Caezg-U2.js → quadrantDiagram-W4KKPZXB-ClVzvpE7.js} +1 -1
- package/dist/web/assets/{razor-CHm8DY1p.js → razor-DF2ZxqCE.js} +1 -1
- package/dist/web/assets/{requirementDiagram-4Y6WPE33-BtdP3Ka6.js → requirementDiagram-4Y6WPE33-uXN6Uoln.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-5OEKKPKP-Bv74oA-n.js → sankeyDiagram-5OEKKPKP-Bi3Tc0wR.js} +1 -1
- package/dist/web/assets/{search-ClmOQd4H.js → search--FRFbCre.js} +1 -1
- package/dist/web/assets/{select-CYtYPr-c.js → select-D0sHgfcU.js} +1 -1
- package/dist/web/assets/{select-BB7QG08o.js → select-c5IIpQj0.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-3UESZ5HK-DuNPl-dg.js → sequenceDiagram-3UESZ5HK-CLdrO2PY.js} +1 -1
- package/dist/web/assets/{server-bEB_DY55.js → server-Dr_6KJFM.js} +1 -1
- package/dist/web/assets/{stateDiagram-AJRCARHV-B72HAgBJ.js → stateDiagram-AJRCARHV-BGInldGc.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-D44x8SXb.js +1 -0
- package/dist/web/assets/{textarea-BqYPvoO-.js → textarea-W-xQPto3.js} +1 -1
- package/dist/web/assets/{timeline-definition-PNZ67QCA-DTmHUgmQ.js → timeline-definition-PNZ67QCA-BUp6Qykc.js} +1 -1
- package/dist/web/assets/{toggles-a5fkwT_D.js → toggles-Bgp7vdwg.js} +1 -1
- package/dist/web/assets/{tooltip-DuyJMci9.js → tooltip-DZcaSN1F.js} +1 -1
- package/dist/web/assets/{track-DCjyrv3n.js → track-Cj1Ogapu.js} +1 -1
- package/dist/web/assets/{trash-2-CIyBqaVy.js → trash-2-DmFXzIhh.js} +1 -1
- package/dist/web/assets/{tsMode-C1UXAkMh.js → tsMode-CSHMQttX.js} +1 -1
- package/dist/web/assets/{typescript-Biht2wHb.js → typescript-CyQKmnN-.js} +1 -1
- package/dist/web/assets/{upload-D05XS5-G.js → upload-C-4QDrwN.js} +1 -1
- package/dist/web/assets/{use-profiles-CrWTyz1G.js → use-profiles-D5mIgeQU.js} +1 -1
- package/dist/web/assets/{use-providers-Dv1Nk6s7.js → use-providers-BViTes-6.js} +1 -1
- package/dist/web/assets/{use-translation-settings-CcUnipVO.js → use-translation-settings-Dgw0oKP1.js} +1 -1
- package/dist/web/assets/{useNormalizedLogs-D9W1cT4R.js → useNormalizedLogs-BX7pMg0-.js} +1 -1
- package/dist/web/assets/{useTokenUsage-CZ5mDshD.js → useTokenUsage-T03faPfn.js} +1 -1
- package/dist/web/assets/{vennDiagram-CIIHVFJN-ByoNydXe.js → vennDiagram-CIIHVFJN-iQYnP9Ux.js} +1 -1
- package/dist/web/assets/{wardley-L42UT6IY-BqdMkOLl.js → wardley-L42UT6IY-J7vXwA5J.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-YWT4CUSO-AO22HrEF.js → wardleyDiagram-YWT4CUSO-CdtM5GJv.js} +1 -1
- package/dist/web/assets/{xml-NLGqNFDv.js → xml-C79KdvcD.js} +1 -1
- package/dist/web/assets/{xychartDiagram-2RQKCTM6-vzPgjgqW.js → xychartDiagram-2RQKCTM6-B3gcBChQ.js} +1 -1
- package/dist/web/assets/{yaml-AWlGS_Ig.js → yaml-C1WLpuVe.js} +1 -1
- package/dist/web/index.html +2 -2
- package/node_modules/@agent-tower/shared/dist/index.d.ts +1 -0
- package/node_modules/@agent-tower/shared/dist/index.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/index.js +1 -0
- package/node_modules/@agent-tower/shared/dist/index.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/task-hierarchy.d.ts +17 -0
- package/node_modules/@agent-tower/shared/dist/task-hierarchy.d.ts.map +1 -0
- package/node_modules/@agent-tower/shared/dist/task-hierarchy.js +12 -0
- package/node_modules/@agent-tower/shared/dist/task-hierarchy.js.map +1 -0
- package/node_modules/@agent-tower/shared/dist/types.d.ts +8 -2
- package/node_modules/@agent-tower/shared/dist/types.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/prisma/migrations/20261027000000_preserve_workspace_history/migration.sql +2 -0
- package/prisma/schema.prisma +2 -0
- package/dist/web/assets/MobileTaskDetail-M_Kke9rL.js +0 -3
- package/dist/web/assets/ProjectKanbanPage-soDqevjQ.js +0 -12
- package/dist/web/assets/TaskDetail-CqhPxvg3.js +0 -1
- package/dist/web/assets/channel-CUa8oyzC.js +0 -1
- package/dist/web/assets/check-DaZqOL8l.js +0 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-BAx111NO.js +0 -1
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-BAx111NO.js +0 -1
- package/dist/web/assets/index-BN53vGxp.css +0 -1
- package/dist/web/assets/index-Cc3qXMhU.js +0 -122
- package/dist/web/assets/javascript-BNXtViSL.js +0 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-Bu3l_CgB.js +0 -1
|
@@ -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
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
}
|
|
1372
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
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.
|
|
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 ─────────────────────────────────────────────────────────────────────
|
|
@@ -2154,7 +2209,7 @@ export class WorkspaceService {
|
|
|
2154
2209
|
}
|
|
2155
2210
|
// ── Cleanup ──────────────────────────────────────────────────────────────────
|
|
2156
2211
|
/**
|
|
2157
|
-
*
|
|
2212
|
+
* 回收已完成任务的 ABANDONED/MERGED Workspace 资源,保留会话历史。
|
|
2158
2213
|
*
|
|
2159
2214
|
* @returns 被清理的 Workspace 数量
|
|
2160
2215
|
*/
|
|
@@ -2162,69 +2217,86 @@ export class WorkspaceService {
|
|
|
2162
2217
|
const workspaces = await prisma.workspace.findMany({
|
|
2163
2218
|
where: {
|
|
2164
2219
|
status: { in: [WorkspaceStatus.ABANDONED, WorkspaceStatus.MERGED] },
|
|
2165
|
-
|
|
2220
|
+
cleanedAt: null,
|
|
2221
|
+
task: { status: TaskStatus.DONE, deletedAt: null },
|
|
2166
2222
|
},
|
|
2167
|
-
|
|
2223
|
+
select: { id: true },
|
|
2168
2224
|
});
|
|
2169
2225
|
let cleaned = 0;
|
|
2170
|
-
for (const
|
|
2226
|
+
for (const candidate of workspaces) {
|
|
2171
2227
|
try {
|
|
2172
|
-
await withSessionResourceCleanup({ workspaceId:
|
|
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;
|
|
2173
2241
|
const sessions = await prisma.session.findMany({ where: { workspaceId: workspace.id }, select: { id: true } });
|
|
2174
2242
|
for (const session of sessions) {
|
|
2175
2243
|
await stopSessionForResourceCleanup(this.sessionService, session.id);
|
|
2176
2244
|
}
|
|
2177
2245
|
await this.backgroundService.stopAllForWorkspace(workspace.id);
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
await prisma.workspace.delete({ where: { id: workspace.id } });
|
|
2181
|
-
cleaned++;
|
|
2182
|
-
return;
|
|
2183
|
-
}
|
|
2184
|
-
const worktreeManager = new WorktreeManager(workspace.task.project.repoPath);
|
|
2246
|
+
const worktreeManager = isWorktreeWorkspace(workspace)
|
|
2247
|
+
? new WorktreeManager(workspace.task.project.repoPath) : null;
|
|
2185
2248
|
// 清理残留 worktree(如果还存在)
|
|
2186
|
-
if (workspace.worktreePath) {
|
|
2249
|
+
if (worktreeManager && workspace.worktreePath) {
|
|
2187
2250
|
const removeResult = await worktreeManager.remove(workspace.worktreePath);
|
|
2188
2251
|
if (removeResult.status === 'unregistered') {
|
|
2189
2252
|
console.warn(`[WorkspaceService] cleanup: workspace ${workspace.id} path is unregistered or unsafe to remove: ${removeResult.path}`);
|
|
2190
2253
|
return;
|
|
2191
2254
|
}
|
|
2192
2255
|
}
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
// Retain the owner record so the branch can be reclaimed on family deletion.
|
|
2200
|
-
if (referencedByChild) {
|
|
2201
|
-
// The directory has been reclaimed; the branch still belongs to this task.
|
|
2202
|
-
await this.backgroundService.releaseLogsForWorkspace?.(workspace.id);
|
|
2203
|
-
cleaned++;
|
|
2204
|
-
return;
|
|
2205
|
-
}
|
|
2206
|
-
// Task 已 DONE,branch 不再需要,删除。安全 helper 会跳过 base/main/master/current/missing。
|
|
2207
|
-
const branchDeleteResult = await worktreeManager.deleteBranchIfSafe(workspace.branchName, {
|
|
2208
|
-
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 },
|
|
2209
2262
|
});
|
|
2210
|
-
|
|
2211
|
-
|
|
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() } });
|
|
2212
2266
|
}
|
|
2213
|
-
|
|
2214
|
-
|
|
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
|
+
});
|
|
2215
2272
|
}
|
|
2216
|
-
await this.backgroundService.releaseLogsForWorkspace?.(workspace.id);
|
|
2217
|
-
await prisma.workspace.delete({ where: { id: workspace.id } });
|
|
2218
|
-
cleaned++;
|
|
2219
2273
|
})));
|
|
2220
2274
|
}
|
|
2221
2275
|
catch (err) {
|
|
2222
2276
|
// Keep process evidence and directory resources for a later retry.
|
|
2223
|
-
console.warn(`[WorkspaceService] cleanup: failed for workspace ${
|
|
2277
|
+
console.warn(`[WorkspaceService] cleanup: failed for workspace ${candidate.id}: ${err instanceof Error ? err.message : err}`);
|
|
2224
2278
|
}
|
|
2225
2279
|
}
|
|
2226
2280
|
return cleaned;
|
|
2227
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
|
+
}
|
|
2228
2300
|
// ── Startup Prune ────────────────────────────────────────────────────────────
|
|
2229
2301
|
assertWorktreeWorkspace(workspace) {
|
|
2230
2302
|
if (isWorktreeWorkspace(workspace))
|