@shepai/cli 1.85.0 → 1.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +2 -1
  2. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.d.ts +22 -0
  4. package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.d.ts.map +1 -0
  5. package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.js +76 -0
  6. package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.d.ts +7 -2
  7. package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.js +29 -15
  9. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  10. package/dist/packages/core/src/infrastructure/di/container.js +5 -0
  11. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +3 -0
  13. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +2 -0
  14. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +3 -0
  16. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +1 -1
  17. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
  18. package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +6 -2
  19. package/dist/src/presentation/cli/commands/feat/del.command.d.ts +3 -1
  20. package/dist/src/presentation/cli/commands/feat/del.command.d.ts.map +1 -1
  21. package/dist/src/presentation/cli/commands/feat/del.command.js +19 -2
  22. package/dist/src/presentation/web/app/actions/delete-feature.d.ts +1 -1
  23. package/dist/src/presentation/web/app/actions/delete-feature.d.ts.map +1 -1
  24. package/dist/src/presentation/web/app/actions/delete-feature.js +4 -2
  25. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +5 -4
  27. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog-config.d.ts +9 -0
  28. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog-config.d.ts.map +1 -0
  29. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog-config.js +1 -0
  30. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.d.ts +3 -0
  31. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.d.ts.map +1 -0
  32. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.js +16 -0
  33. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.stories.d.ts +8 -0
  34. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.stories.d.ts.map +1 -0
  35. package/dist/src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.stories.js +25 -0
  36. package/dist/src/presentation/web/components/common/delete-feature-dialog/index.d.ts +3 -0
  37. package/dist/src/presentation/web/components/common/delete-feature-dialog/index.d.ts.map +1 -0
  38. package/dist/src/presentation/web/components/common/delete-feature-dialog/index.js +1 -0
  39. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +1 -1
  40. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
  41. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  42. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +5 -7
  43. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +1 -1
  44. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  45. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +2 -2
  46. package/dist/src/presentation/web/lib/derive-graph.d.ts +1 -1
  47. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -1
  48. package/dist/tsconfig.build.tsbuildinfo +1 -1
  49. package/package.json +1 -1
  50. package/web/.next/BUILD_ID +1 -1
  51. package/web/.next/build-manifest.json +2 -2
  52. package/web/.next/fallback-build-manifest.json +2 -2
  53. package/web/.next/prerender-manifest.json +3 -3
  54. package/web/.next/required-server-files.js +1 -1
  55. package/web/.next/required-server-files.json +1 -1
  56. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +18 -18
  57. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  58. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  59. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +21 -21
  60. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  63. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  64. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  65. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +18 -18
  66. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  67. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +21 -21
  69. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  70. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  71. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +14 -14
  72. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  73. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  75. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  76. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  77. package/web/.next/server/app/_global-error.html +2 -2
  78. package/web/.next/server/app/_global-error.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  80. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  81. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  82. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  83. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  84. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  85. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  86. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  87. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  88. package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
  89. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  90. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  92. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  93. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  94. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  95. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  96. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  97. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  98. package/web/.next/server/app/version/page.js.nft.json +1 -1
  99. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  100. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  101. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  102. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +1 -1
  103. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -1
  104. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +1 -1
  105. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -1
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js.map +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js +1 -1
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js.map +1 -1
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__b3a4cef4._.js +1 -1
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__b3a4cef4._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__f0d8d054._.js +2 -2
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/_135edb9c._.js +3 -0
  124. package/web/.next/server/chunks/ssr/{_63868199._.js.map → _135edb9c._.js.map} +1 -1
  125. package/web/.next/server/chunks/ssr/_5860e4e2._.js +3 -0
  126. package/web/.next/server/chunks/ssr/_5860e4e2._.js.map +1 -0
  127. package/web/.next/server/chunks/ssr/_752e01fd._.js +3 -0
  128. package/web/.next/server/chunks/ssr/_752e01fd._.js.map +1 -0
  129. package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
  130. package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
  131. package/web/.next/server/chunks/ssr/{_6bffa94a._.js → _a2ec151c._.js} +2 -2
  132. package/web/.next/server/chunks/ssr/_a2ec151c._.js.map +1 -0
  133. package/web/.next/server/chunks/ssr/_a68d7e1c._.js +1 -1
  134. package/web/.next/server/chunks/ssr/_a68d7e1c._.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/_cc77a143._.js +3 -0
  136. package/web/.next/server/chunks/ssr/{_1e3cf73b._.js.map → _cc77a143._.js.map} +1 -1
  137. package/web/.next/server/chunks/ssr/_e6f2da4f._.js +7 -0
  138. package/web/.next/server/chunks/ssr/{_34fbed18._.js.map → _e6f2da4f._.js.map} +1 -1
  139. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  140. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +1 -1
  142. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -1
  143. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  144. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  145. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  146. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  147. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js +2 -2
  148. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js.map +1 -1
  149. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +3 -0
  150. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -0
  151. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +3 -0
  152. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -0
  153. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  154. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  155. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js +2 -2
  156. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js.map +1 -1
  157. package/web/.next/server/pages/500.html +2 -2
  158. package/web/.next/server/server-reference-manifest.js +1 -1
  159. package/web/.next/server/server-reference-manifest.json +28 -28
  160. package/web/.next/static/chunks/{31c1e96c4cfeb16b.js → 20e5c07abd2699c2.js} +2 -2
  161. package/web/.next/static/chunks/673af06602f590f0.js +1 -0
  162. package/web/.next/static/chunks/8b59757e9f52e364.js +1 -0
  163. package/web/.next/static/chunks/{26f58bbf4766e1c4.js → 98b1c6b413aeb539.js} +1 -1
  164. package/web/.next/static/chunks/ba99f8c298491782.js +1 -0
  165. package/web/.next/static/chunks/c267885c32e4091c.js +1 -0
  166. package/web/.next/static/chunks/c2e2e1720b4f9a1a.js +1 -0
  167. package/web/.next/static/chunks/c481a0ab2ddddbf4.js +1 -0
  168. package/web/.next/static/chunks/{5b707c839eafb404.js → e49abd7c0c1cdef2.js} +2 -2
  169. package/web/.next/static/chunks/eafcdd214c540495.js +1 -0
  170. package/web/.next/server/chunks/ssr/_1e3cf73b._.js +0 -3
  171. package/web/.next/server/chunks/ssr/_34fbed18._.js +0 -7
  172. package/web/.next/server/chunks/ssr/_63868199._.js +0 -3
  173. package/web/.next/server/chunks/ssr/_6bffa94a._.js.map +0 -1
  174. package/web/.next/server/chunks/ssr/_d42594dd._.js +0 -3
  175. package/web/.next/server/chunks/ssr/_d42594dd._.js.map +0 -1
  176. package/web/.next/server/chunks/ssr/node_modules__pnpm_d80c1060._.js +0 -3
  177. package/web/.next/server/chunks/ssr/node_modules__pnpm_d80c1060._.js.map +0 -1
  178. package/web/.next/server/chunks/ssr/src_presentation_web_components_80b5b4bc._.js +0 -3
  179. package/web/.next/server/chunks/ssr/src_presentation_web_components_80b5b4bc._.js.map +0 -1
  180. package/web/.next/server/chunks/ssr/src_presentation_web_components_82416b8f._.js +0 -3
  181. package/web/.next/server/chunks/ssr/src_presentation_web_components_82416b8f._.js.map +0 -1
  182. package/web/.next/static/chunks/79f610312f57dc66.js +0 -1
  183. package/web/.next/static/chunks/8fa4bf83842a3389.js +0 -1
  184. package/web/.next/static/chunks/c9333b53106c0ca9.js +0 -1
  185. package/web/.next/static/chunks/ce7a578a83924232.js +0 -1
  186. package/web/.next/static/chunks/d8e93250744112df.js +0 -1
  187. package/web/.next/static/chunks/da7d7608abd1032f.js +0 -1
  188. package/web/.next/static/chunks/df38705b7992b33f.js +0 -1
  189. /package/web/.next/static/{Lf0zFNsMS4qCNRm_LSgya → VCU_mY2u0y_7bLsvmLjyS}/_buildManifest.js +0 -0
  190. /package/web/.next/static/{Lf0zFNsMS4qCNRm_LSgya → VCU_mY2u0y_7bLsvmLjyS}/_clientMiddlewareManifest.json +0 -0
  191. /package/web/.next/static/{Lf0zFNsMS4qCNRm_LSgya → VCU_mY2u0y_7bLsvmLjyS}/_ssgManifest.js +0 -0
