agent-tower 0.7.4-beta.0 → 0.7.4-beta.2
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__/codex-mcp-windows.test.d.ts +2 -0
- package/dist/executors/__tests__/codex-mcp-windows.test.d.ts.map +1 -0
- package/dist/executors/__tests__/codex-mcp-windows.test.js +128 -0
- package/dist/executors/__tests__/codex-mcp-windows.test.js.map +1 -0
- package/dist/executors/__tests__/codex.executor.test.js +394 -1
- package/dist/executors/__tests__/codex.executor.test.js.map +1 -1
- package/dist/executors/codex.executor.d.ts +6 -6
- package/dist/executors/codex.executor.d.ts.map +1 -1
- package/dist/executors/codex.executor.js +118 -32
- package/dist/executors/codex.executor.js.map +1 -1
- package/dist/mcp/tools/tasks.js +3 -3
- package/dist/mcp/tools/tasks.js.map +1 -1
- package/dist/mcp/types.js +2 -2
- 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__/acp-process-manager.test.js +65 -0
- package/dist/runtime/__tests__/acp-process-manager.test.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/acp/agents/pi-coding-agent.d.ts.map +1 -1
- package/dist/runtime/acp/agents/pi-coding-agent.js +3 -0
- package/dist/runtime/acp/agents/pi-coding-agent.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 +128 -13
- package/dist/services/__tests__/task.service.test.js.map +1 -1
- package/dist/services/__tests__/workspace.service.test.js +95 -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-display-state.d.ts +10 -0
- package/dist/services/task-display-state.d.ts.map +1 -0
- package/dist/services/task-display-state.js +45 -0
- package/dist/services/task-display-state.js.map +1 -0
- package/dist/services/task.service.d.ts +20 -1
- package/dist/services/task.service.d.ts.map +1 -1
- package/dist/services/task.service.js +134 -101
- 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 +162 -89
- package/dist/services/workspace.service.js.map +1 -1
- package/dist/web/assets/{AgentDemoPage-JXetlNBf.js → AgentDemoPage-CrkoVCOZ.js} +1 -1
- package/dist/web/assets/{AgentEnvironmentSettingsPage-CdYyUCwJ.js → AgentEnvironmentSettingsPage-BRihy3_Q.js} +1 -1
- package/dist/web/assets/{AttachmentPreview-DMS-PM-1.js → AttachmentPreview-B9z1Mxb-.js} +2 -2
- package/dist/web/assets/{BranchSelect-BAq4L2ZS.js → BranchSelect-Bo5uhKCt.js} +1 -1
- package/dist/web/assets/{BrandLogo--kWXXJtZ.js → BrandLogo-DEL42B23.js} +1 -1
- package/dist/web/assets/{ConversationPage-CvC4RyB5.js → ConversationPage-C46RuN9U.js} +1 -1
- package/dist/web/assets/{CreateTaskInput-DjVxCAfc.js → CreateTaskInput-4aHJpsfL.js} +1 -1
- package/dist/web/assets/{DemoPage-cDVTGOp8.js → DemoPage-CAZqNag-.js} +1 -1
- package/dist/web/assets/{DesignSystemPage-BI54IkKi.js → DesignSystemPage-CjCYC24B.js} +1 -1
- package/dist/web/assets/{ExecutionPermissionSelector-f1UYIm1z.js → ExecutionPermissionSelector-CJgc_EVo.js} +1 -1
- package/dist/web/assets/{GeneralSettingsPage-C0yto6C_.js → GeneralSettingsPage-DFT7Cubi.js} +1 -1
- package/dist/web/assets/{LoadingPreviewPage-BiJSaHUi.js → LoadingPreviewPage-CB4VDPAZ.js} +1 -1
- package/dist/web/assets/{McpSettingsPage-BbHwZtyj.js → McpSettingsPage-CgiyGvkH.js} +1 -1
- package/dist/web/assets/{MemberAvatar-BLezO3vS.js → MemberAvatar-Cfz8LU6k.js} +1 -1
- package/dist/web/assets/MobileTaskDetail-yZNyZMQt.js +3 -0
- package/dist/web/assets/{NotificationSettingsPage-CiKoL2Kv.js → NotificationSettingsPage-BSMJ45yx.js} +1 -1
- package/dist/web/assets/{ProfileSettingsPage-DCB48cPS.js → ProfileSettingsPage-BwNThOnH.js} +1 -1
- package/dist/web/assets/ProjectKanbanPage-DtZW0bOh.js +14 -0
- package/dist/web/assets/{ProjectSettingsPage-COvIVq1h.js → ProjectSettingsPage-CMBMkbgI.js} +1 -1
- package/dist/web/assets/{ProviderSettingsPage-CPuJcZDg.js → ProviderSettingsPage-D759BSRa.js} +2 -2
- package/dist/web/assets/{SettingsMasterDetail-Cv7YaRJB.js → SettingsMasterDetail-DpYUTM-Q.js} +1 -1
- package/dist/web/assets/TaskDetail-rRHGOvSw.js +1 -0
- package/dist/web/assets/{TaskHandoffPanel-CxH3Mgyd.js → TaskHandoffPanel-DBcC1xQW.js} +24 -24
- package/dist/web/assets/{TeamSettingsPage-D-XDefNd.js → TeamSettingsPage-BszQfKp0.js} +1 -1
- package/dist/web/assets/{TranslationSettingsPage-BPHI-SZW.js → TranslationSettingsPage-lLaxWCy3.js} +1 -1
- package/dist/web/assets/{arc-CC81aLuf.js → arc-DtgXFw4D.js} +1 -1
- package/dist/web/assets/{architectureDiagram-3BPJPVTR-DL08XGaN.js → architectureDiagram-3BPJPVTR-B3p3EMX1.js} +1 -1
- package/dist/web/assets/{at-sign-DYPIlD6D.js → at-sign-B8rXgKEE.js} +1 -1
- package/dist/web/assets/{blockDiagram-GPEHLZMM-B4IW5WxI.js → blockDiagram-GPEHLZMM-BmekCfr0.js} +1 -1
- package/dist/web/assets/{c4Diagram-AAUBKEIU-Cj4d_FqK.js → c4Diagram-AAUBKEIU-CF6hJhuL.js} +1 -1
- package/dist/web/assets/channel-BdK_fAel.js +1 -0
- package/dist/web/assets/check-DwK55QS2.js +1 -0
- package/dist/web/assets/{chevron-down-DNhYsNAt.js → chevron-down-Dftc5hr4.js} +1 -1
- package/dist/web/assets/{chevron-up-CjrLieBR.js → chevron-up-CKRxN6zX.js} +1 -1
- package/dist/web/assets/{chip-Cf92J-pQ.js → chip-ZTBHcXU2.js} +1 -1
- package/dist/web/assets/{chunk-2J33WTMH-DeCj8QSD.js → chunk-2J33WTMH-Bjelop4M.js} +1 -1
- package/dist/web/assets/{chunk-4BX2VUAB-k-6rzQmQ.js → chunk-4BX2VUAB-B1rJPbL6.js} +1 -1
- package/dist/web/assets/{chunk-55IACEB6-qMTCQ5bX.js → chunk-55IACEB6-B5qfH7Gj.js} +1 -1
- package/dist/web/assets/{chunk-727SXJPM-CMnu18d1.js → chunk-727SXJPM-ClFMbgrH.js} +1 -1
- package/dist/web/assets/{chunk-AQP2D5EJ-C0mFbUMn.js → chunk-AQP2D5EJ-BMFjTO7B.js} +1 -1
- package/dist/web/assets/{chunk-FMBD7UC4-u6-_M137.js → chunk-FMBD7UC4-Pr1oOFfR.js} +1 -1
- package/dist/web/assets/{chunk-ND2GUHAM-DHrIE_8H.js → chunk-ND2GUHAM-BPm4TRpO.js} +1 -1
- package/dist/web/assets/{chunk-QZHKN3VN-aTyC0wZq.js → chunk-QZHKN3VN-DCPA_U0M.js} +1 -1
- package/dist/web/assets/classDiagram-4FO5ZUOK-CFzCq0ml.js +1 -0
- package/dist/web/assets/classDiagram-v2-Q7XG4LA2-CFzCq0ml.js +1 -0
- package/dist/web/assets/{code-block-OCS4YCEC-CBIOQOMH.js → code-block-OCS4YCEC-Cx53F4d7.js} +1 -1
- package/dist/web/assets/{confirm-dialog-DWeBZLJW.js → confirm-dialog-C_j-w4TS.js} +1 -1
- package/dist/web/assets/{content-JM9E1MeD.js → content-DeIfej_n.js} +2 -2
- package/dist/web/assets/{copy-D0gl9kF8.js → copy-B-BaLIlh.js} +1 -1
- package/dist/web/assets/{cose-bilkent-S5V4N54A-xLyliSgU.js → cose-bilkent-S5V4N54A-gIys-0yu.js} +1 -1
- package/dist/web/assets/{cssMode-DO5UnQ64.js → cssMode-xF0bjbbU.js} +1 -1
- package/dist/web/assets/{dagre-BM42HDAG-CbNpoO2d.js → dagre-BM42HDAG-Bwc3Ntc-.js} +1 -1
- package/dist/web/assets/{diagram-2AECGRRQ-CG3hKxAX.js → diagram-2AECGRRQ-zkydBsMT.js} +1 -1
- package/dist/web/assets/{diagram-5GNKFQAL-mQu9M28s.js → diagram-5GNKFQAL-p9As3QtI.js} +1 -1
- package/dist/web/assets/{diagram-KO2AKTUF-BSeEp_Uw.js → diagram-KO2AKTUF-N_pUU-iU.js} +1 -1
- package/dist/web/assets/{diagram-LMA3HP47-D6yRdao-.js → diagram-LMA3HP47-CA2rl4Gq.js} +1 -1
- package/dist/web/assets/{diagram-OG6HWLK6-BUBUW9wD.js → diagram-OG6HWLK6-BoXxBlUC.js} +1 -1
- package/dist/web/assets/{dialog-D1lkhqVL.js → dialog-CnjWIdWp.js} +1 -1
- package/dist/web/assets/{erDiagram-TEJ5UH35-BQSZgRqq.js → erDiagram-TEJ5UH35-CVBHQTCN.js} +1 -1
- package/dist/web/assets/{file-BijjwxRR.js → file-jMLGlXos.js} +1 -1
- package/dist/web/assets/{flowDiagram-I6XJVG4X-D-eqyr5Y.js → flowDiagram-I6XJVG4X-kK7iKiAv.js} +1 -1
- package/dist/web/assets/{folder-picker-Czxm0_S9.js → folder-picker-CR8LiSQf.js} +1 -1
- package/dist/web/assets/{freemarker2-B4RvEa_U.js → freemarker2-CTMcTiBd.js} +1 -1
- package/dist/web/assets/{ganttDiagram-6RSMTGT7-BWGkCt_x.js → ganttDiagram-6RSMTGT7-CJVvLTkW.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-PVQCEYII-DGVc49pR.js → gitGraphDiagram-PVQCEYII-D8uj_SCw.js} +1 -1
- package/dist/web/assets/{globe-Ce01-45x.js → globe-FFVKce9-.js} +1 -1
- package/dist/web/assets/{handlebars-oyT7drqS.js → handlebars-NHxbmOs3.js} +1 -1
- package/dist/web/assets/{html-CxxWf2Qk.js → html-oFqzz32q.js} +1 -1
- package/dist/web/assets/{htmlMode-RfAHh5Jj.js → htmlMode-sgeetciK.js} +1 -1
- package/dist/web/assets/index-408ws6FY.css +1 -0
- package/dist/web/assets/index-9KNEuwGB.js +122 -0
- package/dist/web/assets/{index-hpHE1jXY.js → index-BzqyZD7L.js} +1 -1
- package/dist/web/assets/{index-DWrSDMX2.js → index-C5lNOKJb.js} +1 -1
- package/dist/web/assets/{index-Disv1kQS.js → index-C9vIrQ3Q.js} +1 -1
- package/dist/web/assets/{index-Pt4TsHjm.js → index-Cm_7q6ju.js} +1 -1
- package/dist/web/assets/{index-Dh-tgeaL.js → index-CwfWGzxi.js} +4 -4
- package/dist/web/assets/{index-DyJfPc4O.js → index-D8TNxwWk.js} +1 -1
- package/dist/web/assets/{index-T38iVLEb.js → index-biTPUXAe.js} +1 -1
- package/dist/web/assets/{index-BMZFF1UJ.js → index-gqrRO6ZJ.js} +1 -1
- package/dist/web/assets/{infoDiagram-5YYISTIA-DLPs3dV_.js → infoDiagram-5YYISTIA-CExRZE3Y.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-YF4QCWOH-d_OrnwDY.js → ishikawaDiagram-YF4QCWOH-CsqM2X33.js} +1 -1
- package/dist/web/assets/javascript-COt-61wn.js +1 -0
- package/dist/web/assets/{journeyDiagram-JHISSGLW-EtU1st_0.js → journeyDiagram-JHISSGLW-DX9OMhPD.js} +1 -1
- package/dist/web/assets/{jsonMode-Bqh5vIxx.js → jsonMode-VQg5cpLV.js} +1 -1
- package/dist/web/assets/{kanban-definition-UN3LZRKU-ZWzUnsFK.js → kanban-definition-UN3LZRKU-CWHMx6vc.js} +1 -1
- package/dist/web/assets/{kbd-IjDGsZ2B.js → kbd-GGofKfKu.js} +1 -1
- package/dist/web/assets/{key-round-CbnAuUxp.js → key-round-p-Fpykfj.js} +1 -1
- package/dist/web/assets/{layers-Pdy9vZ6K.js → layers-pbPa_eZq.js} +1 -1
- package/dist/web/assets/{linear-D7n23wcA.js → linear-9VwGhaEA.js} +1 -1
- package/dist/web/assets/{link-Bl1ZbjFh.js → link-CG4UwIS1.js} +1 -1
- package/dist/web/assets/{liquid-Ds47iVLN.js → liquid-SJInUaiB.js} +1 -1
- package/dist/web/assets/{lspLanguageFeatures-Dcch3bsp.js → lspLanguageFeatures-DJOdVyBc.js} +1 -1
- package/dist/web/assets/{mdx-CM7ky-2B.js → mdx-CToYr-3b.js} +1 -1
- package/dist/web/assets/{menu-DubntFHq.js → menu-BFQ1mKU7.js} +1 -1
- package/dist/web/assets/{mermaid-NOHMQCX5-nBsnjgeU.js → mermaid-NOHMQCX5-BOViobLk.js} +58 -58
- package/dist/web/assets/{message-square-BE-pW0m_.js → message-square-BYZsUsLz.js} +1 -1
- package/dist/web/assets/{mindmap-definition-RKZ34NQL-ClHORNTt.js → mindmap-definition-RKZ34NQL-BTcDnn6X.js} +1 -1
- package/dist/web/assets/{modal-CHLtZWvx.js → modal-BT_7Lhtw.js} +1 -1
- package/dist/web/assets/{monaco-BbAmalE2.js → monaco-DUftz48_.js} +3 -3
- package/dist/web/assets/{nav-row-DH7rNq1V.js → nav-row-BjDckaPC.js} +1 -1
- package/dist/web/assets/{paperclip-YP3Bk1lI.js → paperclip-CFAH5neE.js} +1 -1
- package/dist/web/assets/{pencil-BFDuhbtW.js → pencil-Bg9TWm_-.js} +1 -1
- package/dist/web/assets/{people-DEeNaaLt.js → people-BIQwajM2.js} +1 -1
- package/dist/web/assets/{pieDiagram-4H26LBE5-BUOaKIyP.js → pieDiagram-4H26LBE5-CRjqdnP8.js} +1 -1
- package/dist/web/assets/{popover-CUmBEXxL.js → popover-DpYhrrCE.js} +1 -1
- package/dist/web/assets/{python-BODTtU6m.js → python-DbmUucgH.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-W4KKPZXB-Caezg-U2.js → quadrantDiagram-W4KKPZXB-uvA8TYC6.js} +1 -1
- package/dist/web/assets/{razor-CHm8DY1p.js → razor-B0AJhw7W.js} +1 -1
- package/dist/web/assets/{requirementDiagram-4Y6WPE33-BtdP3Ka6.js → requirementDiagram-4Y6WPE33-BWLugaKX.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-5OEKKPKP-Bv74oA-n.js → sankeyDiagram-5OEKKPKP-DHrbZZv8.js} +1 -1
- package/dist/web/assets/{search-ClmOQd4H.js → search-BH8nze-X.js} +1 -1
- package/dist/web/assets/{select-BB7QG08o.js → select-BegY9RkP.js} +1 -1
- package/dist/web/assets/{select-CYtYPr-c.js → select-EcEr5QSS.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-3UESZ5HK-DuNPl-dg.js → sequenceDiagram-3UESZ5HK-CKwEKcTn.js} +1 -1
- package/dist/web/assets/{server-bEB_DY55.js → server-BxEUjx0l.js} +1 -1
- package/dist/web/assets/{stateDiagram-AJRCARHV-B72HAgBJ.js → stateDiagram-AJRCARHV-vhgmSpa9.js} +1 -1
- package/dist/web/assets/stateDiagram-v2-BHNVJYJU-C0z5OTY4.js +1 -0
- package/dist/web/assets/{textarea-BqYPvoO-.js → textarea-CvoGGROs.js} +1 -1
- package/dist/web/assets/{timeline-definition-PNZ67QCA-DTmHUgmQ.js → timeline-definition-PNZ67QCA-bSDKcwDZ.js} +1 -1
- package/dist/web/assets/{toggles-a5fkwT_D.js → toggles-CEDUD08u.js} +1 -1
- package/dist/web/assets/{tooltip-DuyJMci9.js → tooltip-CKaUbVZ7.js} +1 -1
- package/dist/web/assets/{track-DCjyrv3n.js → track-1qw2cvTy.js} +1 -1
- package/dist/web/assets/{trash-2-CIyBqaVy.js → trash-2-ChiXon87.js} +1 -1
- package/dist/web/assets/{tsMode-C1UXAkMh.js → tsMode-bnV8W2Ru.js} +1 -1
- package/dist/web/assets/{typescript-Biht2wHb.js → typescript-d1MHIeEx.js} +1 -1
- package/dist/web/assets/{upload-D05XS5-G.js → upload-CQ-cQaOz.js} +1 -1
- package/dist/web/assets/{use-profiles-CrWTyz1G.js → use-profiles-CJzoqarX.js} +1 -1
- package/dist/web/assets/{use-providers-Dv1Nk6s7.js → use-providers-S29TCag2.js} +1 -1
- package/dist/web/assets/{use-translation-settings-CcUnipVO.js → use-translation-settings-DifNJaCu.js} +1 -1
- package/dist/web/assets/{useNormalizedLogs-D9W1cT4R.js → useNormalizedLogs-BVdY8qDk.js} +1 -1
- package/dist/web/assets/{useTokenUsage-CZ5mDshD.js → useTokenUsage-nh_KDA3q.js} +1 -1
- package/dist/web/assets/{vennDiagram-CIIHVFJN-ByoNydXe.js → vennDiagram-CIIHVFJN-D7QbDYzC.js} +1 -1
- package/dist/web/assets/{wardley-L42UT6IY-BqdMkOLl.js → wardley-L42UT6IY-C9aHlNVa.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-YWT4CUSO-AO22HrEF.js → wardleyDiagram-YWT4CUSO-CZhubDRC.js} +1 -1
- package/dist/web/assets/{xml-NLGqNFDv.js → xml-DAKKxHAr.js} +1 -1
- package/dist/web/assets/{xychartDiagram-2RQKCTM6-vzPgjgqW.js → xychartDiagram-2RQKCTM6-BgDlpFBh.js} +1 -1
- package/dist/web/assets/{yaml-AWlGS_Ig.js → yaml-D_hSVVz0.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 +20 -4
- 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
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import prismaPkg from '@prisma/client';
|
|
2
|
+
import { TaskStatus } from '@agent-tower/shared';
|
|
3
|
+
const { Prisma } = prismaPkg;
|
|
4
|
+
// Correlated to the outer `task` row. The supported hierarchy has three levels;
|
|
5
|
+
// use the parentTaskId index, including children outside the requested page.
|
|
6
|
+
// Keep project/status checks in the projection: putting them in WHERE makes
|
|
7
|
+
// SQLite prefer the project/status index and scan the project for every task.
|
|
8
|
+
function descendantCount(status) {
|
|
9
|
+
return Prisma.sql `(
|
|
10
|
+
SELECT COALESCE(SUM(CASE
|
|
11
|
+
WHEN descendant."projectId" = task."projectId" AND descendant."status" = ${status} THEN 1
|
|
12
|
+
ELSE 0
|
|
13
|
+
END), 0) FROM "Task" descendant
|
|
14
|
+
WHERE descendant."deletedAt" IS NULL
|
|
15
|
+
AND descendant."parentTaskId" IN (
|
|
16
|
+
SELECT task."id"
|
|
17
|
+
UNION ALL
|
|
18
|
+
SELECT CASE WHEN child."projectId" = task."projectId" THEN child."id" END FROM "Task" child
|
|
19
|
+
WHERE child."parentTaskId" = task."id"
|
|
20
|
+
AND child."deletedAt" IS NULL
|
|
21
|
+
)
|
|
22
|
+
)`;
|
|
23
|
+
}
|
|
24
|
+
const runningDescendantCount = descendantCount(TaskStatus.IN_PROGRESS);
|
|
25
|
+
const reviewDescendantCount = descendantCount(TaskStatus.IN_REVIEW);
|
|
26
|
+
// Keep the persisted status for writes and runtime lifecycle decisions.
|
|
27
|
+
// Reads, filters and statistics share this display-only expression.
|
|
28
|
+
export const taskDisplayStatusSql = Prisma.sql `CASE
|
|
29
|
+
WHEN task."status" = ${TaskStatus.IN_PROGRESS} OR ${runningDescendantCount} > 0 THEN ${TaskStatus.IN_PROGRESS}
|
|
30
|
+
WHEN task."status" = ${TaskStatus.IN_REVIEW} OR ${reviewDescendantCount} > 0 THEN ${TaskStatus.IN_REVIEW}
|
|
31
|
+
ELSE task."status"
|
|
32
|
+
END`;
|
|
33
|
+
export const taskDisplayColumnsSql = Prisma.sql `
|
|
34
|
+
${taskDisplayStatusSql} AS "displayStatus",
|
|
35
|
+
${runningDescendantCount} AS "runningDescendantCount",
|
|
36
|
+
${reviewDescendantCount} AS "reviewDescendantCount"
|
|
37
|
+
`;
|
|
38
|
+
export function mapTaskDisplayState(row) {
|
|
39
|
+
return {
|
|
40
|
+
displayStatus: row.displayStatus,
|
|
41
|
+
runningDescendantCount: Number(row.runningDescendantCount),
|
|
42
|
+
reviewDescendantCount: Number(row.reviewDescendantCount),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=task-display-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-display-state.js","sourceRoot":"","sources":["../../src/services/task-display-state.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAyB,MAAM,qBAAqB,CAAC;AAExE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;AAE7B,gFAAgF;AAChF,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,SAAS,eAAe,CAAC,MAAkB;IACzC,OAAO,MAAM,CAAC,GAAG,CAAA;;iFAE8D,MAAM;;;;;;;;;;;IAWnF,CAAC;AACL,CAAC;AAED,MAAM,sBAAsB,GAAG,eAAe,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACvE,MAAM,qBAAqB,GAAG,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAEpE,wEAAwE;AACxE,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAA;yBACrB,UAAU,CAAC,WAAW,OAAO,sBAAsB,aAAa,UAAU,CAAC,WAAW;yBACtF,UAAU,CAAC,SAAS,OAAO,qBAAqB,aAAa,UAAU,CAAC,SAAS;;IAEtG,CAAC;AAEL,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAA;IAC3C,oBAAoB;IACpB,sBAAsB;IACtB,qBAAqB;CACxB,CAAC;AAQF,MAAM,UAAU,mBAAmB,CAAC,GAAmB;IACrD,OAAO;QACL,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,sBAAsB,EAAE,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC;QAC1D,qBAAqB,EAAE,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -5,6 +5,7 @@ import type { SessionManager } from './session-manager.js';
|
|
|
5
5
|
import type { TaskCleanupService } from './task-cleanup.service.js';
|
|
6
6
|
import type { WorkspaceBackgroundService } from './workspace-background-service.service.js';
|
|
7
7
|
import type { CreateTaskInput, TaskBoardResponse } from '@agent-tower/shared';
|
|
8
|
+
import { type TaskDeletionScope } from '@agent-tower/shared';
|
|
8
9
|
interface UpdateTaskInput {
|
|
9
10
|
title?: string;
|
|
10
11
|
description?: string;
|
|
@@ -27,6 +28,8 @@ export declare class TaskService {
|
|
|
27
28
|
private readonly cleanupService;
|
|
28
29
|
private readonly backgroundService?;
|
|
29
30
|
constructor(eventBus: EventBus, sessionManager: SessionManager, cleanupService?: Pick<TaskCleanupService, 'trigger'> | undefined, backgroundService?: Pick<WorkspaceBackgroundService, "stopAllForWorkspace"> | undefined);
|
|
31
|
+
/** Page and count using the same display status, before loading associations. */
|
|
32
|
+
private findPage;
|
|
30
33
|
/**
|
|
31
34
|
* Compact board read model. Query count remains fixed as project/task counts grow.
|
|
32
35
|
*/
|
|
@@ -36,9 +39,13 @@ export declare class TaskService {
|
|
|
36
39
|
*/
|
|
37
40
|
findByProjectId(projectId: string, params?: FindTasksParams): Promise<{
|
|
38
41
|
data: (Omit<Omit<{
|
|
42
|
+
subtaskCount: number;
|
|
43
|
+
displayStatus: import("@agent-tower/shared").TaskStatus;
|
|
44
|
+
runningDescendantCount: number;
|
|
45
|
+
reviewDescendantCount: number;
|
|
46
|
+
status: TaskStatus;
|
|
39
47
|
id: string;
|
|
40
48
|
createdAt: Date;
|
|
41
|
-
status: string;
|
|
42
49
|
priority: number;
|
|
43
50
|
updatedAt: Date;
|
|
44
51
|
project: {
|
|
@@ -96,7 +103,9 @@ export declare class TaskService {
|
|
|
96
103
|
commitMessage: string | null;
|
|
97
104
|
previewTarget: string | null;
|
|
98
105
|
hibernatedAt: Date | null;
|
|
106
|
+
cleanedAt: Date | null;
|
|
99
107
|
})[];
|
|
108
|
+
ancestorIds: string[];
|
|
100
109
|
}, "project" | "handoff"> & {
|
|
101
110
|
project: {
|
|
102
111
|
name: string;
|
|
@@ -193,7 +202,9 @@ export declare class TaskService {
|
|
|
193
202
|
commitMessage: string | null;
|
|
194
203
|
previewTarget: string | null;
|
|
195
204
|
hibernatedAt: Date | null;
|
|
205
|
+
cleanedAt: Date | null;
|
|
196
206
|
})[];
|
|
207
|
+
ancestorIds: string[];
|
|
197
208
|
}, "project" | "handoff"> & {
|
|
198
209
|
project: {
|
|
199
210
|
name: string;
|
|
@@ -219,6 +230,11 @@ export declare class TaskService {
|
|
|
219
230
|
titlePreview: string;
|
|
220
231
|
contentPreview: string | undefined;
|
|
221
232
|
isTruncated: boolean;
|
|
233
|
+
} & {
|
|
234
|
+
displayStatus: import("@agent-tower/shared").TaskStatus;
|
|
235
|
+
runningDescendantCount: number;
|
|
236
|
+
reviewDescendantCount: number;
|
|
237
|
+
status: TaskStatus;
|
|
222
238
|
}>;
|
|
223
239
|
findSubtasks(id: string, params?: FindTasksParams): Promise<TaskBoardResponse>;
|
|
224
240
|
findBodyById(id: string): Promise<{
|
|
@@ -236,6 +252,7 @@ export declare class TaskService {
|
|
|
236
252
|
* - 自动计算 position(同状态下最大 position + 1)
|
|
237
253
|
*/
|
|
238
254
|
create(projectId: string, input: CreateTaskInput): Promise<{
|
|
255
|
+
ancestorIds: string[];
|
|
239
256
|
project: {
|
|
240
257
|
isGitRepo: boolean;
|
|
241
258
|
worktreeReady: boolean;
|
|
@@ -413,6 +430,7 @@ export declare class TaskService {
|
|
|
413
430
|
* 4. 后台 worker 再停止 Session、删除 worktree/branch,并最终硬删除 Task
|
|
414
431
|
*/
|
|
415
432
|
delete(id: string, expectedSubtaskCount?: number): Promise<boolean>;
|
|
433
|
+
getDeletionScope(id: string): Promise<TaskDeletionScope>;
|
|
416
434
|
getCleanupStatus(taskId: string): Promise<{
|
|
417
435
|
status: string;
|
|
418
436
|
lastError: string | null;
|
|
@@ -482,6 +500,7 @@ export declare class TaskService {
|
|
|
482
500
|
projectId: string;
|
|
483
501
|
parentTaskId: string | null;
|
|
484
502
|
}>;
|
|
503
|
+
private withDisplayState;
|
|
485
504
|
/**
|
|
486
505
|
* 发射 task:updated 事件,通知 SocketGateway 转发到前端
|
|
487
506
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task.service.d.ts","sourceRoot":"","sources":["../../src/services/task.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAiE,MAAM,mBAAmB,CAAC;AAQ9G,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,2BAA2B,CAAC;AACzF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAK5F,OAAO,KAAK,EAAE,eAAe,EAAiB,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"task.service.d.ts","sourceRoot":"","sources":["../../src/services/task.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,12 +8,15 @@ import { defaultWorkspaceLifecycleBarrier } from './workspace-lifecycle-barrier.
|
|
|
8
8
|
import { ensureProjectIsMutable, getStoredProjectGitCapability, detectProjectGitCapability } from './project-guards.js';
|
|
9
9
|
import { requireLocalBaseBranch } from '../git/base-branch.js';
|
|
10
10
|
import { defaultTeamLockService } from './team-lock.service.js';
|
|
11
|
-
import { TaskPriority } from '@agent-tower/shared';
|
|
11
|
+
import { TaskPriority, MAX_TASK_DEPTH } from '@agent-tower/shared';
|
|
12
12
|
import prismaPkg from '@prisma/client';
|
|
13
|
+
import { taskDisplayColumnsSql, taskDisplayStatusSql, mapTaskDisplayState } from './task-display-state.js';
|
|
13
14
|
const { Prisma } = prismaPkg;
|
|
14
15
|
const taskBoardColumns = Prisma.sql `
|
|
15
16
|
task."id", task."projectId", task."title", task."status", task."priority",
|
|
16
17
|
task."position", task."updatedAt", task."parentTaskId",
|
|
18
|
+
${taskDisplayColumnsSql},
|
|
19
|
+
(SELECT parent."parentTaskId" FROM "Task" parent WHERE parent."id" = task."parentTaskId") AS "grandparentTaskId",
|
|
17
20
|
(SELECT COUNT(*) FROM "Task" child WHERE child."parentTaskId" = task."id" AND child."deletedAt" IS NULL) AS "subtaskCount",
|
|
18
21
|
(SELECT COUNT(*) FROM "Task" child WHERE child."parentTaskId" = task."id" AND child."deletedAt" IS NULL AND child."status" = 'IN_PROGRESS') AS "runningSubtaskCount"
|
|
19
22
|
`;
|
|
@@ -49,6 +52,19 @@ const visibleSessionSummary = {
|
|
|
49
52
|
updatedAt: true,
|
|
50
53
|
},
|
|
51
54
|
};
|
|
55
|
+
// The schema stores adjacency; these bounded reads cover the supported three levels.
|
|
56
|
+
function subtreeWhere(id, projectId) {
|
|
57
|
+
return { deletedAt: null, ...(projectId ? { projectId } : {}), OR: [
|
|
58
|
+
{ id }, { parentTaskId: id }, { parentTask: { parentTaskId: id, deletedAt: null } },
|
|
59
|
+
] };
|
|
60
|
+
}
|
|
61
|
+
function ancestorIds(parentTaskId, grandparentTaskId) {
|
|
62
|
+
return [grandparentTaskId, parentTaskId].filter((id) => Boolean(id));
|
|
63
|
+
}
|
|
64
|
+
function withHierarchy(task) {
|
|
65
|
+
const { parentTask, ...metadata } = task;
|
|
66
|
+
return { ...metadata, ancestorIds: ancestorIds(task.parentTaskId, parentTask?.parentTaskId) };
|
|
67
|
+
}
|
|
52
68
|
function sliceAtCompleteCodePointBoundary(value, maxLength) {
|
|
53
69
|
let end = 0;
|
|
54
70
|
for (const character of value) {
|
|
@@ -276,20 +292,11 @@ export class TaskService {
|
|
|
276
292
|
this.cleanupService = cleanupService;
|
|
277
293
|
this.backgroundService = backgroundService;
|
|
278
294
|
}
|
|
279
|
-
/**
|
|
280
|
-
|
|
281
|
-
*/
|
|
282
|
-
async findBoard(params = {}) {
|
|
295
|
+
/** Page and count using the same display status, before loading associations. */
|
|
296
|
+
async findPage(params, includeArchived = false) {
|
|
283
297
|
const page = Math.max(1, params.page || 1);
|
|
284
298
|
const limit = Math.min(1000, Math.max(1, params.limit || 1000));
|
|
285
299
|
const skip = (page - 1) * limit;
|
|
286
|
-
const where = {
|
|
287
|
-
deletedAt: null,
|
|
288
|
-
project: { archivedAt: null },
|
|
289
|
-
...(params.projectId ? { projectId: params.projectId } : {}),
|
|
290
|
-
...(params.parentTaskId ? { parentTaskId: params.parentTaskId } : {}),
|
|
291
|
-
...(params.status ? { status: params.status } : {}),
|
|
292
|
-
};
|
|
293
300
|
const projectFilter = params.projectId
|
|
294
301
|
? Prisma.sql `AND task."projectId" = ${params.projectId}`
|
|
295
302
|
: Prisma.empty;
|
|
@@ -297,20 +304,21 @@ export class TaskService {
|
|
|
297
304
|
? Prisma.sql `AND task."parentTaskId" = ${params.parentTaskId}`
|
|
298
305
|
: Prisma.empty;
|
|
299
306
|
const statusFilter = params.status
|
|
300
|
-
? Prisma.sql `AND
|
|
307
|
+
? Prisma.sql `AND (${taskDisplayStatusSql}) = ${params.status}`
|
|
301
308
|
: Prisma.empty;
|
|
302
|
-
const
|
|
309
|
+
const fromWhere = Prisma.sql `
|
|
310
|
+
FROM "Task" task
|
|
311
|
+
INNER JOIN "Project" project ON project."id" = task."projectId"
|
|
312
|
+
WHERE task."deletedAt" IS NULL
|
|
313
|
+
${includeArchived ? Prisma.empty : Prisma.sql `AND project."archivedAt" IS NULL`}
|
|
314
|
+
${projectFilter} ${statusFilter} ${parentFilter}
|
|
315
|
+
`;
|
|
316
|
+
const [tasks, counts] = await Promise.all([
|
|
303
317
|
prisma.$queryRaw(Prisma.sql `
|
|
304
318
|
SELECT ${taskBoardColumns}
|
|
305
|
-
|
|
306
|
-
INNER JOIN "Project" project ON project."id" = task."projectId"
|
|
307
|
-
WHERE task."deletedAt" IS NULL
|
|
308
|
-
AND project."archivedAt" IS NULL
|
|
309
|
-
${projectFilter}
|
|
310
|
-
${statusFilter}
|
|
311
|
-
${parentFilter}
|
|
319
|
+
${fromWhere}
|
|
312
320
|
ORDER BY
|
|
313
|
-
CASE
|
|
321
|
+
CASE "displayStatus"
|
|
314
322
|
WHEN ${TaskStatus.IN_PROGRESS} THEN 0
|
|
315
323
|
WHEN ${TaskStatus.IN_REVIEW} THEN 1
|
|
316
324
|
WHEN ${TaskStatus.TODO} THEN 2
|
|
@@ -318,22 +326,29 @@ export class TaskService {
|
|
|
318
326
|
WHEN ${TaskStatus.CANCELLED} THEN 4
|
|
319
327
|
ELSE 99
|
|
320
328
|
END ASC,
|
|
321
|
-
CASE WHEN
|
|
329
|
+
CASE WHEN "displayStatus" = ${TaskStatus.IN_REVIEW} THEN task."priority" ELSE 0 END DESC,
|
|
322
330
|
task."position" ASC,
|
|
323
331
|
task."id" ASC
|
|
324
332
|
LIMIT ${limit} OFFSET ${skip}
|
|
325
333
|
`),
|
|
326
|
-
prisma.
|
|
334
|
+
prisma.$queryRaw(Prisma.sql `SELECT COUNT(*) AS total ${fromWhere}`),
|
|
327
335
|
]);
|
|
328
|
-
|
|
329
|
-
|
|
336
|
+
return { tasks, total: Number(counts[0].total), page, limit };
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Compact board read model. Query count remains fixed as project/task counts grow.
|
|
340
|
+
*/
|
|
341
|
+
async findBoard(params = {}) {
|
|
342
|
+
const { tasks, total, page, limit } = await this.findPage(params);
|
|
343
|
+
// Descendants can rank ahead of their ancestors or fall on another page.
|
|
344
|
+
// Return the complete compact path without changing the page count/limit.
|
|
330
345
|
const pageIds = new Set(tasks.map((task) => task.id));
|
|
331
|
-
const missingParentIds = [...new Set(tasks.flatMap((task) => task.parentTaskId
|
|
346
|
+
const missingParentIds = [...new Set(tasks.flatMap((task) => ancestorIds(task.parentTaskId, task.grandparentTaskId).filter(id => !pageIds.has(id))))];
|
|
332
347
|
const parents = params.parentTaskId || missingParentIds.length === 0 ? []
|
|
333
348
|
: await prisma.$queryRaw(Prisma.sql `
|
|
334
349
|
SELECT ${taskBoardColumns} FROM "Task" task
|
|
335
350
|
INNER JOIN "Project" project ON project."id" = task."projectId"
|
|
336
|
-
WHERE task."id" IN (${
|
|
351
|
+
WHERE task."id" IN (SELECT value FROM json_each(${JSON.stringify(missingParentIds)}))
|
|
337
352
|
AND task."deletedAt" IS NULL AND project."archivedAt" IS NULL
|
|
338
353
|
`);
|
|
339
354
|
const allTasks = [...tasks, ...parents];
|
|
@@ -405,10 +420,12 @@ export class TaskService {
|
|
|
405
420
|
id: task.id,
|
|
406
421
|
projectId: task.projectId,
|
|
407
422
|
parentTaskId: task.parentTaskId,
|
|
423
|
+
ancestorIds: ancestorIds(task.parentTaskId, task.grandparentTaskId),
|
|
408
424
|
subtaskCount: Number(task.subtaskCount),
|
|
409
425
|
runningSubtaskCount: Number(task.runningSubtaskCount),
|
|
410
426
|
title: titlePreview,
|
|
411
427
|
status: task.status,
|
|
428
|
+
...mapTaskDisplayState(task),
|
|
412
429
|
priority: task.priority ?? TaskPriority.NORMAL,
|
|
413
430
|
...(preferredWorkspace ? {
|
|
414
431
|
preferredWorkspace: {
|
|
@@ -445,60 +462,37 @@ export class TaskService {
|
|
|
445
462
|
if (!project) {
|
|
446
463
|
throw new NotFoundError('Project', projectId);
|
|
447
464
|
}
|
|
448
|
-
const
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
id: true,
|
|
469
|
-
projectId: true,
|
|
470
|
-
title: true,
|
|
471
|
-
baseBranch: true,
|
|
472
|
-
parentTaskId: true,
|
|
473
|
-
status: true,
|
|
474
|
-
priority: true,
|
|
475
|
-
position: true,
|
|
476
|
-
createdAt: true,
|
|
477
|
-
updatedAt: true,
|
|
478
|
-
workspaces: { include: { sessions: visibleSessionSummary } },
|
|
479
|
-
project: true,
|
|
480
|
-
},
|
|
481
|
-
orderBy: [{ updatedAt: 'desc' }],
|
|
482
|
-
skip,
|
|
483
|
-
take: limit,
|
|
484
|
-
}),
|
|
485
|
-
prisma.task.count({ where }),
|
|
486
|
-
]);
|
|
487
|
-
data.sort((a, b) => {
|
|
488
|
-
const sa = statusOrder[a.status] ?? 99;
|
|
489
|
-
const sb = statusOrder[b.status] ?? 99;
|
|
490
|
-
if (sa !== sb)
|
|
491
|
-
return sa - sb;
|
|
492
|
-
if (a.status === TaskStatus.IN_REVIEW) {
|
|
493
|
-
const priorityDelta = (b.priority ?? TaskPriority.NORMAL) - (a.priority ?? TaskPriority.NORMAL);
|
|
494
|
-
if (priorityDelta !== 0)
|
|
495
|
-
return priorityDelta;
|
|
496
|
-
}
|
|
497
|
-
return (a.position ?? 0) - (b.position ?? 0) || a.id.localeCompare(b.id);
|
|
465
|
+
const { tasks, total, page, limit } = await this.findPage({
|
|
466
|
+
...params, projectId, limit: params.limit || 200,
|
|
467
|
+
}, true);
|
|
468
|
+
const data = await prisma.task.findMany({
|
|
469
|
+
where: { id: { in: tasks.map(task => task.id) }, deletedAt: null },
|
|
470
|
+
select: {
|
|
471
|
+
id: true,
|
|
472
|
+
projectId: true,
|
|
473
|
+
title: true,
|
|
474
|
+
baseBranch: true,
|
|
475
|
+
parentTaskId: true,
|
|
476
|
+
parentTask: { select: { parentTaskId: true } },
|
|
477
|
+
status: true,
|
|
478
|
+
priority: true,
|
|
479
|
+
position: true,
|
|
480
|
+
createdAt: true,
|
|
481
|
+
updatedAt: true,
|
|
482
|
+
workspaces: { include: { sessions: visibleSessionSummary } },
|
|
483
|
+
project: true,
|
|
484
|
+
},
|
|
498
485
|
});
|
|
486
|
+
const byId = new Map(data.map(task => [task.id, task]));
|
|
499
487
|
const projectGitCapability = getStoredProjectGitCapability(project);
|
|
500
488
|
return {
|
|
501
|
-
data:
|
|
489
|
+
data: tasks.flatMap(row => {
|
|
490
|
+
const task = byId.get(row.id);
|
|
491
|
+
return task ? [withTaskPreviews(withProjectGitCapability({
|
|
492
|
+
...withHierarchy(task), status: row.status, ...mapTaskDisplayState(row),
|
|
493
|
+
subtaskCount: Number(row.subtaskCount),
|
|
494
|
+
}, projectGitCapability), { omitDescription: true })] : [];
|
|
495
|
+
}),
|
|
502
496
|
total,
|
|
503
497
|
page,
|
|
504
498
|
limit,
|
|
@@ -518,6 +512,7 @@ export class TaskService {
|
|
|
518
512
|
title: true,
|
|
519
513
|
baseBranch: true,
|
|
520
514
|
parentTaskId: true,
|
|
515
|
+
parentTask: { select: { parentTaskId: true } },
|
|
521
516
|
_count: { select: { subtasks: { where: { deletedAt: null } } } },
|
|
522
517
|
status: true,
|
|
523
518
|
priority: true,
|
|
@@ -531,7 +526,7 @@ export class TaskService {
|
|
|
531
526
|
throw new NotFoundError('Task', id);
|
|
532
527
|
}
|
|
533
528
|
const { _count, ...metadata } = task;
|
|
534
|
-
return withTaskPreviews(withProjectGitMetadata({ ...metadata, subtaskCount: _count.subtasks }), { omitDescription: true });
|
|
529
|
+
return this.withDisplayState(withTaskPreviews(withProjectGitMetadata({ ...withHierarchy(metadata), subtaskCount: _count.subtasks }), { omitDescription: true }));
|
|
535
530
|
}
|
|
536
531
|
async findSubtasks(id, params = {}) {
|
|
537
532
|
const parent = await prisma.task.findFirst({ where: { id, deletedAt: null } });
|
|
@@ -592,19 +587,26 @@ export class TaskService {
|
|
|
592
587
|
ensureProjectIsMutable(project, 'create tasks');
|
|
593
588
|
const parent = input.parentTaskId ? await prisma.task.findFirst({
|
|
594
589
|
where: { id: input.parentTaskId, projectId, deletedAt: null },
|
|
595
|
-
include: { workspaces: {
|
|
596
|
-
where: { parentWorkspaceId: null, ownerMemberId: null, status: { not: WorkspaceStatus.ABANDONED } },
|
|
590
|
+
include: { parentTask: { select: { parentTaskId: true } }, workspaces: {
|
|
591
|
+
where: { parentWorkspaceId: null, ownerMemberId: null, status: { not: WorkspaceStatus.ABANDONED }, cleanedAt: null },
|
|
597
592
|
orderBy: { createdAt: 'desc' },
|
|
598
593
|
} },
|
|
599
594
|
}) : null;
|
|
600
595
|
if (input.parentTaskId && !parent)
|
|
601
596
|
throw new NotFoundError('Parent task', input.parentTaskId);
|
|
602
|
-
if (parent?.parentTaskId)
|
|
603
|
-
throw new ValidationError('
|
|
597
|
+
if (parent?.parentTask?.parentTaskId)
|
|
598
|
+
throw new ValidationError('Tasks support at most three levels');
|
|
604
599
|
const parentWorkspace = parent?.workspaces.find((workspace) => workspace.status === WorkspaceStatus.ACTIVE)
|
|
605
600
|
?? parent?.workspaces.find((workspace) => workspace.status === WorkspaceStatus.HIBERNATED)
|
|
606
601
|
?? parent?.workspaces[0];
|
|
607
602
|
const parentBranch = parentWorkspace?.branchName || parent?.baseBranch;
|
|
603
|
+
// A grandchild may inherit an ancestor branch before its parent starts.
|
|
604
|
+
// Serialize validation/persistence with that branch owner's cleanup as well.
|
|
605
|
+
const requestedParentBranch = input.baseBranch ?? parentBranch;
|
|
606
|
+
const branchOwners = input.baseBranch === null || !requestedParentBranch ? [] : await prisma.workspace.findMany({
|
|
607
|
+
where: { task: { projectId, deletedAt: null }, branchName: requestedParentBranch },
|
|
608
|
+
select: { id: true },
|
|
609
|
+
});
|
|
608
610
|
const createWithParentBranch = async () => {
|
|
609
611
|
// Resolve at task creation so delayed starts and TeamRun main workspaces
|
|
610
612
|
// cannot silently follow a later project default change. Local tasks opt out.
|
|
@@ -625,9 +627,12 @@ export class TaskService {
|
|
|
625
627
|
if (parent) {
|
|
626
628
|
const liveParent = await tx.task.findFirst({
|
|
627
629
|
where: { id: parent.id, projectId, deletedAt: null, project: { archivedAt: null } },
|
|
630
|
+
include: { parentTask: { select: { parentTaskId: true } } },
|
|
628
631
|
});
|
|
629
632
|
if (!liveParent)
|
|
630
633
|
throw new NotFoundError('Parent task', parent.id);
|
|
634
|
+
if (liveParent.parentTask?.parentTaskId)
|
|
635
|
+
throw new ValidationError('Tasks support at most three levels');
|
|
631
636
|
}
|
|
632
637
|
return tx.task.create({
|
|
633
638
|
data: {
|
|
@@ -646,6 +651,7 @@ export class TaskService {
|
|
|
646
651
|
this.eventBus.emit('task:updated', { taskId: parent.id, projectId, status: parent.status });
|
|
647
652
|
return {
|
|
648
653
|
...created,
|
|
654
|
+
ancestorIds: parent ? ancestorIds(parent.id, parent.parentTaskId) : [],
|
|
649
655
|
project: {
|
|
650
656
|
...project,
|
|
651
657
|
...buildProjectGitMetadata(project),
|
|
@@ -654,9 +660,7 @@ export class TaskService {
|
|
|
654
660
|
};
|
|
655
661
|
// Serialize branch validation and child persistence with parent workspace
|
|
656
662
|
// cleanup, so its reference becomes visible before that branch is reclaimed.
|
|
657
|
-
return parentWorkspace
|
|
658
|
-
? defaultWorkspaceLifecycleBarrier.withWorkspace(parentWorkspace.id, createWithParentBranch)
|
|
659
|
-
: createWithParentBranch();
|
|
663
|
+
return defaultWorkspaceLifecycleBarrier.withWorkspaces([...branchOwners.map(workspace => workspace.id), ...(parentWorkspace ? [parentWorkspace.id] : [])], createWithParentBranch);
|
|
660
664
|
}
|
|
661
665
|
/**
|
|
662
666
|
* 更新任务基本信息
|
|
@@ -781,13 +785,14 @@ export class TaskService {
|
|
|
781
785
|
if (!taskForGuard || taskForGuard.deletedAt)
|
|
782
786
|
throw new NotFoundError('Task', id);
|
|
783
787
|
ensureProjectIsMutable(taskForGuard.project, 'delete tasks');
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
788
|
+
const familyWhere = subtreeWhere(id, taskForGuard.projectId);
|
|
789
|
+
if (expectedSubtaskCount !== undefined && expectedSubtaskCount !== (await prisma.task.count({
|
|
790
|
+
where: familyWhere,
|
|
791
|
+
})) - 1) {
|
|
787
792
|
throw new ServiceError('Subtasks changed. Review the deletion confirmation again.', 'TASK_DELETE_SCOPE_CHANGED', 409);
|
|
788
793
|
}
|
|
789
794
|
const workspaceIds = await prisma.workspace.findMany({
|
|
790
|
-
where: { task:
|
|
795
|
+
where: { task: familyWhere },
|
|
791
796
|
select: { id: true },
|
|
792
797
|
});
|
|
793
798
|
const result = await defaultWorkspaceLifecycleBarrier.withWorkspaces(workspaceIds.map((workspace) => workspace.id), async () => {
|
|
@@ -801,13 +806,23 @@ export class TaskService {
|
|
|
801
806
|
throw new NotFoundError('Task', id);
|
|
802
807
|
ensureProjectIsMutable(parent.project, 'delete tasks');
|
|
803
808
|
const family = await tx.task.findMany({
|
|
804
|
-
where:
|
|
805
|
-
select: { id: true },
|
|
809
|
+
where: familyWhere,
|
|
810
|
+
select: { id: true, parentTaskId: true },
|
|
806
811
|
});
|
|
807
812
|
if (expectedSubtaskCount !== undefined && expectedSubtaskCount !== family.length - 1) {
|
|
808
813
|
throw new ServiceError('Subtasks changed. Review the deletion confirmation again.', 'TASK_DELETE_SCOPE_CHANGED', 409);
|
|
809
814
|
}
|
|
810
|
-
const
|
|
815
|
+
const byId = new Map(family.map(task => [task.id, task]));
|
|
816
|
+
const depth = (task) => {
|
|
817
|
+
let current = task;
|
|
818
|
+
let value = 0;
|
|
819
|
+
while (current.parentTaskId && byId.has(current.parentTaskId) && value < MAX_TASK_DEPTH) {
|
|
820
|
+
current = byId.get(current.parentTaskId);
|
|
821
|
+
value++;
|
|
822
|
+
}
|
|
823
|
+
return value;
|
|
824
|
+
};
|
|
825
|
+
const taskIds = family.sort((a, b) => depth(b) - depth(a) || a.id.localeCompare(b.id)).map(task => task.id);
|
|
811
826
|
await tx.task.updateMany({ where: { id: { in: taskIds } }, data: { deletedAt: new Date() } });
|
|
812
827
|
const tasks = await tx.task.findMany({
|
|
813
828
|
where: { id: { in: taskIds } },
|
|
@@ -826,6 +841,7 @@ export class TaskService {
|
|
|
826
841
|
workspaces: orderedTasks.flatMap((task) => task.workspaces.map((workspace) => ({
|
|
827
842
|
id: workspace.id,
|
|
828
843
|
worktreePath: workspace.worktreePath,
|
|
844
|
+
resourcesCleaned: workspace.cleanedAt != null,
|
|
829
845
|
workingDir: getWorkspaceWorkingDir(workspace),
|
|
830
846
|
workspaceKind: workspace.workspaceKind,
|
|
831
847
|
branchName: workspace.branchName,
|
|
@@ -860,6 +876,14 @@ export class TaskService {
|
|
|
860
876
|
this.cleanupService?.trigger();
|
|
861
877
|
return true;
|
|
862
878
|
}
|
|
879
|
+
async getDeletionScope(id) {
|
|
880
|
+
return prisma.$transaction(async (tx) => {
|
|
881
|
+
const task = await tx.task.findFirst({ where: { id, deletedAt: null }, select: { projectId: true } });
|
|
882
|
+
if (!task)
|
|
883
|
+
throw new NotFoundError('Task', id);
|
|
884
|
+
return { descendantCount: (await tx.task.count({ where: subtreeWhere(id, task.projectId) })) - 1 };
|
|
885
|
+
});
|
|
886
|
+
}
|
|
863
887
|
async getCleanupStatus(taskId) {
|
|
864
888
|
const job = await prisma.taskCleanupJob.findFirst({
|
|
865
889
|
where: { taskId }, orderBy: { createdAt: 'desc' },
|
|
@@ -894,11 +918,11 @@ export class TaskService {
|
|
|
894
918
|
if (!project) {
|
|
895
919
|
throw new NotFoundError('Project', projectId);
|
|
896
920
|
}
|
|
897
|
-
const counts = await prisma.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
921
|
+
const counts = await prisma.$queryRaw(Prisma.sql `
|
|
922
|
+
SELECT ${taskDisplayStatusSql} AS "displayStatus", COUNT(*) AS count
|
|
923
|
+
FROM "Task" task WHERE task."projectId" = ${projectId} AND task."deletedAt" IS NULL
|
|
924
|
+
GROUP BY "displayStatus"
|
|
925
|
+
`);
|
|
902
926
|
const stats = {
|
|
903
927
|
total: 0,
|
|
904
928
|
todo: 0,
|
|
@@ -908,9 +932,9 @@ export class TaskService {
|
|
|
908
932
|
cancelled: 0,
|
|
909
933
|
};
|
|
910
934
|
for (const row of counts) {
|
|
911
|
-
const count = row.
|
|
935
|
+
const count = Number(row.count);
|
|
912
936
|
stats.total += count;
|
|
913
|
-
switch (row.
|
|
937
|
+
switch (row.displayStatus) {
|
|
914
938
|
case TaskStatus.TODO:
|
|
915
939
|
stats.todo = count;
|
|
916
940
|
break;
|
|
@@ -985,6 +1009,15 @@ export class TaskService {
|
|
|
985
1009
|
};
|
|
986
1010
|
}
|
|
987
1011
|
// ── 内部方法 ────────────────────────────────────────────────────────────────
|
|
1012
|
+
async withDisplayState(task) {
|
|
1013
|
+
const [state] = await prisma.$queryRaw(Prisma.sql `
|
|
1014
|
+
SELECT task."status", ${taskDisplayColumnsSql} FROM "Task" task
|
|
1015
|
+
WHERE task."id" = ${task.id} AND task."deletedAt" IS NULL
|
|
1016
|
+
`);
|
|
1017
|
+
if (!state)
|
|
1018
|
+
throw new NotFoundError('Task', task.id);
|
|
1019
|
+
return { ...task, status: state.status, ...mapTaskDisplayState(state) };
|
|
1020
|
+
}
|
|
988
1021
|
/**
|
|
989
1022
|
* 发射 task:updated 事件,通知 SocketGateway 转发到前端
|
|
990
1023
|
*/
|