agent-tower 0.7.2 → 0.7.4-beta.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.
- package/dist/executors/__tests__/providers.test.js +53 -0
- package/dist/executors/__tests__/providers.test.js.map +1 -1
- package/dist/executors/providers.d.ts +2 -0
- package/dist/executors/providers.d.ts.map +1 -1
- package/dist/executors/providers.js +3 -2
- package/dist/executors/providers.js.map +1 -1
- package/dist/git/base-branch.d.ts +3 -0
- package/dist/git/base-branch.d.ts.map +1 -0
- package/dist/git/base-branch.js +17 -0
- package/dist/git/base-branch.js.map +1 -0
- package/dist/git/worktree.manager.d.ts +2 -0
- package/dist/git/worktree.manager.d.ts.map +1 -1
- package/dist/git/worktree.manager.js +29 -8
- package/dist/git/worktree.manager.js.map +1 -1
- package/dist/git/worktree.manager.test.js +38 -0
- package/dist/git/worktree.manager.test.js.map +1 -1
- package/dist/mcp/http-client.d.ts +4 -6
- package/dist/mcp/http-client.d.ts.map +1 -1
- package/dist/mcp/http-client.js +6 -0
- package/dist/mcp/http-client.js.map +1 -1
- package/dist/mcp/tools/__tests__/providers.test.d.ts +2 -0
- package/dist/mcp/tools/__tests__/providers.test.d.ts.map +1 -0
- package/dist/mcp/tools/__tests__/providers.test.js +22 -0
- package/dist/mcp/tools/__tests__/providers.test.js.map +1 -0
- package/dist/mcp/tools/__tests__/tasks.test.d.ts +2 -0
- package/dist/mcp/tools/__tests__/tasks.test.d.ts.map +1 -0
- package/dist/mcp/tools/__tests__/tasks.test.js +49 -0
- package/dist/mcp/tools/__tests__/tasks.test.js.map +1 -0
- package/dist/mcp/tools/providers.d.ts.map +1 -1
- package/dist/mcp/tools/providers.js +3 -2
- package/dist/mcp/tools/providers.js.map +1 -1
- package/dist/mcp/tools/tasks.d.ts.map +1 -1
- package/dist/mcp/tools/tasks.js +31 -2
- package/dist/mcp/tools/tasks.js.map +1 -1
- package/dist/mcp/types.d.ts +27 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js +13 -0
- package/dist/mcp/types.js.map +1 -1
- package/dist/output/__tests__/text-block-lifecycle.test.js +37 -0
- package/dist/output/__tests__/text-block-lifecycle.test.js.map +1 -1
- package/dist/output/text-block-tracker.d.ts.map +1 -1
- package/dist/output/text-block-tracker.js +24 -1
- package/dist/output/text-block-tracker.js.map +1 -1
- package/dist/prompts/task-handoff.d.ts +6 -0
- package/dist/prompts/task-handoff.d.ts.map +1 -0
- package/dist/prompts/task-handoff.js +17 -0
- package/dist/prompts/task-handoff.js.map +1 -0
- package/dist/prompts/task-handoff.test.d.ts +2 -0
- package/dist/prompts/task-handoff.test.d.ts.map +1 -0
- package/dist/prompts/task-handoff.test.js +27 -0
- package/dist/prompts/task-handoff.test.js.map +1 -0
- package/dist/prompts/workspace-background-service-policy.d.ts +6 -0
- package/dist/prompts/workspace-background-service-policy.d.ts.map +1 -1
- package/dist/prompts/workspace-background-service-policy.js +2 -1
- package/dist/prompts/workspace-background-service-policy.js.map +1 -1
- package/dist/routes/__tests__/providers.test.js +67 -0
- package/dist/routes/__tests__/providers.test.js.map +1 -1
- package/dist/routes/__tests__/task-handoff.test.d.ts +2 -0
- package/dist/routes/__tests__/task-handoff.test.d.ts.map +1 -0
- package/dist/routes/__tests__/task-handoff.test.js +185 -0
- package/dist/routes/__tests__/task-handoff.test.js.map +1 -0
- package/dist/routes/__tests__/tasks.test.js +46 -0
- package/dist/routes/__tests__/tasks.test.js.map +1 -1
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +8 -0
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/tasks.d.ts.map +1 -1
- package/dist/routes/tasks.js +60 -2
- package/dist/routes/tasks.js.map +1 -1
- package/dist/runtime/acp/history-reconciler.js +1 -1
- package/dist/runtime/acp/history-reconciler.js.map +1 -1
- package/dist/services/__tests__/session-manager.lifecycle.test.js +171 -1
- package/dist/services/__tests__/session-manager.lifecycle.test.js.map +1 -1
- package/dist/services/__tests__/task.service.test.js +142 -76
- package/dist/services/__tests__/task.service.test.js.map +1 -1
- package/dist/services/__tests__/translation-protection.test.js +48 -18
- package/dist/services/__tests__/translation-protection.test.js.map +1 -1
- package/dist/services/__tests__/translation-session-blocks.test.js +66 -2
- package/dist/services/__tests__/translation-session-blocks.test.js.map +1 -1
- package/dist/services/__tests__/workspace-background-service.service.test.js +74 -26
- package/dist/services/__tests__/workspace-background-service.service.test.js.map +1 -1
- package/dist/services/__tests__/workspace.service.test.js +70 -0
- package/dist/services/__tests__/workspace.service.test.js.map +1 -1
- package/dist/services/message-delivery.service.d.ts +4 -1
- package/dist/services/message-delivery.service.d.ts.map +1 -1
- package/dist/services/project.service.d.ts +3 -0
- package/dist/services/project.service.d.ts.map +1 -1
- package/dist/services/provider-config.service.d.ts.map +1 -1
- package/dist/services/provider-config.service.js +1 -0
- package/dist/services/provider-config.service.js.map +1 -1
- package/dist/services/session-manager.d.ts +15 -5
- package/dist/services/session-manager.d.ts.map +1 -1
- package/dist/services/session-manager.js +19 -3
- package/dist/services/session-manager.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 +2 -2
- package/dist/services/task-cleanup.service.js.map +1 -1
- package/dist/services/task-handoff.service.d.ts +18 -0
- package/dist/services/task-handoff.service.d.ts.map +1 -0
- package/dist/services/task-handoff.service.js +87 -0
- package/dist/services/task-handoff.service.js.map +1 -0
- package/dist/services/task.service.d.ts +45 -18
- package/dist/services/task.service.d.ts.map +1 -1
- package/dist/services/task.service.js +215 -160
- package/dist/services/task.service.js.map +1 -1
- package/dist/services/team-run.service.d.ts +3 -0
- package/dist/services/team-run.service.d.ts.map +1 -1
- package/dist/services/team-task-input.service.d.ts +3 -0
- package/dist/services/team-task-input.service.d.ts.map +1 -1
- package/dist/services/translation-protection.d.ts +3 -1
- package/dist/services/translation-protection.d.ts.map +1 -1
- package/dist/services/translation-protection.js +21 -67
- package/dist/services/translation-protection.js.map +1 -1
- package/dist/services/translation-settings.service.d.ts +4 -4
- package/dist/services/translation.service.d.ts.map +1 -1
- package/dist/services/translation.service.js +44 -20
- package/dist/services/translation.service.js.map +1 -1
- package/dist/services/workspace-background-service.service.d.ts +1 -3
- package/dist/services/workspace-background-service.service.d.ts.map +1 -1
- package/dist/services/workspace-background-service.service.js +17 -65
- package/dist/services/workspace-background-service.service.js.map +1 -1
- package/dist/services/workspace.service.d.ts +21 -6
- package/dist/services/workspace.service.d.ts.map +1 -1
- package/dist/services/workspace.service.js +56 -11
- package/dist/services/workspace.service.js.map +1 -1
- package/dist/web/assets/AgentDemoPage-JXetlNBf.js +1 -0
- package/dist/web/assets/{AgentEnvironmentSettingsPage-GHjKIWpb.js → AgentEnvironmentSettingsPage-CdYyUCwJ.js} +1 -1
- package/dist/web/assets/AttachmentPreview-DMS-PM-1.js +2 -0
- package/dist/web/assets/BranchSelect-BAq4L2ZS.js +1 -0
- package/dist/web/assets/BrandLogo--kWXXJtZ.js +1 -0
- package/dist/web/assets/ConversationPage-CvC4RyB5.js +1 -0
- package/dist/web/assets/CreateTaskInput-DjVxCAfc.js +1 -0
- package/dist/web/assets/{DemoPage-DK-ikg1_.js → DemoPage-cDVTGOp8.js} +3 -3
- package/dist/web/assets/DesignSystemPage-BI54IkKi.js +12 -0
- package/dist/web/assets/{ExecutionPermissionSelector-B8befbxJ.js → ExecutionPermissionSelector-f1UYIm1z.js} +1 -1
- package/dist/web/assets/GeneralSettingsPage-C0yto6C_.js +1 -0
- package/dist/web/assets/{LoadingPreviewPage-BDlf89rJ.js → LoadingPreviewPage-BiJSaHUi.js} +1 -1
- package/dist/web/assets/McpSettingsPage-BbHwZtyj.js +1 -0
- package/dist/web/assets/{MemberAvatar-YVr_erAr.js → MemberAvatar-BLezO3vS.js} +1 -1
- package/dist/web/assets/MobileTaskDetail-M_Kke9rL.js +3 -0
- package/dist/web/assets/NotificationSettingsPage-CiKoL2Kv.js +1 -0
- package/dist/web/assets/{ProfileSettingsPage-CHe4LlRp.js → ProfileSettingsPage-DCB48cPS.js} +2 -2
- package/dist/web/assets/ProjectKanbanPage-soDqevjQ.js +12 -0
- package/dist/web/assets/ProjectSettingsPage-COvIVq1h.js +2 -0
- package/dist/web/assets/ProviderSettingsPage-CPuJcZDg.js +67 -0
- package/dist/web/assets/{SettingsMasterDetail-DjWR9Sqk.js → SettingsMasterDetail-Cv7YaRJB.js} +1 -1
- package/dist/web/assets/TaskDetail-CqhPxvg3.js +1 -0
- package/dist/web/assets/TaskHandoffPanel-CxH3Mgyd.js +70 -0
- package/dist/web/assets/TeamSettingsPage-D-XDefNd.js +1 -0
- package/dist/web/assets/{TranslationSettingsPage-Cod9c4Ug.js → TranslationSettingsPage-BPHI-SZW.js} +1 -1
- package/dist/web/assets/{arc-DEy33vTc.js → arc-CC81aLuf.js} +1 -1
- package/dist/web/assets/{architectureDiagram-3BPJPVTR-Ky1D1LBk.js → architectureDiagram-3BPJPVTR-DL08XGaN.js} +1 -1
- package/dist/web/assets/{at-sign-C48_y345.js → at-sign-DYPIlD6D.js} +1 -1
- package/dist/web/assets/{blockDiagram-GPEHLZMM-BNgB7kNT.js → blockDiagram-GPEHLZMM-B4IW5WxI.js} +1 -1
- package/dist/web/assets/{c4Diagram-AAUBKEIU-4GMrPMgQ.js → c4Diagram-AAUBKEIU-Cj4d_FqK.js} +1 -1
- package/dist/web/assets/channel-CUa8oyzC.js +1 -0
- package/dist/web/assets/check-DaZqOL8l.js +1 -0
- package/dist/web/assets/{chevron-down-3y5Aiolp.js → chevron-down-DNhYsNAt.js} +1 -1
- package/dist/web/assets/{chevron-up-DqaYcjpq.js → chevron-up-CjrLieBR.js} +1 -1
- package/dist/web/assets/chip-Cf92J-pQ.js +1 -0
- package/dist/web/assets/{chunk-2J33WTMH-C439hRe_.js → chunk-2J33WTMH-DeCj8QSD.js} +1 -1
- package/dist/web/assets/{chunk-4BX2VUAB-D8GK3M3t.js → chunk-4BX2VUAB-k-6rzQmQ.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-Dl4UhJ8X.js → chunk-55IACEB6-qMTCQ5bX.js} +1 -1
- package/dist/web/assets/{chunk-727SXJPM-BSEeayBq.js → chunk-727SXJPM-CMnu18d1.js} +1 -1
- package/dist/web/assets/{chunk-AQP2D5EJ-B6chbZfT.js → chunk-AQP2D5EJ-C0mFbUMn.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-DaLkiLdQ.js → chunk-FMBD7UC4-u6-_M137.js} +1 -1
- package/dist/web/assets/{chunk-ND2GUHAM-DeQwZAAT.js → chunk-ND2GUHAM-DHrIE_8H.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-CLRr4YRM.js → chunk-QZHKN3VN-aTyC0wZq.js} +1 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-BAx111NO.js +1 -0
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-BAx111NO.js +1 -0
- package/dist/web/assets/{code-block-OCS4YCEC-CnoxUpOx.js → code-block-OCS4YCEC-CBIOQOMH.js} +1 -1
- package/dist/web/assets/confirm-dialog-DWeBZLJW.js +1 -0
- package/dist/web/assets/content-JM9E1MeD.js +2 -0
- package/dist/web/assets/{copy-HRMhTkIG.js → copy-D0gl9kF8.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-C1UiYzfk.js → cose-bilkent-S5V4N54A-xLyliSgU.js} +1 -1
- package/dist/web/assets/cssMode-DO5UnQ64.js +1 -0
- package/dist/web/assets/{dagre-BM42HDAG-CTJpBgye.js → dagre-BM42HDAG-CbNpoO2d.js} +1 -1
- package/dist/web/assets/{diagram-2AECGRRQ-Dj1_TEYp.js → diagram-2AECGRRQ-CG3hKxAX.js} +1 -1
- package/dist/web/assets/{diagram-5GNKFQAL-V-KUpwqh.js → diagram-5GNKFQAL-mQu9M28s.js} +1 -1
- package/dist/web/assets/{diagram-KO2AKTUF-CXG1ZIeX.js → diagram-KO2AKTUF-BSeEp_Uw.js} +1 -1
- package/dist/web/assets/{diagram-LMA3HP47-BZSJUwk9.js → diagram-LMA3HP47-D6yRdao-.js} +1 -1
- package/dist/web/assets/{diagram-OG6HWLK6-CCr4gq4u.js → diagram-OG6HWLK6-BUBUW9wD.js} +1 -1
- package/dist/web/assets/dialog-D1lkhqVL.js +5 -0
- package/dist/web/assets/{erDiagram-TEJ5UH35-Djtyzh6z.js → erDiagram-TEJ5UH35-BQSZgRqq.js} +1 -1
- package/dist/web/assets/file-BijjwxRR.js +1 -0
- package/dist/web/assets/{flowDiagram-I6XJVG4X-BmSVSiXJ.js → flowDiagram-I6XJVG4X-D-eqyr5Y.js} +1 -1
- package/dist/web/assets/folder-picker-Czxm0_S9.js +1 -0
- package/dist/web/assets/{freemarker2-DdptX5f1.js → freemarker2-B4RvEa_U.js} +2 -2
- package/dist/web/assets/{ganttDiagram-6RSMTGT7-r5vQX-b5.js → ganttDiagram-6RSMTGT7-BWGkCt_x.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PVQCEYII-Zj9aloh9.js → gitGraphDiagram-PVQCEYII-DGVc49pR.js} +1 -1
- package/dist/web/assets/{globe-B9I-jHBB.js → globe-Ce01-45x.js} +1 -1
- package/dist/web/assets/handlebars-oyT7drqS.js +1 -0
- package/dist/web/assets/html-CxxWf2Qk.js +1 -0
- package/dist/web/assets/htmlMode-RfAHh5Jj.js +1 -0
- package/dist/web/assets/index-BMZFF1UJ.js +1 -0
- package/dist/web/assets/index-BN53vGxp.css +1 -0
- package/dist/web/assets/index-Cc3qXMhU.js +122 -0
- package/dist/web/assets/{index-Bhvt-E6d.js → index-DWrSDMX2.js} +2 -2
- package/dist/web/assets/{index-DkRy6eNX.js → index-Dh-tgeaL.js} +4 -4
- package/dist/web/assets/{index-B1oVmCie.js → index-Disv1kQS.js} +1 -1
- package/dist/web/assets/{index-DcOU2m2F.js → index-DyJfPc4O.js} +1 -1
- package/dist/web/assets/{index-Dk3bRQAK.js → index-Pt4TsHjm.js} +1 -1
- package/dist/web/assets/{index-CThFsQNP.js → index-T38iVLEb.js} +1 -1
- package/dist/web/assets/{index-BtUQYU5l.js → index-hpHE1jXY.js} +1 -1
- package/dist/web/assets/{infoDiagram-5YYISTIA-BHtVaxZx.js → infoDiagram-5YYISTIA-DLPs3dV_.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-BYmwjkbC.js → ishikawaDiagram-YF4QCWOH-d_OrnwDY.js} +1 -1
- package/dist/web/assets/javascript-BNXtViSL.js +1 -0
- package/dist/web/assets/{journeyDiagram-JHISSGLW-c8BBqqRS.js → journeyDiagram-JHISSGLW-EtU1st_0.js} +1 -1
- package/dist/web/assets/jsonMode-Bqh5vIxx.js +7 -0
- package/dist/web/assets/{kanban-definition-UN3LZRKU-D4Vr-oFT.js → kanban-definition-UN3LZRKU-ZWzUnsFK.js} +1 -1
- package/dist/web/assets/{kbd-C88ut3t9.js → kbd-IjDGsZ2B.js} +1 -1
- package/dist/web/assets/{key-round-Cjbj2qNa.js → key-round-CbnAuUxp.js} +1 -1
- package/dist/web/assets/{layers-eaHAVcc3.js → layers-Pdy9vZ6K.js} +1 -1
- package/dist/web/assets/{linear-opi90s0L.js → linear-D7n23wcA.js} +1 -1
- package/dist/web/assets/{link-BSGb85gq.js → link-Bl1ZbjFh.js} +1 -1
- package/dist/web/assets/liquid-Ds47iVLN.js +1 -0
- package/dist/web/assets/{lspLanguageFeatures-DWu2Ubf0.js → lspLanguageFeatures-Dcch3bsp.js} +1 -1
- package/dist/web/assets/mdx-CM7ky-2B.js +1 -0
- package/dist/web/assets/{menu--sjyisSg.js → menu-DubntFHq.js} +1 -1
- package/dist/web/assets/{mermaid-NOHMQCX5-BSNbBj78.js → mermaid-NOHMQCX5-nBsnjgeU.js} +54 -54
- package/dist/web/assets/{message-square-BLEJN6p7.js → message-square-BE-pW0m_.js} +1 -1
- package/dist/web/assets/{mindmap-definition-RKZ34NQL-BN3ZjBh-.js → mindmap-definition-RKZ34NQL-ClHORNTt.js} +1 -1
- package/dist/web/assets/modal-CHLtZWvx.js +1 -0
- package/dist/web/assets/{monaco-BkuNyOkP.js → monaco-BbAmalE2.js} +3 -3
- package/dist/web/assets/nav-row-DH7rNq1V.js +1 -0
- package/dist/web/assets/{paperclip-CTNoXpUW.js → paperclip-YP3Bk1lI.js} +1 -1
- package/dist/web/assets/{pencil-Cp70ZwtG.js → pencil-BFDuhbtW.js} +1 -1
- package/dist/web/assets/{people-DT78SebR.js → people-DEeNaaLt.js} +1 -1
- package/dist/web/assets/{pieDiagram-4H26LBE5-CfmFHpPI.js → pieDiagram-4H26LBE5-BUOaKIyP.js} +1 -1
- package/dist/web/assets/popover-CUmBEXxL.js +1 -0
- package/dist/web/assets/provider-selection-DSu7SCI7.js +1 -0
- package/dist/web/assets/python-BODTtU6m.js +1 -0
- package/dist/web/assets/{quadrantDiagram-W4KKPZXB-CeaumJAa.js → quadrantDiagram-W4KKPZXB-Caezg-U2.js} +1 -1
- package/dist/web/assets/razor-CHm8DY1p.js +1 -0
- package/dist/web/assets/{requirementDiagram-4Y6WPE33-BWWCDXCE.js → requirementDiagram-4Y6WPE33-BtdP3Ka6.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-5OEKKPKP-DAJut743.js → sankeyDiagram-5OEKKPKP-Bv74oA-n.js} +1 -1
- package/dist/web/assets/{search-DniD_AGC.js → search-ClmOQd4H.js} +1 -1
- package/dist/web/assets/{select-BPdJrr5M.js → select-BB7QG08o.js} +1 -1
- package/dist/web/assets/{select-B5RYunTs.js → select-CYtYPr-c.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-3UESZ5HK-CynjRGW4.js → sequenceDiagram-3UESZ5HK-DuNPl-dg.js} +1 -1
- package/dist/web/assets/{server-xswxWpKD.js → server-bEB_DY55.js} +1 -1
- package/dist/web/assets/{stateDiagram-AJRCARHV-amAtpx9w.js → stateDiagram-AJRCARHV-B72HAgBJ.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-Bu3l_CgB.js +1 -0
- package/dist/web/assets/{textarea-BVyPl9rM.js → textarea-BqYPvoO-.js} +1 -1
- package/dist/web/assets/{timeline-definition-PNZ67QCA-DZ9W7WlP.js → timeline-definition-PNZ67QCA-DTmHUgmQ.js} +1 -1
- package/dist/web/assets/{toggles-QcIz43DP.js → toggles-a5fkwT_D.js} +1 -1
- package/dist/web/assets/tooltip-DuyJMci9.js +1 -0
- package/dist/web/assets/{track-Ckye0-tt.js → track-DCjyrv3n.js} +1 -1
- package/dist/web/assets/{trash-2-CvUJsbtT.js → trash-2-CIyBqaVy.js} +1 -1
- package/dist/web/assets/tsMode-C1UXAkMh.js +11 -0
- package/dist/web/assets/typescript-Biht2wHb.js +1 -0
- package/dist/web/assets/{upload-CsXAmAun.js → upload-D05XS5-G.js} +1 -1
- package/dist/web/assets/use-profiles-CrWTyz1G.js +1 -0
- package/dist/web/assets/{use-providers-Td1-gyrN.js → use-providers-Dv1Nk6s7.js} +1 -1
- package/dist/web/assets/{use-translation-settings-NYM0lmBx.js → use-translation-settings-CcUnipVO.js} +1 -1
- package/dist/web/assets/useNormalizedLogs-D9W1cT4R.js +1 -0
- package/dist/web/assets/useTokenUsage-CZ5mDshD.js +1 -0
- package/dist/web/assets/{vennDiagram-CIIHVFJN-CB2Ubvy9.js → vennDiagram-CIIHVFJN-ByoNydXe.js} +1 -1
- package/dist/web/assets/{wardley-L42UT6IY-BXOkk77I.js → wardley-L42UT6IY-BqdMkOLl.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-YWT4CUSO-VA6ywdQQ.js → wardleyDiagram-YWT4CUSO-AO22HrEF.js} +1 -1
- package/dist/web/assets/xml-NLGqNFDv.js +1 -0
- package/dist/web/assets/{xychartDiagram-2RQKCTM6-FNcvDj5G.js → xychartDiagram-2RQKCTM6-vzPgjgqW.js} +1 -1
- package/dist/web/assets/yaml-AWlGS_Ig.js +1 -0
- 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-handoff.d.ts +12 -0
- package/node_modules/@agent-tower/shared/dist/task-handoff.d.ts.map +1 -0
- package/node_modules/@agent-tower/shared/dist/task-handoff.js +2 -0
- package/node_modules/@agent-tower/shared/dist/task-handoff.js.map +1 -0
- package/node_modules/@agent-tower/shared/dist/translation.d.ts +12 -0
- package/node_modules/@agent-tower/shared/dist/translation.d.ts.map +1 -1
- package/node_modules/@agent-tower/shared/dist/translation.js +19 -0
- package/node_modules/@agent-tower/shared/dist/translation.js.map +1 -1
- package/node_modules/@agent-tower/shared/dist/types.d.ts +28 -1
- 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/20261023000000_add_task_base_branch/migration.sql +2 -0
- package/prisma/migrations/20261023010000_add_subtasks/migration.sql +2 -0
- package/prisma/migrations/20261026000000_add_task_handoff/migration.sql +1 -0
- package/prisma/schema.prisma +6 -0
- package/dist/web/assets/AgentDemoPage-BfXkNCdN.js +0 -1
- package/dist/web/assets/AttachmentPreview-CLN1lnLe.js +0 -2
- package/dist/web/assets/BranchSelect-Cofp8vYf.js +0 -1
- package/dist/web/assets/BrandLogo-BUimEX-9.js +0 -1
- package/dist/web/assets/ConversationPage-R7vNaOQv.js +0 -1
- package/dist/web/assets/CreateTaskInput-CasITF8y.js +0 -1
- package/dist/web/assets/DesignSystemPage-BhjNs2vP.js +0 -12
- package/dist/web/assets/EditableTaskTitle-BJ9Rxggf.js +0 -70
- package/dist/web/assets/GeneralSettingsPage-RMN2al8I.js +0 -1
- package/dist/web/assets/McpSettingsPage-CPNxFF67.js +0 -1
- package/dist/web/assets/MobileTaskDetail-QNUHMq7u.js +0 -3
- package/dist/web/assets/NotificationSettingsPage-BEyuyu3Z.js +0 -1
- package/dist/web/assets/ProjectKanbanPage-Bt_01giW.js +0 -12
- package/dist/web/assets/ProjectSettingsPage-cus6Ns97.js +0 -2
- package/dist/web/assets/ProviderSettingsPage-DqA_B1Ey.js +0 -67
- package/dist/web/assets/TaskDetail-rEXNe2h3.js +0 -1
- package/dist/web/assets/TeamSettingsPage-DwWROtW6.js +0 -1
- package/dist/web/assets/channel-DTP-syjA.js +0 -1
- package/dist/web/assets/check-BmiJ7qMY.js +0 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-CUKgurLa.js +0 -1
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-CUKgurLa.js +0 -1
- package/dist/web/assets/confirm-dialog-ltNBFYCs.js +0 -1
- package/dist/web/assets/content-DPQMfMae.js +0 -2
- package/dist/web/assets/cssMode-DkuSsGeg.js +0 -1
- package/dist/web/assets/dialog-CuFEdqLg.js +0 -5
- package/dist/web/assets/handlebars-B34f-LAf.js +0 -1
- package/dist/web/assets/hooks-BLxb16IA.js +0 -1
- package/dist/web/assets/html-CnvOQ63o.js +0 -1
- package/dist/web/assets/htmlMode-RdxZ8Svp.js +0 -1
- package/dist/web/assets/icon-button-CYiKa-7C.js +0 -1
- package/dist/web/assets/index-0XPZayUU.css +0 -1
- package/dist/web/assets/index-BJObbxud.js +0 -122
- package/dist/web/assets/index-DZLnTISJ.js +0 -1
- package/dist/web/assets/javascript-BhombDEO.js +0 -1
- package/dist/web/assets/jsonMode-BJGOUeaV.js +0 -7
- package/dist/web/assets/liquid-Czy1WpPz.js +0 -1
- package/dist/web/assets/mdx-DhXfoSnM.js +0 -1
- package/dist/web/assets/modal-CSGOqphK.js +0 -1
- package/dist/web/assets/popover-BiVxGGgp.js +0 -1
- package/dist/web/assets/python-DIcQDjcf.js +0 -1
- package/dist/web/assets/razor-DYK6Rxer.js +0 -1
- package/dist/web/assets/search-field-CQLDXLeA.js +0 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-V-lSceg1.js +0 -1
- package/dist/web/assets/tooltip-CPqGK_WZ.js +0 -1
- package/dist/web/assets/tsMode-c5x0d47n.js +0 -11
- package/dist/web/assets/typescript-i7eYblLt.js +0 -1
- package/dist/web/assets/use-profiles-DuXaBRju.js +0 -1
- package/dist/web/assets/use-projects-Ddz0knyr.js +0 -1
- package/dist/web/assets/use-workspaces-CdJZLmGh.js +0 -1
- package/dist/web/assets/useNormalizedLogs--RbVywYa.js +0 -1
- package/dist/web/assets/useTokenUsage-DDXf7E4p.js +0 -1
- package/dist/web/assets/xml-D2EGActB.js +0 -1
- package/dist/web/assets/yaml-jeiIZSL4.js +0 -1
- /package/dist/web/assets/{EditableTaskTitle-DcpNTP1B.css → TaskHandoffPanel-DcpNTP1B.css} +0 -0
|
@@ -3,13 +3,20 @@ export { buildTextPreview } from '../utils/text-preview.js';
|
|
|
3
3
|
import { prisma } from '../utils/index.js';
|
|
4
4
|
import { TaskStatus, SessionStatus, SessionPurpose, WorkspaceKind, WorkspaceStatus } from '../types/index.js';
|
|
5
5
|
import { getWorkspaceWorkingDir } from './workspace-kind.js';
|
|
6
|
-
import { NotFoundError, ValidationError, InvalidStateTransitionError, } from '../errors.js';
|
|
6
|
+
import { NotFoundError, ServiceError, ValidationError, InvalidStateTransitionError, } from '../errors.js';
|
|
7
7
|
import { defaultWorkspaceLifecycleBarrier } from './workspace-lifecycle-barrier.js';
|
|
8
|
-
import { ensureProjectIsMutable, getStoredProjectGitCapability } from './project-guards.js';
|
|
8
|
+
import { ensureProjectIsMutable, getStoredProjectGitCapability, detectProjectGitCapability } from './project-guards.js';
|
|
9
|
+
import { requireLocalBaseBranch } from '../git/base-branch.js';
|
|
9
10
|
import { defaultTeamLockService } from './team-lock.service.js';
|
|
10
11
|
import { TaskPriority } from '@agent-tower/shared';
|
|
11
12
|
import prismaPkg from '@prisma/client';
|
|
12
13
|
const { Prisma } = prismaPkg;
|
|
14
|
+
const taskBoardColumns = Prisma.sql `
|
|
15
|
+
task."id", task."projectId", task."title", task."status", task."priority",
|
|
16
|
+
task."position", task."updatedAt", task."parentTaskId",
|
|
17
|
+
(SELECT COUNT(*) FROM "Task" child WHERE child."parentTaskId" = task."id" AND child."deletedAt" IS NULL) AS "subtaskCount",
|
|
18
|
+
(SELECT COUNT(*) FROM "Task" child WHERE child."parentTaskId" = task."id" AND child."deletedAt" IS NULL AND child."status" = 'IN_PROGRESS') AS "runningSubtaskCount"
|
|
19
|
+
`;
|
|
13
20
|
/**
|
|
14
21
|
* 合法的状态流转规则
|
|
15
22
|
* 看板拖拽场景下允许任意状态互转,状态变更无危险副作用
|
|
@@ -210,13 +217,17 @@ function normalizeUpdateTaskInput(current, input) {
|
|
|
210
217
|
]),
|
|
211
218
|
};
|
|
212
219
|
}
|
|
220
|
+
function withoutTaskHandoff(task) {
|
|
221
|
+
const { handoff: _handoff, ...metadata } = task;
|
|
222
|
+
return metadata;
|
|
223
|
+
}
|
|
213
224
|
function withTaskPreviews(task, options = {}) {
|
|
214
225
|
const titlePreview = buildTextPreview(task.title, TASK_TITLE_MAX_LENGTH);
|
|
215
226
|
const contentPreview = buildTextPreview(task.description);
|
|
216
227
|
const isTruncated = task.title !== titlePreview
|
|
217
228
|
|| Boolean(task.description && task.description !== contentPreview);
|
|
218
229
|
const base = {
|
|
219
|
-
...task,
|
|
230
|
+
...withoutTaskHandoff(task),
|
|
220
231
|
title: titlePreview,
|
|
221
232
|
titlePreview,
|
|
222
233
|
contentPreview: contentPreview || undefined,
|
|
@@ -234,13 +245,15 @@ function withProjectGitMetadata(task) {
|
|
|
234
245
|
return withProjectGitCapability(task, capability);
|
|
235
246
|
}
|
|
236
247
|
function withProjectGitCapability(task, capability) {
|
|
237
|
-
|
|
248
|
+
const result = {
|
|
238
249
|
...task,
|
|
239
250
|
project: {
|
|
240
251
|
...task.project,
|
|
241
252
|
...capability,
|
|
242
253
|
},
|
|
243
254
|
};
|
|
255
|
+
delete result.handoff;
|
|
256
|
+
return result;
|
|
244
257
|
}
|
|
245
258
|
function buildProjectGitMetadata(project) {
|
|
246
259
|
return getStoredProjectGitCapability(project);
|
|
@@ -274,30 +287,28 @@ export class TaskService {
|
|
|
274
287
|
deletedAt: null,
|
|
275
288
|
project: { archivedAt: null },
|
|
276
289
|
...(params.projectId ? { projectId: params.projectId } : {}),
|
|
290
|
+
...(params.parentTaskId ? { parentTaskId: params.parentTaskId } : {}),
|
|
277
291
|
...(params.status ? { status: params.status } : {}),
|
|
278
292
|
};
|
|
279
293
|
const projectFilter = params.projectId
|
|
280
294
|
? Prisma.sql `AND task."projectId" = ${params.projectId}`
|
|
281
295
|
: Prisma.empty;
|
|
296
|
+
const parentFilter = params.parentTaskId
|
|
297
|
+
? Prisma.sql `AND task."parentTaskId" = ${params.parentTaskId}`
|
|
298
|
+
: Prisma.empty;
|
|
282
299
|
const statusFilter = params.status
|
|
283
300
|
? Prisma.sql `AND task."status" = ${params.status}`
|
|
284
301
|
: Prisma.empty;
|
|
285
302
|
const [tasks, total] = await Promise.all([
|
|
286
303
|
prisma.$queryRaw(Prisma.sql `
|
|
287
|
-
SELECT
|
|
288
|
-
task."id" AS "id",
|
|
289
|
-
task."projectId" AS "projectId",
|
|
290
|
-
task."title" AS "title",
|
|
291
|
-
task."status" AS "status",
|
|
292
|
-
task."priority" AS "priority",
|
|
293
|
-
task."position" AS "position",
|
|
294
|
-
task."updatedAt" AS "updatedAt"
|
|
304
|
+
SELECT ${taskBoardColumns}
|
|
295
305
|
FROM "Task" task
|
|
296
306
|
INNER JOIN "Project" project ON project."id" = task."projectId"
|
|
297
307
|
WHERE task."deletedAt" IS NULL
|
|
298
308
|
AND project."archivedAt" IS NULL
|
|
299
309
|
${projectFilter}
|
|
300
310
|
${statusFilter}
|
|
311
|
+
${parentFilter}
|
|
301
312
|
ORDER BY
|
|
302
313
|
CASE task."status"
|
|
303
314
|
WHEN ${TaskStatus.IN_PROGRESS} THEN 0
|
|
@@ -314,7 +325,19 @@ export class TaskService {
|
|
|
314
325
|
`),
|
|
315
326
|
prisma.task.count({ where }),
|
|
316
327
|
]);
|
|
317
|
-
|
|
328
|
+
// A child can rank ahead of its completed parent or fall on another page.
|
|
329
|
+
// Return compact parent context without changing the page's count/limit.
|
|
330
|
+
const pageIds = new Set(tasks.map((task) => task.id));
|
|
331
|
+
const missingParentIds = [...new Set(tasks.flatMap((task) => task.parentTaskId && !pageIds.has(task.parentTaskId) ? [task.parentTaskId] : []))];
|
|
332
|
+
const parents = params.parentTaskId || missingParentIds.length === 0 ? []
|
|
333
|
+
: await prisma.$queryRaw(Prisma.sql `
|
|
334
|
+
SELECT ${taskBoardColumns} FROM "Task" task
|
|
335
|
+
INNER JOIN "Project" project ON project."id" = task."projectId"
|
|
336
|
+
WHERE task."id" IN (${Prisma.join(missingParentIds)})
|
|
337
|
+
AND task."deletedAt" IS NULL AND project."archivedAt" IS NULL
|
|
338
|
+
`);
|
|
339
|
+
const allTasks = [...tasks, ...parents];
|
|
340
|
+
const taskIds = allTasks.map((task) => task.id);
|
|
318
341
|
const workspaceRows = taskIds.length === 0
|
|
319
342
|
? []
|
|
320
343
|
: await prisma.$queryRaw(Prisma.sql `
|
|
@@ -362,7 +385,7 @@ export class TaskService {
|
|
|
362
385
|
workspacesByTaskId.set(workspace.taskId, group);
|
|
363
386
|
}
|
|
364
387
|
const preferredWorkspaceByTaskId = new Map();
|
|
365
|
-
for (const task of
|
|
388
|
+
for (const task of allTasks) {
|
|
366
389
|
const candidates = workspacesByTaskId.get(task.id) ?? [];
|
|
367
390
|
const preferred = candidates.find((workspace) => workspace.status === WorkspaceStatus.ACTIVE)
|
|
368
391
|
?? candidates[0];
|
|
@@ -370,7 +393,7 @@ export class TaskService {
|
|
|
370
393
|
preferredWorkspaceByTaskId.set(task.id, preferred);
|
|
371
394
|
}
|
|
372
395
|
}
|
|
373
|
-
const data =
|
|
396
|
+
const data = allTasks.map((task) => {
|
|
374
397
|
const titlePreview = buildTextPreview(task.title, TASK_TITLE_MAX_LENGTH);
|
|
375
398
|
const preferredWorkspace = preferredWorkspaceByTaskId.get(task.id);
|
|
376
399
|
const hasRunningSession = (workspacesByTaskId.get(task.id) ?? [])
|
|
@@ -381,6 +404,9 @@ export class TaskService {
|
|
|
381
404
|
return {
|
|
382
405
|
id: task.id,
|
|
383
406
|
projectId: task.projectId,
|
|
407
|
+
parentTaskId: task.parentTaskId,
|
|
408
|
+
subtaskCount: Number(task.subtaskCount),
|
|
409
|
+
runningSubtaskCount: Number(task.runningSubtaskCount),
|
|
384
410
|
title: titlePreview,
|
|
385
411
|
status: task.status,
|
|
386
412
|
priority: task.priority ?? TaskPriority.NORMAL,
|
|
@@ -400,7 +426,8 @@ export class TaskService {
|
|
|
400
426
|
};
|
|
401
427
|
});
|
|
402
428
|
return {
|
|
403
|
-
data,
|
|
429
|
+
data: data.slice(0, tasks.length),
|
|
430
|
+
...(parents.length ? { parents: data.slice(tasks.length) } : {}),
|
|
404
431
|
total,
|
|
405
432
|
page,
|
|
406
433
|
limit,
|
|
@@ -441,6 +468,8 @@ export class TaskService {
|
|
|
441
468
|
id: true,
|
|
442
469
|
projectId: true,
|
|
443
470
|
title: true,
|
|
471
|
+
baseBranch: true,
|
|
472
|
+
parentTaskId: true,
|
|
444
473
|
status: true,
|
|
445
474
|
priority: true,
|
|
446
475
|
position: true,
|
|
@@ -487,6 +516,9 @@ export class TaskService {
|
|
|
487
516
|
projectId: true,
|
|
488
517
|
project: true,
|
|
489
518
|
title: true,
|
|
519
|
+
baseBranch: true,
|
|
520
|
+
parentTaskId: true,
|
|
521
|
+
_count: { select: { subtasks: { where: { deletedAt: null } } } },
|
|
490
522
|
status: true,
|
|
491
523
|
priority: true,
|
|
492
524
|
position: true,
|
|
@@ -498,7 +530,14 @@ export class TaskService {
|
|
|
498
530
|
if (!task) {
|
|
499
531
|
throw new NotFoundError('Task', id);
|
|
500
532
|
}
|
|
501
|
-
|
|
533
|
+
const { _count, ...metadata } = task;
|
|
534
|
+
return withTaskPreviews(withProjectGitMetadata({ ...metadata, subtaskCount: _count.subtasks }), { omitDescription: true });
|
|
535
|
+
}
|
|
536
|
+
async findSubtasks(id, params = {}) {
|
|
537
|
+
const parent = await prisma.task.findFirst({ where: { id, deletedAt: null } });
|
|
538
|
+
if (!parent)
|
|
539
|
+
throw new NotFoundError('Task', id);
|
|
540
|
+
return this.findBoard({ ...params, projectId: parent.projectId, parentTaskId: id });
|
|
502
541
|
}
|
|
503
542
|
async findBodyById(id) {
|
|
504
543
|
const task = await prisma.task.findFirst({
|
|
@@ -551,27 +590,73 @@ export class TaskService {
|
|
|
551
590
|
throw new NotFoundError('Project', projectId);
|
|
552
591
|
}
|
|
553
592
|
ensureProjectIsMutable(project, 'create tasks');
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
593
|
+
const parent = input.parentTaskId ? await prisma.task.findFirst({
|
|
594
|
+
where: { id: input.parentTaskId, projectId, deletedAt: null },
|
|
595
|
+
include: { workspaces: {
|
|
596
|
+
where: { parentWorkspaceId: null, ownerMemberId: null, status: { not: WorkspaceStatus.ABANDONED } },
|
|
597
|
+
orderBy: { createdAt: 'desc' },
|
|
598
|
+
} },
|
|
599
|
+
}) : null;
|
|
600
|
+
if (input.parentTaskId && !parent)
|
|
601
|
+
throw new NotFoundError('Parent task', input.parentTaskId);
|
|
602
|
+
if (parent?.parentTaskId)
|
|
603
|
+
throw new ValidationError('Subtasks cannot have their own subtasks');
|
|
604
|
+
const parentWorkspace = parent?.workspaces.find((workspace) => workspace.status === WorkspaceStatus.ACTIVE)
|
|
605
|
+
?? parent?.workspaces.find((workspace) => workspace.status === WorkspaceStatus.HIBERNATED)
|
|
606
|
+
?? parent?.workspaces[0];
|
|
607
|
+
const parentBranch = parentWorkspace?.branchName || parent?.baseBranch;
|
|
608
|
+
const createWithParentBranch = async () => {
|
|
609
|
+
// Resolve at task creation so delayed starts and TeamRun main workspaces
|
|
610
|
+
// cannot silently follow a later project default change. Local tasks opt out.
|
|
611
|
+
let baseBranch = null;
|
|
612
|
+
if (input.baseBranch !== null) {
|
|
613
|
+
const requestedBranch = input.baseBranch ?? parentBranch ?? ((await detectProjectGitCapability(project.repoPath)).worktreeReady ? project.mainBranch : null);
|
|
614
|
+
if (requestedBranch !== null) {
|
|
615
|
+
baseBranch = await requireLocalBaseBranch(project.repoPath, requestedBranch);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
// 自动计算 position
|
|
619
|
+
const maxPosition = await prisma.task.aggregate({
|
|
620
|
+
where: { projectId, status: TaskStatus.TODO, deletedAt: null },
|
|
621
|
+
_max: { position: true },
|
|
622
|
+
});
|
|
623
|
+
const created = await prisma.$transaction(async (tx) => {
|
|
624
|
+
// Recheck after Git validation, serialized with the deletion marker.
|
|
625
|
+
if (parent) {
|
|
626
|
+
const liveParent = await tx.task.findFirst({
|
|
627
|
+
where: { id: parent.id, projectId, deletedAt: null, project: { archivedAt: null } },
|
|
628
|
+
});
|
|
629
|
+
if (!liveParent)
|
|
630
|
+
throw new NotFoundError('Parent task', parent.id);
|
|
631
|
+
}
|
|
632
|
+
return tx.task.create({
|
|
633
|
+
data: {
|
|
634
|
+
title: normalizedInput.title,
|
|
635
|
+
description: normalizedInput.description,
|
|
636
|
+
priority: normalizedInput.priority ?? TaskPriority.NORMAL,
|
|
637
|
+
baseBranch,
|
|
638
|
+
parentTaskId: parent?.id,
|
|
639
|
+
position: (maxPosition._max.position ?? 0) + 1,
|
|
640
|
+
projectId,
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
});
|
|
644
|
+
this.eventBus.emit('task:updated', { taskId: created.id, projectId, status: created.status });
|
|
645
|
+
if (parent)
|
|
646
|
+
this.eventBus.emit('task:updated', { taskId: parent.id, projectId, status: parent.status });
|
|
647
|
+
return {
|
|
648
|
+
...created,
|
|
649
|
+
project: {
|
|
650
|
+
...project,
|
|
651
|
+
...buildProjectGitMetadata(project),
|
|
652
|
+
},
|
|
653
|
+
};
|
|
574
654
|
};
|
|
655
|
+
// Serialize branch validation and child persistence with parent workspace
|
|
656
|
+
// cleanup, so its reference becomes visible before that branch is reclaimed.
|
|
657
|
+
return parentWorkspace
|
|
658
|
+
? defaultWorkspaceLifecycleBarrier.withWorkspace(parentWorkspace.id, createWithParentBranch)
|
|
659
|
+
: createWithParentBranch();
|
|
575
660
|
}
|
|
576
661
|
/**
|
|
577
662
|
* 更新任务基本信息
|
|
@@ -594,7 +679,7 @@ export class TaskService {
|
|
|
594
679
|
this.emitTaskUpdated(id, task.projectId, updated.status, updated.priority);
|
|
595
680
|
}
|
|
596
681
|
return {
|
|
597
|
-
...updated,
|
|
682
|
+
...withoutTaskHandoff(updated),
|
|
598
683
|
project: {
|
|
599
684
|
...task.project,
|
|
600
685
|
...buildProjectGitMetadata(task.project),
|
|
@@ -639,7 +724,7 @@ export class TaskService {
|
|
|
639
724
|
// 通知前端
|
|
640
725
|
this.emitTaskUpdated(id, task.projectId, status);
|
|
641
726
|
return {
|
|
642
|
-
...updated,
|
|
727
|
+
...withoutTaskHandoff(updated),
|
|
643
728
|
project: {
|
|
644
729
|
...task.project,
|
|
645
730
|
...buildProjectGitMetadata(task.project),
|
|
@@ -676,7 +761,7 @@ export class TaskService {
|
|
|
676
761
|
this.emitTaskUpdated(id, task.projectId, status);
|
|
677
762
|
}
|
|
678
763
|
return {
|
|
679
|
-
...updated,
|
|
764
|
+
...withoutTaskHandoff(updated),
|
|
680
765
|
project: {
|
|
681
766
|
...task.project,
|
|
682
767
|
...buildProjectGitMetadata(task.project),
|
|
@@ -686,149 +771,119 @@ export class TaskService {
|
|
|
686
771
|
/**
|
|
687
772
|
* 快速删除任务
|
|
688
773
|
*
|
|
689
|
-
* 1.
|
|
690
|
-
* 2.
|
|
774
|
+
* 1. 在同一事务中标记父子 Task 为 deletedAt,并保存清理快照
|
|
775
|
+
* 2. 普通读取立即隐藏已删除的任务
|
|
691
776
|
* 3. 通过 EventBus 通知前端实时删除
|
|
692
777
|
* 4. 后台 worker 再停止 Session、删除 worktree/branch,并最终硬删除 Task
|
|
693
778
|
*/
|
|
694
|
-
async delete(id) {
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
where: { id },
|
|
698
|
-
include: { project: true },
|
|
699
|
-
});
|
|
700
|
-
if (!taskForGuard || taskForGuard.deletedAt) {
|
|
779
|
+
async delete(id, expectedSubtaskCount) {
|
|
780
|
+
const taskForGuard = await prisma.task.findUnique({ where: { id }, include: { project: true } });
|
|
781
|
+
if (!taskForGuard || taskForGuard.deletedAt)
|
|
701
782
|
throw new NotFoundError('Task', id);
|
|
702
|
-
}
|
|
703
783
|
ensureProjectIsMutable(taskForGuard.project, 'delete tasks');
|
|
784
|
+
if (expectedSubtaskCount !== undefined && expectedSubtaskCount !== await prisma.task.count({
|
|
785
|
+
where: { parentTaskId: id, deletedAt: null },
|
|
786
|
+
})) {
|
|
787
|
+
throw new ServiceError('Subtasks changed. Review the deletion confirmation again.', 'TASK_DELETE_SCOPE_CHANGED', 409);
|
|
788
|
+
}
|
|
704
789
|
const workspaceIds = await prisma.workspace.findMany({
|
|
705
|
-
where: {
|
|
790
|
+
where: { task: { OR: [{ id }, { parentTaskId: id }], deletedAt: null } },
|
|
706
791
|
select: { id: true },
|
|
707
792
|
});
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
for (const workspace of workspaceIds) {
|
|
793
|
+
const result = await defaultWorkspaceLifecycleBarrier.withWorkspaces(workspaceIds.map((workspace) => workspace.id), async () => {
|
|
794
|
+
for (const workspace of workspaceIds)
|
|
711
795
|
await this.backgroundService?.stopAllForWorkspace(workspace.id);
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
try {
|
|
736
|
-
const taskForCleanup = await prisma.task.findUnique({
|
|
737
|
-
where: { id },
|
|
738
|
-
include: {
|
|
739
|
-
project: true,
|
|
740
|
-
teamRun: {
|
|
741
|
-
include: {
|
|
742
|
-
invocations: {
|
|
743
|
-
where: { status: { in: CANCELLABLE_DELETE_INVOCATION_STATUSES } },
|
|
744
|
-
select: { id: true },
|
|
745
|
-
},
|
|
746
|
-
},
|
|
747
|
-
},
|
|
748
|
-
workspaces: {
|
|
749
|
-
include: { sessions: true },
|
|
796
|
+
// Mark the complete family and persist its recovery snapshot together.
|
|
797
|
+
// Child creation rechecks the parent inside its own transaction.
|
|
798
|
+
return prisma.$transaction(async (tx) => {
|
|
799
|
+
const parent = await tx.task.findFirst({ where: { id, deletedAt: null }, include: { project: true } });
|
|
800
|
+
if (!parent)
|
|
801
|
+
throw new NotFoundError('Task', id);
|
|
802
|
+
ensureProjectIsMutable(parent.project, 'delete tasks');
|
|
803
|
+
const family = await tx.task.findMany({
|
|
804
|
+
where: { OR: [{ id }, { parentTaskId: id }], deletedAt: null },
|
|
805
|
+
select: { id: true },
|
|
806
|
+
});
|
|
807
|
+
if (expectedSubtaskCount !== undefined && expectedSubtaskCount !== family.length - 1) {
|
|
808
|
+
throw new ServiceError('Subtasks changed. Review the deletion confirmation again.', 'TASK_DELETE_SCOPE_CHANGED', 409);
|
|
809
|
+
}
|
|
810
|
+
const taskIds = [...family.filter((task) => task.id !== id).map((task) => task.id), id];
|
|
811
|
+
await tx.task.updateMany({ where: { id: { in: taskIds } }, data: { deletedAt: new Date() } });
|
|
812
|
+
const tasks = await tx.task.findMany({
|
|
813
|
+
where: { id: { in: taskIds } },
|
|
814
|
+
include: {
|
|
815
|
+
workspaces: { include: { sessions: true } },
|
|
816
|
+
teamRun: { include: { invocations: {
|
|
817
|
+
where: { status: { in: CANCELLABLE_DELETE_INVOCATION_STATUSES } }, select: { id: true },
|
|
818
|
+
} } },
|
|
750
819
|
},
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
workingDir: getWorkspaceWorkingDir(workspace),
|
|
768
|
-
workspaceKind: workspace.workspaceKind,
|
|
769
|
-
branchName: workspace.branchName,
|
|
770
|
-
baseBranch: workspace.baseBranch,
|
|
771
|
-
// Logical completion does not close a reusable ACP adapter.
|
|
772
|
-
sessions: workspace.sessions.map((session) => ({ id: session.id })),
|
|
773
|
-
})),
|
|
774
|
-
};
|
|
775
|
-
const teamRunId = taskForCleanup.teamRun?.id;
|
|
776
|
-
const cancelledInvocationIds = taskForCleanup.teamRun?.invocations.map((invocation) => invocation.id) ?? [];
|
|
777
|
-
await prisma.$transaction(async (tx) => {
|
|
820
|
+
});
|
|
821
|
+
const tasksById = new Map(tasks.map((task) => [task.id, task]));
|
|
822
|
+
const orderedTasks = taskIds.map((taskId) => tasksById.get(taskId));
|
|
823
|
+
const snapshot = {
|
|
824
|
+
taskId: id, taskIds, projectId: parent.projectId,
|
|
825
|
+
project: { repoPath: parent.project.repoPath, mainBranch: parent.project.mainBranch },
|
|
826
|
+
workspaces: orderedTasks.flatMap((task) => task.workspaces.map((workspace) => ({
|
|
827
|
+
id: workspace.id,
|
|
828
|
+
worktreePath: workspace.worktreePath,
|
|
829
|
+
workingDir: getWorkspaceWorkingDir(workspace),
|
|
830
|
+
workspaceKind: workspace.workspaceKind,
|
|
831
|
+
branchName: workspace.branchName,
|
|
832
|
+
baseBranch: workspace.baseBranch,
|
|
833
|
+
sessions: workspace.sessions.map((session) => ({ id: session.id })),
|
|
834
|
+
}))),
|
|
835
|
+
};
|
|
778
836
|
await tx.taskCleanupJob.create({
|
|
779
|
-
data: {
|
|
780
|
-
taskId: taskForCleanup.id,
|
|
781
|
-
projectId: taskForCleanup.projectId,
|
|
782
|
-
payload: JSON.stringify(snapshot),
|
|
783
|
-
},
|
|
837
|
+
data: { taskId: id, projectId: parent.projectId, payload: JSON.stringify(snapshot) },
|
|
784
838
|
});
|
|
785
|
-
|
|
839
|
+
const teamRunIds = tasks.flatMap((task) => task.teamRun ? [task.teamRun.id] : []);
|
|
840
|
+
if (teamRunIds.length) {
|
|
786
841
|
await tx.workRequest.updateMany({
|
|
787
|
-
where: {
|
|
788
|
-
teamRunId,
|
|
789
|
-
status: { in: CANCELLABLE_DELETE_WORK_REQUEST_STATUSES },
|
|
790
|
-
},
|
|
842
|
+
where: { teamRunId: { in: teamRunIds }, status: { in: CANCELLABLE_DELETE_WORK_REQUEST_STATUSES } },
|
|
791
843
|
data: { status: 'CANCELLED' },
|
|
792
844
|
});
|
|
793
845
|
await tx.agentInvocation.updateMany({
|
|
794
|
-
where: {
|
|
795
|
-
|
|
796
|
-
status: { in: CANCELLABLE_DELETE_INVOCATION_STATUSES },
|
|
797
|
-
},
|
|
798
|
-
data: {
|
|
799
|
-
status: 'CANCELLED',
|
|
800
|
-
nextRoomReplyReminderAt: null,
|
|
801
|
-
},
|
|
846
|
+
where: { teamRunId: { in: teamRunIds }, status: { in: CANCELLABLE_DELETE_INVOCATION_STATUSES } },
|
|
847
|
+
data: { status: 'CANCELLED', nextRoomReplyReminderAt: null },
|
|
802
848
|
});
|
|
803
849
|
}
|
|
850
|
+
return {
|
|
851
|
+
taskIds, projectId: parent.projectId,
|
|
852
|
+
invocationIds: tasks.flatMap((task) => task.teamRun?.invocations.map((invocation) => invocation.id) ?? []),
|
|
853
|
+
};
|
|
804
854
|
});
|
|
805
|
-
cleanupJobCreated = true;
|
|
806
|
-
deleteResult = {
|
|
807
|
-
projectId: taskForCleanup.projectId,
|
|
808
|
-
cancelledInvocationIds,
|
|
809
|
-
};
|
|
810
|
-
}
|
|
811
|
-
catch (error) {
|
|
812
|
-
if (!cleanupJobCreated) {
|
|
813
|
-
await prisma.task.updateMany({
|
|
814
|
-
where: { id, deletedAt },
|
|
815
|
-
data: { deletedAt: null },
|
|
816
|
-
}).catch(() => {
|
|
817
|
-
// If rollback fails, leave the task hidden rather than masking the original error.
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
throw error;
|
|
821
|
-
}
|
|
822
|
-
for (const invocationId of deleteResult.cancelledInvocationIds) {
|
|
823
|
-
defaultTeamLockService.releaseByOwner(invocationId);
|
|
824
|
-
}
|
|
825
|
-
this.eventBus.emit('task:deleted', {
|
|
826
|
-
taskId: id,
|
|
827
|
-
projectId: deleteResult.projectId,
|
|
828
855
|
});
|
|
856
|
+
for (const invocationId of result.invocationIds)
|
|
857
|
+
defaultTeamLockService.releaseByOwner(invocationId);
|
|
858
|
+
for (const taskId of result.taskIds)
|
|
859
|
+
this.eventBus.emit('task:deleted', { taskId, projectId: result.projectId });
|
|
829
860
|
this.cleanupService?.trigger();
|
|
830
861
|
return true;
|
|
831
862
|
}
|
|
863
|
+
async getCleanupStatus(taskId) {
|
|
864
|
+
const job = await prisma.taskCleanupJob.findFirst({
|
|
865
|
+
where: { taskId }, orderBy: { createdAt: 'desc' },
|
|
866
|
+
select: { taskId: true, status: true, lastError: true, nextRetryAt: true },
|
|
867
|
+
});
|
|
868
|
+
if (!job)
|
|
869
|
+
throw new NotFoundError('Task cleanup', taskId);
|
|
870
|
+
return job;
|
|
871
|
+
}
|
|
872
|
+
async retryCleanup(taskId) {
|
|
873
|
+
const job = await prisma.taskCleanupJob.findFirst({ where: { taskId }, orderBy: { createdAt: 'desc' } });
|
|
874
|
+
if (!job)
|
|
875
|
+
throw new NotFoundError('Task cleanup', taskId);
|
|
876
|
+
const project = await prisma.project.findUnique({ where: { id: job.projectId } });
|
|
877
|
+
if (!project)
|
|
878
|
+
throw new NotFoundError('Project', job.projectId);
|
|
879
|
+
ensureProjectIsMutable(project, 'retry task cleanup');
|
|
880
|
+
await prisma.taskCleanupJob.updateMany({
|
|
881
|
+
where: { id: job.id, status: 'FAILED' },
|
|
882
|
+
data: { status: 'PENDING', attempts: 0, lastError: null, nextRetryAt: null },
|
|
883
|
+
});
|
|
884
|
+
this.cleanupService?.trigger();
|
|
885
|
+
return this.getCleanupStatus(taskId);
|
|
886
|
+
}
|
|
832
887
|
/**
|
|
833
888
|
* 获取项目的任务统计
|
|
834
889
|
*/
|