@@ -54,9 +54,10 @@ export interface IWorktreeService {
54
54
  * Remove an existing worktree.
55
55
  *
56
56
  * @param worktreePath - Path to the worktree to remove
57
+ * @param force - When true, passes --force to git worktree remove (handles dirty worktrees)
57
58
  * @throws WorktreeError if worktree not found or has uncommitted changes
58
59
  */
59
- remove(worktreePath: string): Promise<void>;
60
+ remove(worktreePath: string, force?: boolean): Promise<void>;
60
61
  /**
61
62
  * List all worktrees in a repository.
62
63
  *
@@ -1 +1 @@
1
- {"version":3,"file":"worktree-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/worktree-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,oBAAY,iBAAiB;IAC3B,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,SAAS,cAAc;CACxB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAGpB,IAAI,EAAE,iBAAiB;aACvB,KAAK,CAAC,EAAE,KAAK;gBAF7B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,iBAAiB,EACvB,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;OASG;IACH,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;OAKG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C;;;;;OAKG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAEhD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE3D;;;;;;OAMG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjE;;;;;;OAMG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEvE;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAE1D;;;;;;;OAOG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD"}
1
+ {"version":3,"file":"worktree-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/worktree-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,oBAAY,iBAAiB;IAC3B,cAAc,mBAAmB;IACjC,aAAa,kBAAkB;IAC/B,SAAS,cAAc;IACvB,cAAc,mBAAmB;IACjC,SAAS,cAAc;CACxB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAGpB,IAAI,EAAE,iBAAiB;aACvB,KAAK,CAAC,EAAE,KAAK;gBAF7B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,iBAAiB,EACvB,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;OASG;IACH,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAAC;IAEzB;;;;;;OAMG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7D;;;;;OAKG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAEhD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE3D;;;;;;OAMG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjE;;;;;;OAMG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEvE;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAE1D;;;;;;;OAOG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cleanup Feature Worktree Use Case
3
+ *
4
+ * Orchestrates post-merge cleanup after a feature reaches SdlcLifecycle.Maintain:
5
+ * - Unlinks the git worktree (preserving directory contents on disk)
6
+ * - Deletes the local feature branch
7
+ * - Deletes the remote feature branch (if it still exists)
8
+ *
9
+ * All cleanup steps are non-fatal: errors are caught and logged as warnings
10
+ * so that a cleanup failure never surfaces as a feature run failure.
11
+ */
12
+ import type { IFeatureRepository } from '../../ports/output/repositories/feature-repository.interface.js';
13
+ import type { IWorktreeService } from '../../ports/output/services/worktree-service.interface.js';
14
+ import type { IGitPrService } from '../../ports/output/services/git-pr-service.interface.js';
15
+ export declare class CleanupFeatureWorktreeUseCase {
16
+ private readonly featureRepo;
17
+ private readonly worktreeService;
18
+ private readonly gitPrService;
19
+ constructor(featureRepo: IFeatureRepository, worktreeService: IWorktreeService, gitPrService: IGitPrService);
20
+ execute(featureId: string): Promise<void>;
21
+ }
22
+ //# sourceMappingURL=cleanup-feature-worktree.use-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup-feature-worktree.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yDAAyD,CAAC;AAE7F,qBACa,6BAA6B;IAER,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY;gBAFP,WAAW,EAAE,kBAAkB,EACjC,eAAe,EAAE,gBAAgB,EACpC,YAAY,EAAE,aAAa;IAGjE,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAqChD"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Cleanup Feature Worktree Use Case
3
+ *
4
+ * Orchestrates post-merge cleanup after a feature reaches SdlcLifecycle.Maintain:
5
+ * - Unlinks the git worktree (preserving directory contents on disk)
6
+ * - Deletes the local feature branch
7
+ * - Deletes the remote feature branch (if it still exists)
8
+ *
9
+ * All cleanup steps are non-fatal: errors are caught and logged as warnings
10
+ * so that a cleanup failure never surfaces as a feature run failure.
11
+ */
12
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
13
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
14
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
15
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
16
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
17
+ };
18
+ var __metadata = (this && this.__metadata) || function (k, v) {
19
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
20
+ };
21
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
22
+ return function (target, key) { decorator(target, key, paramIndex); }
23
+ };
24
+ import { injectable, inject } from 'tsyringe';
25
+ let CleanupFeatureWorktreeUseCase = class CleanupFeatureWorktreeUseCase {
26
+ featureRepo;
27
+ worktreeService;
28
+ gitPrService;
29
+ constructor(featureRepo, worktreeService, gitPrService) {
30
+ this.featureRepo = featureRepo;
31
+ this.worktreeService = worktreeService;
32
+ this.gitPrService = gitPrService;
33
+ }
34
+ async execute(featureId) {
35
+ const feature = await this.featureRepo.findById(featureId);
36
+ if (!feature)
37
+ return;
38
+ // Step 1: Unlink the git worktree (directory contents are preserved on disk)
39
+ const worktreePath = feature.worktreePath ??
40
+ this.worktreeService.getWorktreePath(feature.repositoryPath, feature.branch);
41
+ try {
42
+ await this.worktreeService.remove(worktreePath, true);
43
+ }
44
+ catch (err) {
45
+ // eslint-disable-next-line no-console
46
+ console.warn('[CleanupFeatureWorktreeUseCase] worktree remove failed:', err);
47
+ }
48
+ // Step 2: Delete the local feature branch
49
+ try {
50
+ await this.gitPrService.deleteBranch(feature.repositoryPath, feature.branch);
51
+ }
52
+ catch (err) {
53
+ // eslint-disable-next-line no-console
54
+ console.warn('[CleanupFeatureWorktreeUseCase] local branch delete failed:', err);
55
+ }
56
+ // Step 3: Delete the remote feature branch if it still exists
57
+ try {
58
+ const remoteExists = await this.worktreeService.remoteBranchExists(feature.repositoryPath, feature.branch);
59
+ if (remoteExists) {
60
+ await this.gitPrService.deleteBranch(feature.repositoryPath, feature.branch, true);
61
+ }
62
+ }
63
+ catch (err) {
64
+ // eslint-disable-next-line no-console
65
+ console.warn('[CleanupFeatureWorktreeUseCase] remote branch delete failed:', err);
66
+ }
67
+ }
68
+ };
69
+ CleanupFeatureWorktreeUseCase = __decorate([
70
+ injectable(),
71
+ __param(0, inject('IFeatureRepository')),
72
+ __param(1, inject('IWorktreeService')),
73
+ __param(2, inject('IGitPrService')),
74
+ __metadata("design:paramtypes", [Object, Object, Object])
75
+ ], CleanupFeatureWorktreeUseCase);
76
+ export { CleanupFeatureWorktreeUseCase };
@@ -18,13 +18,18 @@ import type { IFeatureRepository } from '../../ports/output/repositories/feature
18
18
  import type { IWorktreeService } from '../../ports/output/services/worktree-service.interface.js';
19
19
  import type { IFeatureAgentProcessService } from '../../ports/output/agents/feature-agent-process.interface.js';
20
20
  import type { IAgentRunRepository } from '../../ports/output/agents/agent-run-repository.interface.js';
21
+ import type { CleanupFeatureWorktreeUseCase } from './cleanup-feature-worktree.use-case.js';
22
+ export interface DeleteFeatureOptions {
23
+ cleanup?: boolean;
24
+ }
21
25
  export declare class DeleteFeatureUseCase {
22
26
  private readonly featureRepo;
23
27
  private readonly worktreeService;
24
28
  private readonly processService;
25
29
  private readonly runRepo;
26
- constructor(featureRepo: IFeatureRepository, worktreeService: IWorktreeService, processService: IFeatureAgentProcessService, runRepo: IAgentRunRepository);
27
- execute(featureId: string): Promise<Feature>;
30
+ private readonly cleanupUseCase;
31
+ constructor(featureRepo: IFeatureRepository, worktreeService: IWorktreeService, processService: IFeatureAgentProcessService, runRepo: IAgentRunRepository, cleanupUseCase: Pick<CleanupFeatureWorktreeUseCase, 'execute'>);
32
+ execute(featureId: string, options?: DeleteFeatureOptions): Promise<Feature>;
28
33
  private cascadeDeleteChildren;
29
34
  private deleteSingleFeature;
30
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"delete-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/features/delete-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAClG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAEvG,qBACa,oBAAoB;IAEC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAE5D,OAAO,CAAC,QAAQ,CAAC,cAAc;IACA,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAJR,WAAW,EAAE,kBAAkB,EACjC,eAAe,EAAE,gBAAgB,EAE7D,cAAc,EAAE,2BAA2B,EACZ,OAAO,EAAE,mBAAmB;IAGxE,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;YAkBpC,qBAAqB;YASrB,mBAAmB;CA8BlC"}
1
+ {"version":3,"file":"delete-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/features/delete-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAClG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAE5F,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qBACa,oBAAoB;IAEC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAE5D,OAAO,CAAC,QAAQ,CAAC,cAAc;IACA,OAAO,CAAC,QAAQ,CAAC,OAAO;IAEvD,OAAO,CAAC,QAAQ,CAAC,cAAc;gBANgB,WAAW,EAAE,kBAAkB,EACjC,eAAe,EAAE,gBAAgB,EAE7D,cAAc,EAAE,2BAA2B,EACZ,OAAO,EAAE,mBAAmB,EAE3D,cAAc,EAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC;IAG3E,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;YAkBpE,qBAAqB;YAYrB,mBAAmB;CA0ClC"}
@@ -32,13 +32,15 @@ let DeleteFeatureUseCase = class DeleteFeatureUseCase {
32
32
  worktreeService;
33
33
  processService;
34
34
  runRepo;
35
- constructor(featureRepo, worktreeService, processService, runRepo) {
35
+ cleanupUseCase;
36
+ constructor(featureRepo, worktreeService, processService, runRepo, cleanupUseCase) {
36
37
  this.featureRepo = featureRepo;
37
38
  this.worktreeService = worktreeService;
38
39
  this.processService = processService;
39
40
  this.runRepo = runRepo;
41
+ this.cleanupUseCase = cleanupUseCase;
40
42
  }
41
- async execute(featureId) {
43
+ async execute(featureId, options) {
42
44
  // 1. Find feature (exact or prefix match)
43
45
  const feature = (await this.featureRepo.findById(featureId)) ??
44
46
  (await this.featureRepo.findByIdPrefix(featureId));
@@ -46,20 +48,20 @@ let DeleteFeatureUseCase = class DeleteFeatureUseCase {
46
48
  throw new Error(`Feature not found: "${featureId}"`);
47
49
  }
48
50
  // 2. Cascade delete all sub-features (depth-first)
49
- await this.cascadeDeleteChildren(feature.id);
51
+ await this.cascadeDeleteChildren(feature.id, options);
50
52
  // 3. Delete the feature itself
51
- await this.deleteSingleFeature(feature);
53
+ await this.deleteSingleFeature(feature, options);
52
54
  return feature;
53
55
  }
54
- async cascadeDeleteChildren(parentId) {
56
+ async cascadeDeleteChildren(parentId, options) {
55
57
  const children = await this.featureRepo.findByParentId(parentId);
56
58
  for (const child of children) {
57
59
  // Recurse into grandchildren first (depth-first)
58
- await this.cascadeDeleteChildren(child.id);
59
- await this.deleteSingleFeature(child);
60
+ await this.cascadeDeleteChildren(child.id, options);
61
+ await this.deleteSingleFeature(child, options);
60
62
  }
61
63
  }
62
- async deleteSingleFeature(feature) {
64
+ async deleteSingleFeature(feature, options) {
63
65
  // Cancel running/pending agent run if present
64
66
  if (feature.agentRunId) {
65
67
  const run = await this.runRepo.findById(feature.agentRunId);
@@ -75,13 +77,24 @@ let DeleteFeatureUseCase = class DeleteFeatureUseCase {
75
77
  await this.runRepo.updateStatus(run.id, AgentRunStatus.cancelled);
76
78
  }
77
79
  }
78
- // Remove worktree (ignore errors if already removed)
79
- const worktreePath = this.worktreeService.getWorktreePath(feature.repositoryPath, feature.branch);
80
- try {
81
- await this.worktreeService.remove(worktreePath);
80
+ // 4. Cleanup: either full cleanup (worktree + branches) or just worktree removal
81
+ const cleanup = options?.cleanup !== false;
82
+ if (cleanup) {
83
+ try {
84
+ await this.cleanupUseCase.execute(feature.id);
85
+ }
86
+ catch {
87
+ // Cleanup is best-effort — don't block deletion
88
+ }
82
89
  }
83
- catch {
84
- // Worktree might already be removed - that's fine
90
+ else {
91
+ const worktreePath = this.worktreeService.getWorktreePath(feature.repositoryPath, feature.branch);
92
+ try {
93
+ await this.worktreeService.remove(worktreePath);
94
+ }
95
+ catch {
96
+ // Worktree might already be removed - that's fine
97
+ }
85
98
  }
86
99
  // Delete feature record
87
100
  await this.featureRepo.delete(feature.id);
@@ -93,6 +106,7 @@ DeleteFeatureUseCase = __decorate([
93
106
  __param(1, inject('IWorktreeService')),
94
107
  __param(2, inject('IFeatureAgentProcessService')),
95
108
  __param(3, inject('IAgentRunRepository')),
96
- __metadata("design:paramtypes", [Object, Object, Object, Object])
109
+ __param(4, inject('CleanupFeatureWorktreeUseCase')),
110
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
97
111
  ], DeleteFeatureUseCase);
98
112
  export { DeleteFeatureUseCase };
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAkHrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAiRrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAmHrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAqRrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -77,6 +77,7 @@ import { ListRepositoriesUseCase } from '../../application/use-cases/repositorie
77
77
  import { DeleteRepositoryUseCase } from '../../application/use-cases/repositories/delete-repository.use-case.js';
78
78
  import { CheckAndUnblockFeaturesUseCase } from '../../application/use-cases/features/check-and-unblock-features.use-case.js';
79
79
  import { UpdateFeatureLifecycleUseCase } from '../../application/use-cases/features/update/update-feature-lifecycle.use-case.js';
80
+ import { CleanupFeatureWorktreeUseCase } from '../../application/use-cases/features/cleanup-feature-worktree.use-case.js';
80
81
  // Session listing
81
82
  import { ClaudeCodeSessionRepository } from '../services/agents/sessions/claude-code-session.repository.js';
82
83
  import { StubSessionRepository } from '../services/agents/sessions/stub-session.repository.js';
@@ -259,6 +260,7 @@ export async function initializeContainer() {
259
260
  // because the latter injects the former via class token.
260
261
  container.registerSingleton(CheckAndUnblockFeaturesUseCase);
261
262
  container.registerSingleton(UpdateFeatureLifecycleUseCase);
263
+ container.registerSingleton(CleanupFeatureWorktreeUseCase);
262
264
  // Session repositories (per-AgentType string tokens)
263
265
  container.register(`IAgentSessionRepository:${AgentType.ClaudeCode}`, {
264
266
  useFactory: () => new ClaudeCodeSessionRepository(),
@@ -334,6 +336,9 @@ export async function initializeContainer() {
334
336
  container.register('UpdateSettingsUseCase', {
335
337
  useFactory: (c) => c.resolve(UpdateSettingsUseCase),
336
338
  });
339
+ container.register('CleanupFeatureWorktreeUseCase', {
340
+ useFactory: (c) => c.resolve(CleanupFeatureWorktreeUseCase),
341
+ });
337
342
  _initialized = true;
338
343
  return container;
339
344
  }
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAe1B,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAU9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAiE1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkP/D"}
1
+ {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAe1B,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAW9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAiE1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAoP/D"}
@@ -24,6 +24,7 @@ import { setPhaseTimingContext, recordLifecycleEvent } from './phase-timing-cont
24
24
  import { setLifecycleContext } from './lifecycle-context.js';
25
25
  import { setLogPrefix, getLogPrefix } from './log-context.js';
26
26
  import { UpdateFeatureLifecycleUseCase } from '../../../../application/use-cases/features/update/update-feature-lifecycle.use-case.js';
27
+ import { CleanupFeatureWorktreeUseCase } from '../../../../application/use-cases/features/cleanup-feature-worktree.use-case.js';
27
28
  /**
28
29
  * Parse CLI arguments into a WorkerArgs object.
29
30
  * Throws if any required argument is missing.
@@ -167,6 +168,7 @@ export async function runWorker(args) {
167
168
  // Resolve merge node dependencies
168
169
  const gitPrService = container.resolve('IGitPrService');
169
170
  const featureRepository = container.resolve('IFeatureRepository');
171
+ const cleanupFeatureWorktreeUseCase = container.resolve(CleanupFeatureWorktreeUseCase);
170
172
  const graphDeps = {
171
173
  executor,
172
174
  mergeNodeDeps: {
@@ -176,6 +178,7 @@ export async function runWorker(args) {
176
178
  verifyMerge: (cwd, featureBranch, baseBranch) => gitPrService.verifyMerge(cwd, featureBranch, baseBranch),
177
179
  featureRepository,
178
180
  gitPrService,
181
+ cleanupFeatureWorktreeUseCase,
179
182
  },
180
183
  };
181
184
  // Use threadId for checkpoint path so resume runs share the same checkpoint DB.
@@ -16,6 +16,7 @@ import type { IAgentExecutor } from '../../../../../../application/ports/output/
16
16
  import type { FeatureAgentState } from '../../state.js';
17
17
  import type { IFeatureRepository } from '../../../../../../application/ports/output/repositories/feature-repository.interface.js';
18
18
  import type { DiffSummary, IGitPrService } from '../../../../../../application/ports/output/services/git-pr-service.interface.js';
19
+ import type { CleanupFeatureWorktreeUseCase } from '../../../../../../application/use-cases/features/cleanup-feature-worktree.use-case.js';
19
20
  export interface MergeNodeDeps {
20
21
  executor: IAgentExecutor;
21
22
  getDiffSummary: (cwd: string, baseBranch: string) => Promise<DiffSummary>;
@@ -28,6 +29,7 @@ export interface MergeNodeDeps {
28
29
  */
29
30
  verifyMerge: (cwd: string, featureBranch: string, baseBranch: string) => Promise<boolean>;
30
31
  gitPrService: IGitPrService;
32
+ cleanupFeatureWorktreeUseCase: Pick<CleanupFeatureWorktreeUseCase, 'execute'>;
31
33
  }
32
34
  /**
33
35
  * Factory that creates the merge node function.
@@ -1 +1 @@
1
- {"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACd,MAAM,iEAAiE,CAAC;AAmBzE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACnE;;;OAGG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,YAAY,EAAE,aAAa,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAsQ7E"}
1
+ {"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACd,MAAM,iEAAiE,CAAC;AAkBzE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uEAAuE,CAAC;AAE3H,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACnE;;;OAGG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1F,YAAY,EAAE,aAAa,CAAC;IAC5B,6BAA6B,EAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC,CAAC;CAC/E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CA0Q7E"}
@@ -231,6 +231,9 @@ export function createMergeNode(deps) {
231
231
  updatedAt: new Date(),
232
232
  });
233
233
  messages.push(`[merge] Feature lifecycle → ${newLifecycle}`);
234
+ if (merged) {
235
+ await deps.cleanupFeatureWorktreeUseCase.execute(feature.id);
236
+ }
234
237
  }
235
238
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
236
239
  await recordPhaseEnd(mergeTimingId, Date.now() - startTime);
@@ -18,7 +18,7 @@ export declare class WorktreeService implements IWorktreeService {
18
18
  private readonly execFile;
19
19
  constructor(execFile: ExecFunction);
20
20
  create(repoPath: string, branch: string, worktreePath: string, startPoint?: string): Promise<WorktreeInfo>;
21
- remove(worktreePath: string): Promise<void>;
21
+ remove(worktreePath: string, force?: boolean): Promise<void>;
22
22
  list(repoPath: string): Promise<WorktreeInfo[]>;
23
23
  exists(repoPath: string, branch: string): Promise<boolean>;
24
24
  branchExists(repoPath: string, branch: string): Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"worktree.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/worktree.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,0EAA0E,CAAC;AAOlF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjD,qBACa,eAAgB,YAAW,gBAAgB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAErE,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC;IAqBlB,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAO/C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1D,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWhE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1D,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAMzD,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;CAU9B"}
1
+ {"version":3,"file":"worktree.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/worktree.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,0EAA0E,CAAC;AAOlF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjD,qBACa,eAAgB,YAAW,gBAAgB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAErE,MAAM,CACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC;IAqBlB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAO/C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1D,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWhE,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWtE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1D,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAMzD,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;CAU9B"}
@@ -48,9 +48,13 @@ let WorktreeService = class WorktreeService {
48
48
  }
49
49
  return created;
50
50
  }
51
- async remove(worktreePath) {
51
+ async remove(worktreePath, force) {
52
52
  try {
53
- await this.execFile('git', ['worktree', 'remove', worktreePath], {});
53
+ const args = ['worktree', 'remove'];
54
+ if (force)
55
+ args.push('--force');
56
+ args.push(worktreePath);
57
+ await this.execFile('git', args, {});
54
58
  }
55
59
  catch (error) {
56
60
  throw this.parseGitError(error);
@@ -2,12 +2,14 @@
2
2
  * Feature Delete Command
3
3
  *
4
4
  * Deletes a feature, its worktree, and cancels any running agent.
5
+ * Optionally cleans up worktree and branches (local + remote).
5
6
  *
6
- * Usage: shep feat del <id> [--force]
7
+ * Usage: shep feat del <id> [--force] [--no-cleanup]
7
8
  *
8
9
  * @example
9
10
  * $ shep feat del feat-123
10
11
  * $ shep feat del feat-123 --force
12
+ * $ shep feat del feat-123 --force --no-cleanup
11
13
  */
12
14
  import { Command } from 'commander';
13
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"del.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/del.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAoC1C"}
1
+ {"version":3,"file":"del.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/del.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAmD1C"}
@@ -2,12 +2,14 @@
2
2
  * Feature Delete Command
3
3
  *
4
4
  * Deletes a feature, its worktree, and cancels any running agent.
5
+ * Optionally cleans up worktree and branches (local + remote).
5
6
  *
6
- * Usage: shep feat del <id> [--force]
7
+ * Usage: shep feat del <id> [--force] [--no-cleanup]
7
8
  *
8
9
  * @example
9
10
  * $ shep feat del feat-123
10
11
  * $ shep feat del feat-123 --force
12
+ * $ shep feat del feat-123 --force --no-cleanup
11
13
  */
12
14
  import { Command } from 'commander';
13
15
  import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
@@ -23,6 +25,7 @@ export function createDelCommand() {
23
25
  .description('Delete a feature')
24
26
  .argument('<id>', 'Feature ID or prefix')
25
27
  .option('-f, --force', 'Skip confirmation prompt')
28
+ .option('--no-cleanup', 'Skip worktree and branch cleanup')
26
29
  .action(async (featureId, options) => {
27
30
  try {
28
31
  // First show what we're about to delete
@@ -38,12 +41,26 @@ export function createDelCommand() {
38
41
  return;
39
42
  }
40
43
  }
44
+ // Determine cleanup preference
45
+ let cleanup = true;
46
+ if (options.cleanup === false) {
47
+ cleanup = false;
48
+ }
49
+ else if (!options.force) {
50
+ cleanup = await confirm({
51
+ message: 'Also clean up worktree and branches?',
52
+ default: true,
53
+ });
54
+ }
41
55
  const deleteUseCase = container.resolve(DeleteFeatureUseCase);
42
- await deleteUseCase.execute(feature.id);
56
+ await deleteUseCase.execute(feature.id, { cleanup });
43
57
  messages.newline();
44
58
  messages.success('Feature deleted');
45
59
  console.log(` ${colors.muted('Name:')} ${feature.name}`);
46
60
  console.log(` ${colors.muted('Branch:')} ${feature.branch}`);
61
+ if (cleanup) {
62
+ console.log(` ${colors.muted('Cleanup:')} worktree, local branch, remote branch`);
63
+ }
47
64
  messages.newline();
48
65
  }
49
66
  catch (error) {
@@ -1,5 +1,5 @@
1
1
  import type { Feature } from '../../../../../packages/core/src/domain/generated/output.js';
2
- export declare function deleteFeature(featureId: string): Promise<{
2
+ export declare function deleteFeature(featureId: string, cleanup?: boolean): Promise<{
3
3
  feature?: Feature;
4
4
  error?: string;
5
5
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"delete-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/delete-feature.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAEpE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAahD"}
1
+ {"version":3,"file":"delete-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/delete-feature.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAEpE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBhD"}
@@ -1,12 +1,14 @@
1
1
  'use server';
2
2
  import { resolve } from '../../lib/server-container.js';
3
- export async function deleteFeature(featureId) {
3
+ export async function deleteFeature(featureId, cleanup) {
4
4
  if (!featureId?.trim()) {
5
5
  return { error: 'id is required' };
6
6
  }
7
7
  try {
8
8
  const deleteFeatureUseCase = resolve('DeleteFeatureUseCase');
9
- const feature = await deleteFeatureUseCase.execute(featureId);
9
+ const feature = cleanup !== undefined
10
+ ? await deleteFeatureUseCase.execute(featureId, { cleanup })
11
+ : await deleteFeatureUseCase.execute(featureId);
10
12
  return { feature };
11
13
  }
12
14
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,wBAAwB,2CAkjBlF"}
1
+ {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAqCA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,wBAAwB,2CA6hBlF"}
@@ -20,7 +20,7 @@ import { DeploymentStatusBadge } from '../../common/deployment-status-badge/inde
20
20
  import { DrawerTitle, DrawerDescription } from '../../ui/drawer.js';
21
21
  import { Button } from '../../ui/button.js';
22
22
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
23
- import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '../../ui/alert-dialog.js';
23
+ import { DeleteFeatureDialog } from '../../common/delete-feature-dialog/index.js';
24
24
  import { ActionButton } from '../../common/action-button/index.js';
25
25
  import { OpenActionMenu } from '../../common/open-action-menu/index.js';
26
26
  import { FeatureDrawerTabs } from '../../common/feature-drawer-tabs/index.js';
@@ -111,6 +111,7 @@ export function FeatureDrawerClient({ view: initialView }) {
111
111
  const [mergeData, setMergeData] = useState(null);
112
112
  // ── Delete state ───────────────────────────────────────────────────────
113
113
  const [isDeleting, setIsDeleting] = useState(false);
114
+ const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
114
115
  // ── Shared reject state ────────────────────────────────────────────────
115
116
  const [isRejecting, setIsRejecting] = useState(false);
116
117
  const isRejectingRef = useRef(false);
@@ -261,10 +262,10 @@ export function FeatureDrawerClient({ view: initialView }) {
261
262
  }, [view, featureNode, prdData, prdSelections, onClose]);
262
263
  const handleTechApprove = useCallback(() => handleSimpleApprove('Plan'), [handleSimpleApprove]);
263
264
  const handleMergeApprove = useCallback(() => handleSimpleApprove('Merge'), [handleSimpleApprove]);
264
- const handleDelete = useCallback(async (featureId) => {
265
+ const handleDelete = useCallback(async (featureId, cleanup) => {
265
266
  setIsDeleting(true);
266
267
  try {
267
- const result = await deleteFeature(featureId);
268
+ const result = await deleteFeature(featureId, cleanup);
268
269
  if (result.error) {
269
270
  toast.error(result.error);
270
271
  return;
@@ -317,7 +318,7 @@ export function FeatureDrawerClient({ view: initialView }) {
317
318
  const repoName = featureNode.repositoryName ??
318
319
  featureNode.repositoryPath.split('/').filter(Boolean).at(-1) ??
319
320
  '';
320
- header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), repoName ? (_jsxs("div", { className: "flex items-center gap-1.5 pt-0.5", children: [_jsx(Code2, { className: "text-muted-foreground size-3.5 shrink-0" }), featureNode.remoteUrl ? (_jsxs("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs transition-colors", "data-testid": "feature-drawer-repo-link", children: [repoName, _jsx(ExternalLink, { className: "size-3" })] })) : (_jsx("span", { className: "text-muted-foreground text-xs", children: repoName }))] })) : null, _jsx(DrawerDescription, { className: "sr-only", children: featureNode.name })] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", "data-testid": "feature-drawer-actions", children: [_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, showSpecs: !!featureActionsInput.specPath }), featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: featureDeployTarget?.targetId })) : null] })) : null, _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [_jsx("code", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: shortId }), _jsx("button", { type: "button", onClick: handleCopyId, className: "text-muted-foreground hover:text-foreground inline-flex items-center rounded p-0.5 transition-colors", "aria-label": "Copy feature ID", "data-testid": "feature-drawer-copy-id", children: idCopied ? (_jsx(Check, { className: "size-3.5 text-green-600" })) : (_jsx(Copy, { className: "size-3.5" })) })] }), featureNode.featureId ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive", "data-testid": "feature-drawer-delete", children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: featureNode.name }), " (", featureNode.featureId, "). This action cannot be undone.", featureNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => handleDelete(featureNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] })) : null] })) : null] }));
321
+ header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), repoName ? (_jsxs("div", { className: "flex items-center gap-1.5 pt-0.5", children: [_jsx(Code2, { className: "text-muted-foreground size-3.5 shrink-0" }), featureNode.remoteUrl ? (_jsxs("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs transition-colors", "data-testid": "feature-drawer-repo-link", children: [repoName, _jsx(ExternalLink, { className: "size-3" })] })) : (_jsx("span", { className: "text-muted-foreground text-xs", children: repoName }))] })) : null, _jsx(DrawerDescription, { className: "sr-only", children: featureNode.name })] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", "data-testid": "feature-drawer-actions", children: [_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, showSpecs: !!featureActionsInput.specPath }), featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: featureDeployTarget?.targetId })) : null] })) : null, _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [_jsx("code", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: shortId }), _jsx("button", { type: "button", onClick: handleCopyId, className: "text-muted-foreground hover:text-foreground inline-flex items-center rounded p-0.5 transition-colors", "aria-label": "Copy feature ID", "data-testid": "feature-drawer-copy-id", children: idCopied ? (_jsx(Check, { className: "size-3.5 text-green-600" })) : (_jsx(Copy, { className: "size-3.5" })) })] }), featureNode.featureId ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive", "data-testid": "feature-drawer-delete", onClick: () => setDeleteDialogOpen(true), children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }), _jsx(DeleteFeatureDialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, onConfirm: (cleanup) => handleDelete(featureNode.featureId, cleanup), isDeleting: isDeleting, featureName: featureNode.name, featureId: featureNode.featureId })] })) : null] })) : null] }));
321
322
  }
322
323
  // ── Body ──────────────────────────────────────────────────────────────
323
324
  let body = null;
@@ -0,0 +1,9 @@
1
+ export interface DeleteFeatureDialogProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ onConfirm: (cleanup: boolean) => void;
5
+ isDeleting: boolean;
6
+ featureName: string;
7
+ featureId: string;
8
+ }
9
+ //# sourceMappingURL=delete-feature-dialog-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-feature-dialog-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog-config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,3 @@
1
+ import type { DeleteFeatureDialogProps } from './delete-feature-dialog-config.js';
2
+ export declare function DeleteFeatureDialog({ open, onOpenChange, onConfirm, isDeleting, featureName, featureId, }: DeleteFeatureDialogProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=delete-feature-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-feature-dialog.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE/E,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,UAAU,EACV,WAAW,EACX,SAAS,GACV,EAAE,wBAAwB,2CAqD1B"}
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Loader2 } from 'lucide-react';
5
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '../../ui/alert-dialog.js';
6
+ import { Checkbox } from '../../ui/checkbox.js';
7
+ import { Label } from '../../ui/label.js';
8
+ export function DeleteFeatureDialog({ open, onOpenChange, onConfirm, isDeleting, featureName, featureId, }) {
9
+ const [cleanup, setCleanup] = useState(true);
10
+ useEffect(() => {
11
+ if (open) {
12
+ setCleanup(true);
13
+ }
14
+ }, [open]);
15
+ return (_jsx(AlertDialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: featureName }), " (", featureId, "). This action cannot be undone."] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: "cleanup-checkbox", checked: cleanup, onCheckedChange: (checked) => setCleanup(checked === true), disabled: isDeleting, "aria-label": "Clean up worktree and branches" }), _jsx(Label, { htmlFor: "cleanup-checkbox", className: "cursor-pointer text-sm", children: "Clean up worktree and branches" })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, onClick: () => onOpenChange(false), children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onConfirm(cleanup), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] }) }));
16
+ }
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { DeleteFeatureDialog } from './delete-feature-dialog.js';
3
+ declare const meta: Meta<typeof DeleteFeatureDialog>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof DeleteFeatureDialog>;
6
+ export declare const Default: Story;
7
+ export declare const Deleting: Story;
8
+ //# sourceMappingURL=delete-feature-dialog.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-feature-dialog.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/delete-feature-dialog/delete-feature-dialog.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAe1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,eAAO,MAAM,QAAQ,EAAE,KAItB,CAAC"}