@shepai/cli 1.90.1 → 1.91.0-pr257.0ec533a

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 (269) hide show
  1. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +6 -0
  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.map +1 -1
  4. package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.js +8 -0
  5. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +1 -0
  6. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +8 -0
  8. package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.d.ts +11 -0
  9. package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.d.ts.map +1 -0
  10. package/dist/src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +49 -0
  11. package/dist/src/presentation/web/app/(dashboard)/feature/[featureId]/[tab]/page.d.ts +3 -0
  12. package/dist/src/presentation/web/app/(dashboard)/feature/[featureId]/[tab]/page.d.ts.map +1 -0
  13. package/dist/src/presentation/web/app/(dashboard)/feature/[featureId]/[tab]/page.js +4 -0
  14. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts +1 -0
  15. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts.map +1 -1
  16. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.js +3 -0
  17. package/dist/src/presentation/web/app/api/attachments/preview/route.d.ts.map +1 -1
  18. package/dist/src/presentation/web/app/api/attachments/preview/route.js +47 -11
  19. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts +4 -0
  20. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.js +17 -0
  22. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts +4 -2
  23. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +2 -2
  25. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.js +9 -6
  27. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts +3 -1
  28. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts.map +1 -1
  29. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.js +94 -5
  30. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts.map +1 -1
  31. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.js +2 -1
  32. package/dist/src/presentation/web/components/common/inline-attachments/index.d.ts +3 -0
  33. package/dist/src/presentation/web/components/common/inline-attachments/index.d.ts.map +1 -0
  34. package/dist/src/presentation/web/components/common/inline-attachments/index.js +1 -0
  35. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.d.ts +20 -0
  36. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.d.ts.map +1 -0
  37. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.js +72 -0
  38. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.stories.d.ts +16 -0
  39. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.stories.d.ts.map +1 -0
  40. package/dist/src/presentation/web/components/common/inline-attachments/inline-attachments.stories.js +46 -0
  41. package/dist/src/presentation/web/hooks/use-selected-feature-id.js +1 -1
  42. package/dist/tsconfig.build.tsbuildinfo +1 -1
  43. package/package.json +1 -1
  44. package/web/.next/BUILD_ID +1 -1
  45. package/web/.next/app-path-routes-manifest.json +2 -0
  46. package/web/.next/build-manifest.json +2 -2
  47. package/web/.next/fallback-build-manifest.json +2 -2
  48. package/web/.next/prerender-manifest.json +3 -3
  49. package/web/.next/required-server-files.js +1 -1
  50. package/web/.next/required-server-files.json +1 -1
  51. package/web/.next/routes-manifest.json +9 -0
  52. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +18 -18
  53. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  54. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  55. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  56. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/app-paths-manifest.json +3 -0
  57. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/build-manifest.json +18 -0
  58. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/next-font-manifest.json +6 -0
  59. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/react-loadable-manifest.json +1 -0
  60. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +320 -0
  61. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +20 -0
  62. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.map +5 -0
  63. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -0
  64. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +2 -0
  65. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +21 -21
  66. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +2 -2
  67. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  68. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  69. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  70. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  71. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  72. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  73. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +18 -18
  74. package/web/.next/server/app/(dashboard)/create/page.js +1 -1
  75. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  76. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  77. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/app-paths-manifest.json +3 -0
  78. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/build-manifest.json +18 -0
  79. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/next-font-manifest.json +6 -0
  80. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/react-loadable-manifest.json +1 -0
  81. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +320 -0
  82. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +20 -0
  83. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.map +5 -0
  84. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -0
  85. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +2 -0
  86. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +21 -21
  87. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +2 -2
  88. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  89. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  90. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +14 -14
  91. package/web/.next/server/app/(dashboard)/page.js +1 -1
  92. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  93. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  94. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  95. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  96. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  97. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app/_global-error/page.js +1 -1
  99. package/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  100. package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  101. package/web/.next/server/app/_global-error.html +2 -2
  102. package/web/.next/server/app/_global-error.rsc +1 -1
  103. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  104. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  105. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  106. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  107. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  108. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  109. package/web/.next/server/app/_not-found/page.js +1 -1
  110. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  111. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  112. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  113. package/web/.next/server/app/api/feature-logs/route.js +1 -1
  114. package/web/.next/server/app/api/feature-logs/route.js.nft.json +1 -1
  115. package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
  116. package/web/.next/server/app/settings/page.js +1 -1
  117. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  118. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  119. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  120. package/web/.next/server/app/skills/page.js +2 -2
  121. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  122. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  123. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  124. package/web/.next/server/app/tools/page.js +2 -2
  125. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  126. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  127. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  128. package/web/.next/server/app/version/page.js +1 -1
  129. package/web/.next/server/app/version/page.js.nft.json +1 -1
  130. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  131. package/web/.next/server/app-paths-manifest.json +2 -0
  132. package/web/.next/server/chunks/[root-of-the-server]__0b10355c._.js +1 -1
  133. package/web/.next/server/chunks/[root-of-the-server]__0b10355c._.js.map +1 -1
  134. package/web/.next/server/chunks/{[root-of-the-server]__d8037e14._.js → [root-of-the-server]__52c318d1._.js} +2 -2
  135. package/web/.next/server/chunks/ssr/403f9_next_dist_esm_build_templates_app-page_c29a2302.js +4 -0
  136. package/web/.next/server/chunks/ssr/403f9_next_dist_esm_build_templates_app-page_c29a2302.js.map +1 -0
  137. package/web/.next/server/chunks/ssr/403f9_next_dist_esm_build_templates_app-page_d1fd387b.js +4 -0
  138. package/web/.next/server/chunks/ssr/403f9_next_dist_esm_build_templates_app-page_d1fd387b.js.map +1 -0
  139. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  140. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_81a06555._.js +3 -0
  142. package/web/.next/server/chunks/ssr/{7f428_lucide-react_dist_esm_icons_9027d30a._.js.map → 7f428_lucide-react_dist_esm_icons_81a06555._.js.map} +1 -1
  143. package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js +3 -0
  144. package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js.map +1 -0
  145. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +1 -1
  146. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -1
  147. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +1 -1
  148. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -1
  149. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
  150. package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__17143953._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  154. package/web/.next/server/chunks/ssr/[root-of-the-server]__45aad79d._.js +3 -0
  155. package/web/.next/server/chunks/ssr/[root-of-the-server]__45aad79d._.js.map +1 -0
  156. package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js +1 -1
  157. package/web/.next/server/chunks/ssr/[root-of-the-server]__5cc4752a._.js +3 -0
  158. package/web/.next/server/chunks/ssr/[root-of-the-server]__5cc4752a._.js.map +1 -0
  159. package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
  160. package/web/.next/server/chunks/ssr/{[root-of-the-server]__f0d8d054._.js → [root-of-the-server]__89e8a5cc._.js} +3 -3
  161. package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js.map +1 -0
  162. package/web/.next/server/chunks/ssr/{[root-of-the-server]__248ee887._.js → [root-of-the-server]__8d9536c4._.js} +2 -2
  163. package/web/.next/server/chunks/ssr/[root-of-the-server]__94128fa9._.js +3 -0
  164. package/web/.next/server/chunks/ssr/[root-of-the-server]__94128fa9._.js.map +1 -0
  165. package/web/.next/server/chunks/ssr/[root-of-the-server]__9bfb8e7c._.js +3 -0
  166. package/web/.next/server/chunks/ssr/[root-of-the-server]__9bfb8e7c._.js.map +1 -0
  167. package/web/.next/server/chunks/ssr/[root-of-the-server]__9dc40036._.js +3 -0
  168. package/web/.next/server/chunks/ssr/[root-of-the-server]__9dc40036._.js.map +1 -0
  169. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js +1 -1
  170. package/web/.next/server/chunks/ssr/[root-of-the-server]__9de266fa._.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  172. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  173. package/web/.next/server/chunks/ssr/[root-of-the-server]__b65f78cf._.js +3 -0
  174. package/web/.next/server/chunks/ssr/{[root-of-the-server]__b3a4cef4._.js → [root-of-the-server]__e630cc47._.js} +2 -2
  175. package/web/.next/server/chunks/ssr/[root-of-the-server]__e630cc47._.js.map +1 -0
  176. package/web/.next/server/chunks/ssr/{[root-of-the-server]__b062b383._.js → [root-of-the-server]__f1a05100._.js} +2 -2
  177. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9bc1434f._.js → [root-of-the-server]__f8210f45._.js} +2 -2
  178. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
  179. package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
  180. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  181. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  182. package/web/.next/server/chunks/ssr/{_752e01fd._.js → _21c75883._.js} +2 -2
  183. package/web/.next/server/chunks/ssr/{_752e01fd._.js.map → _21c75883._.js.map} +1 -1
  184. package/web/.next/server/chunks/ssr/_3533fed7._.js +3 -0
  185. package/web/.next/server/chunks/ssr/_3533fed7._.js.map +1 -0
  186. package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
  187. package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/_922aa39f._.js +3 -0
  189. package/web/.next/server/chunks/ssr/_922aa39f._.js.map +1 -0
  190. package/web/.next/server/chunks/ssr/_a5c23e45._.js +3 -0
  191. package/web/.next/server/chunks/ssr/_a5c23e45._.js.map +1 -0
  192. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  193. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  194. package/web/.next/server/chunks/ssr/{_2fa756cd._.js → _ef1cbadb._.js} +2 -2
  195. package/web/.next/server/chunks/ssr/{_2fa756cd._.js.map → _ef1cbadb._.js.map} +1 -1
  196. package/web/.next/server/chunks/ssr/_f50485a5._.js +3 -0
  197. package/web/.next/server/chunks/ssr/_f50485a5._.js.map +1 -0
  198. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  199. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  200. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +1 -1
  201. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -1
  202. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  203. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  204. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  205. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  206. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_feature_[featureId]_[tab]_page_tsx_40a5d287._.js +3 -0
  207. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_feature_[featureId]_[tab]_page_tsx_40a5d287._.js.map +1 -0
  208. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js +2 -2
  209. package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js.map +1 -1
  210. package/web/.next/server/chunks/ssr/src_presentation_web_components_a5e6c910._.js +3 -0
  211. package/web/.next/server/chunks/ssr/src_presentation_web_components_a5e6c910._.js.map +1 -0
  212. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  213. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
  214. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  215. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
  216. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  217. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  218. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js +2 -2
  219. package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js.map +1 -1
  220. package/web/.next/server/pages/500.html +2 -2
  221. package/web/.next/server/server-reference-manifest.js +1 -1
  222. package/web/.next/server/server-reference-manifest.json +322 -28
  223. package/web/.next/static/chunks/2a09571d38368a18.css +2 -0
  224. package/web/.next/static/chunks/{132ff681f7e12121.js → 2b57a812d425e46c.js} +1 -1
  225. package/web/.next/static/chunks/30a344bb33a015e4.js +1 -0
  226. package/web/.next/static/chunks/{4354b4b30513e7f0.js → 349683fd8a55926e.js} +2 -2
  227. package/web/.next/static/chunks/{4906aba274bc6920.js → 50f823c5bd79359a.js} +1 -1
  228. package/web/.next/static/chunks/5ab0d19719a78f8a.js +1 -0
  229. package/web/.next/static/chunks/{54de5c2f98832b92.js → 5ec3d76ca618c32a.js} +1 -1
  230. package/web/.next/static/chunks/{38bb02c07a427f1e.js → b7a4219b1107049b.js} +1 -1
  231. package/web/.next/static/chunks/ba35a8119b89113c.js +1 -0
  232. package/web/.next/static/chunks/{7c7da9e978216d2b.js → bdfe416e656a9558.js} +1 -1
  233. package/web/.next/static/chunks/d9247a52ae260218.js +1 -0
  234. package/web/.next/static/chunks/e3553e79bd410414.js +11 -0
  235. package/web/.next/static/chunks/{0cbb35f940c9feef.js → e4e7979e34b7df8d.js} +1 -1
  236. package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_9027d30a._.js +0 -3
  237. package/web/.next/server/chunks/ssr/[root-of-the-server]__4af0afe0._.js +0 -3
  238. package/web/.next/server/chunks/ssr/[root-of-the-server]__b3a4cef4._.js.map +0 -1
  239. package/web/.next/server/chunks/ssr/[root-of-the-server]__c2173b6d._.js +0 -3
  240. package/web/.next/server/chunks/ssr/[root-of-the-server]__c2173b6d._.js.map +0 -1
  241. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3c963c6._.js +0 -3
  242. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3c963c6._.js.map +0 -1
  243. package/web/.next/server/chunks/ssr/[root-of-the-server]__f0d8d054._.js.map +0 -1
  244. package/web/.next/server/chunks/ssr/_411648c4._.js +0 -3
  245. package/web/.next/server/chunks/ssr/_411648c4._.js.map +0 -1
  246. package/web/.next/server/chunks/ssr/_903aed47._.js +0 -3
  247. package/web/.next/server/chunks/ssr/_903aed47._.js.map +0 -1
  248. package/web/.next/server/chunks/ssr/_cc46119f._.js +0 -3
  249. package/web/.next/server/chunks/ssr/_cc46119f._.js.map +0 -1
  250. package/web/.next/server/chunks/ssr/_f38b49fe._.js +0 -3
  251. package/web/.next/server/chunks/ssr/_f38b49fe._.js.map +0 -1
  252. package/web/.next/server/chunks/ssr/node_modules__pnpm_c931457d._.js +0 -3
  253. package/web/.next/server/chunks/ssr/node_modules__pnpm_c931457d._.js.map +0 -1
  254. package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js +0 -3
  255. package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js.map +0 -1
  256. package/web/.next/static/chunks/1e0cfdcb44a16493.js +0 -1
  257. package/web/.next/static/chunks/5c55da0e28e6cdc8.js +0 -1
  258. package/web/.next/static/chunks/bb3e32c60cb2e794.js +0 -11
  259. package/web/.next/static/chunks/c0f23bc23fd8b8ad.js +0 -1
  260. package/web/.next/static/chunks/cb5c85c5e16e82d3.js +0 -1
  261. package/web/.next/static/chunks/f98eb6cb17b61cb2.css +0 -2
  262. /package/web/.next/server/chunks/{[root-of-the-server]__d8037e14._.js.map → [root-of-the-server]__52c318d1._.js.map} +0 -0
  263. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__248ee887._.js.map → [root-of-the-server]__8d9536c4._.js.map} +0 -0
  264. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__4af0afe0._.js.map → [root-of-the-server]__b65f78cf._.js.map} +0 -0
  265. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__b062b383._.js.map → [root-of-the-server]__f1a05100._.js.map} +0 -0
  266. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__9bc1434f._.js.map → [root-of-the-server]__f8210f45._.js.map} +0 -0
  267. /package/web/.next/static/{o8F4OKh6WJmRpbTqaCZ67 → TduNW421ayOJTfqE7Kf_f}/_buildManifest.js +0 -0
  268. /package/web/.next/static/{o8F4OKh6WJmRpbTqaCZ67 → TduNW421ayOJTfqE7Kf_f}/_clientMiddlewareManifest.json +0 -0
  269. /package/web/.next/static/{o8F4OKh6WJmRpbTqaCZ67 → TduNW421ayOJTfqE7Kf_f}/_ssgManifest.js +0 -0
@@ -97,6 +97,12 @@ export interface IWorktreeService {
97
97
  * @returns Computed worktree path (e.g., /repo/.worktrees/branch-name)
98
98
  */
99
99
  getWorktreePath(repoPath: string, branch: string): string;
100
+ /**
101
+ * Prune stale worktree entries whose directories no longer exist.
102
+ *
103
+ * @param repoPath - Path to the git repository
104
+ */
105
+ prune(repoPath: string): Promise<void>;
100
106
  /**
101
107
  * Ensure a directory is a valid git repository with at least one commit.
102
108
  * If the directory is not a git repo, initializes it with `git init`
@@ -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;;;;;;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"}
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;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;;;;;;OAOG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD"}
@@ -1 +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"}
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;CA4ChD"}
@@ -44,6 +44,14 @@ let CleanupFeatureWorktreeUseCase = class CleanupFeatureWorktreeUseCase {
44
44
  catch (err) {
45
45
  // eslint-disable-next-line no-console
46
46
  console.warn('[CleanupFeatureWorktreeUseCase] worktree remove failed:', err);
47
+ // Prune stale worktree entries so the branch is no longer considered "in use"
48
+ try {
49
+ await this.worktreeService.prune(feature.repositoryPath);
50
+ }
51
+ catch (pruneErr) {
52
+ // eslint-disable-next-line no-console
53
+ console.warn('[CleanupFeatureWorktreeUseCase] worktree prune failed:', pruneErr);
54
+ }
47
55
  }
48
56
  // Step 2: Delete the local feature branch
49
57
  try {
@@ -19,6 +19,7 @@ export declare class WorktreeService implements IWorktreeService {
19
19
  constructor(execFile: ExecFunction);
20
20
  create(repoPath: string, branch: string, worktreePath: string, startPoint?: string): Promise<WorktreeInfo>;
21
21
  remove(worktreePath: string, force?: boolean): Promise<void>;
22
+ prune(repoPath: string): Promise<void>;
22
23
  list(repoPath: string): Promise<WorktreeInfo[]>;
23
24
  exists(repoPath: string, branch: string): Promise<boolean>;
24
25
  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,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"}
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,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtC,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"}
@@ -60,6 +60,14 @@ let WorktreeService = class WorktreeService {
60
60
  throw this.parseGitError(error);
61
61
  }
62
62
  }
63
+ async prune(repoPath) {
64
+ try {
65
+ await this.execFile('git', ['worktree', 'prune'], { cwd: repoPath });
66
+ }
67
+ catch (error) {
68
+ throw this.parseGitError(error);
69
+ }
70
+ }
63
71
  async list(repoPath) {
64
72
  const { stdout } = await this.execFile('git', ['worktree', 'list', '--porcelain'], {
65
73
  cwd: repoPath,
@@ -0,0 +1,11 @@
1
+ /** Skip static pre-rendering since we need runtime DI container. */
2
+ export declare const dynamic = "force-dynamic";
3
+ interface FeatureDrawerTabPageProps {
4
+ params: Promise<{
5
+ featureId: string;
6
+ tab: string;
7
+ }>;
8
+ }
9
+ export default function FeatureDrawerTabPage({ params }: FeatureDrawerTabPageProps): Promise<import("react/jsx-runtime").JSX.Element | null>;
10
+ export {};
11
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/presentation/web/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.tsx"],"names":[],"mappings":"AAaA,oEAAoE;AACpE,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,UAAU,yBAAyB;IACjC,MAAM,EAAE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,wBAA8B,oBAAoB,CAAC,EAAE,MAAM,EAAE,EAAE,yBAAyB,2DA8CvF"}
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { resolve } from '../../../../../../lib/server-container.js';
3
+ import { buildFeatureNodeData } from '../../../../../build-feature-node-data.js';
4
+ import { computeDrawerView, parseTabKey, } from '../../../../../../components/common/control-center-drawer/drawer-view.js';
5
+ import { FeatureDrawerClient } from '../../../../../../components/common/control-center-drawer/feature-drawer-client.js';
6
+ /** Skip static pre-rendering since we need runtime DI container. */
7
+ export const dynamic = 'force-dynamic';
8
+ export default async function FeatureDrawerTabPage({ params }) {
9
+ const { featureId, tab } = await params;
10
+ const urlTab = parseTabKey(tab);
11
+ try {
12
+ const featureRepo = resolve('IFeatureRepository');
13
+ const agentRunRepo = resolve('IAgentRunRepository');
14
+ const repoRepo = resolve('IRepositoryRepository');
15
+ const gitPrService = resolve('IGitPrService');
16
+ const feature = await featureRepo.findById(featureId);
17
+ if (!feature)
18
+ return null;
19
+ const run = feature.agentRunId ? await agentRunRepo.findById(feature.agentRunId) : null;
20
+ const getArtifact = resolve('GetFeatureArtifactUseCase');
21
+ const [repo, baseBranch, artifact, remoteUrl] = await Promise.all([
22
+ repoRepo.findByPath(feature.repositoryPath).catch(() => null),
23
+ gitPrService.getDefaultBranch(feature.repositoryPath).catch(() => 'main'),
24
+ getArtifact.execute(featureId).catch(() => null),
25
+ gitPrService.getRemoteUrl(feature.repositoryPath).catch(() => null),
26
+ ]);
27
+ const nodeData = buildFeatureNodeData(feature, run, {
28
+ repositoryName: repo?.name,
29
+ baseBranch,
30
+ oneLiner: artifact?.oneLiner,
31
+ remoteUrl: remoteUrl ?? undefined,
32
+ });
33
+ const view = computeDrawerView({
34
+ selectedNode: nodeData,
35
+ isCreateDrawerOpen: false,
36
+ pendingRepositoryPath: '',
37
+ pendingParentFeatureId: undefined,
38
+ selectedRepoNode: null,
39
+ features: [],
40
+ workflowDefaults: undefined,
41
+ });
42
+ if (!view)
43
+ return null;
44
+ return _jsx(FeatureDrawerClient, { view: view, urlTab: urlTab });
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
@@ -0,0 +1,3 @@
1
+ /** Children slot stub — canvas is rendered by the layout. */
2
+ export default function FeatureTabPage(): null;
3
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/presentation/web/app/(dashboard)/feature/[featureId]/[tab]/page.tsx"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,CAAC,OAAO,UAAU,cAAc,SAErC"}
@@ -0,0 +1,4 @@
1
+ /** Children slot stub — canvas is rendered by the layout. */
2
+ export default function FeatureTabPage() {
3
+ return null;
4
+ }
@@ -11,6 +11,7 @@ export interface RejectionFeedbackData {
11
11
  iteration: number;
12
12
  message: string;
13
13
  phase?: string;
14
+ attachments?: string[];
14
15
  }
15
16
  type GetPhaseTimingsResult = {
16
17
  timings: PhaseTimingData[];
@@ -1 +1 @@
1
- {"version":3,"file":"get-feature-phase-timings.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-phase-timings.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,qBAAqB,GACtB;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAAE,GAC1E;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA2B9F"}
1
+ {"version":3,"file":"get-feature-phase-timings.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-phase-timings.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,KAAK,qBAAqB,GACtB;IAAE,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,iBAAiB,EAAE,qBAAqB,EAAE,CAAA;CAAE,GAC1E;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtB,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA2B9F"}
@@ -42,6 +42,9 @@ async function readRejectionFeedback(featureId) {
42
42
  iteration: Number(entry.iteration ?? 1),
43
43
  message: String(entry.message ?? ''),
44
44
  phase: entry.phase ? String(entry.phase) : undefined,
45
+ attachments: Array.isArray(entry.attachments)
46
+ ? entry.attachments.map(String)
47
+ : undefined,
45
48
  }));
46
49
  }
47
50
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/attachments/preview/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsB3C,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA6BrE"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/attachments/preview/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA8D3C,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA0BrE"}
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from 'next/server';
2
- import { readFile, stat } from 'fs/promises';
3
- import { extname, resolve } from 'path';
2
+ import { readFile, stat, readdir } from 'fs/promises';
3
+ import { basename, extname, join, resolve } from 'path';
4
4
  import { getShepHomeDir } from '../../../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
5
5
  const MIME_MAP = {
6
6
  '.png': 'image/png',
@@ -18,6 +18,44 @@ const MIME_MAP = {
18
18
  '.yaml': 'text/yaml',
19
19
  '.yml': 'text/yaml',
20
20
  };
21
+ /**
22
+ * When the exact path doesn't exist (e.g. pending-<id> was renamed to <slug>),
23
+ * search all sibling attachment directories for the same filename.
24
+ */
25
+ async function findAttachmentFallback(requestedPath, attachmentsRoot) {
26
+ const filename = basename(requestedPath);
27
+ try {
28
+ const dirs = await readdir(attachmentsRoot, { withFileTypes: true });
29
+ for (const entry of dirs) {
30
+ if (!entry.isDirectory())
31
+ continue;
32
+ const candidate = join(attachmentsRoot, entry.name, filename);
33
+ try {
34
+ await stat(candidate);
35
+ return candidate;
36
+ }
37
+ catch {
38
+ // not in this directory
39
+ }
40
+ }
41
+ }
42
+ catch {
43
+ // attachments root doesn't exist
44
+ }
45
+ return null;
46
+ }
47
+ function serveFile(filePath, mimeTypeHint) {
48
+ return readFile(filePath).then((buffer) => {
49
+ const ext = extname(filePath).toLowerCase();
50
+ const contentType = MIME_MAP[ext] ?? mimeTypeHint ?? 'application/octet-stream';
51
+ return new NextResponse(buffer, {
52
+ headers: {
53
+ 'Content-Type': contentType,
54
+ 'Cache-Control': 'private, max-age=3600',
55
+ },
56
+ });
57
+ });
58
+ }
21
59
  export async function GET(request) {
22
60
  const path = request.nextUrl.searchParams.get('path');
23
61
  const mimeTypeHint = request.nextUrl.searchParams.get('mimeType');
@@ -31,17 +69,15 @@ export async function GET(request) {
31
69
  }
32
70
  try {
33
71
  await stat(path);
34
- const buffer = await readFile(path);
35
- const ext = extname(path).toLowerCase();
36
- const contentType = MIME_MAP[ext] ?? mimeTypeHint ?? 'application/octet-stream';
37
- return new NextResponse(buffer, {
38
- headers: {
39
- 'Content-Type': contentType,
40
- 'Cache-Control': 'private, max-age=3600',
41
- },
42
- });
72
+ return await serveFile(path, mimeTypeHint);
43
73
  }
44
74
  catch {
75
+ // File not found at exact path — try fallback search
76
+ // This handles the case where pending-<sessionId>/ was renamed to <featureSlug>/
77
+ const fallbackPath = await findAttachmentFallback(path, attachmentsRoot);
78
+ if (fallbackPath) {
79
+ return await serveFile(fallbackPath, mimeTypeHint);
80
+ }
45
81
  return NextResponse.json({ error: 'File not found' }, { status: 404 });
46
82
  }
47
83
  }
@@ -4,6 +4,10 @@ import type { ParentFeatureOption } from '../../common/feature-create-drawer/fea
4
4
  import type { WorkflowDefaults } from '../../../app/actions/get-workflow-defaults.js';
5
5
  /** Tab key matching FeatureDrawerTabs */
6
6
  export type FeatureTabKey = 'overview' | 'activity' | 'log' | 'plan' | 'prd-review' | 'tech-decisions' | 'product-decisions' | 'merge-review';
7
+ /** All valid tab key values — used for URL param validation. */
8
+ export declare const VALID_TAB_KEYS: ReadonlySet<string>;
9
+ /** Type-guard: returns the value as FeatureTabKey if valid, otherwise undefined. */
10
+ export declare function parseTabKey(value: string | null | undefined): FeatureTabKey | undefined;
7
11
  /**
8
12
  * Discriminated union representing every possible drawer state in the control center.
9
13
  * Only one view can be active at a time.
@@ -1 +1 @@
1
- {"version":3,"file":"drawer-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/drawer-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,yCAAyC;AACzC,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,KAAK,GACL,MAAM,GACN,YAAY,GACZ,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,CAAC;AAEnB;;;GAGG;AACH,MAAM,MAAM,UAAU;AACpB,qEAAqE;AACnE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE;AACvE,4BAA4B;GAC1B;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AACH,8BAA8B;GAC5B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAErD,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAOrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD,GAAG,UAAU,GAAG,IAAI,CAoBpB"}
1
+ {"version":3,"file":"drawer-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/drawer-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,yCAAyC;AACzC,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,KAAK,GACL,MAAM,GACN,YAAY,GACZ,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,CAAC;AAEnB,gEAAgE;AAChE,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,CAS7C,CAAC;AAEH,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAGvF;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU;AACpB,qEAAqE;AACnE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,aAAa,CAAA;CAAE;AACvE,4BAA4B;GAC1B;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AACH,8BAA8B;GAC5B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAErD,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAOrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD,GAAG,UAAU,GAAG,IAAI,CAoBpB"}
@@ -1,3 +1,20 @@
1
+ /** All valid tab key values — used for URL param validation. */
2
+ export const VALID_TAB_KEYS = new Set([
3
+ 'overview',
4
+ 'activity',
5
+ 'log',
6
+ 'plan',
7
+ 'prd-review',
8
+ 'tech-decisions',
9
+ 'product-decisions',
10
+ 'merge-review',
11
+ ]);
12
+ /** Type-guard: returns the value as FeatureTabKey if valid, otherwise undefined. */
13
+ export function parseTabKey(value) {
14
+ if (value && VALID_TAB_KEYS.has(value))
15
+ return value;
16
+ return undefined;
17
+ }
1
18
  /** Derives the initial tab from node lifecycle + state. */
2
19
  export function deriveInitialTab(node) {
3
20
  if (node.lifecycle === 'requirements' && node.state === 'action-required')
@@ -1,6 +1,8 @@
1
- import type { DrawerView } from './drawer-view.js';
1
+ import type { DrawerView, FeatureTabKey } from './drawer-view.js';
2
2
  export interface FeatureDrawerClientProps {
3
3
  view: DrawerView;
4
+ /** Tab key extracted from the URL path segment (e.g. /feature/[id]/activity → 'activity'). */
5
+ urlTab?: FeatureTabKey;
4
6
  }
5
- export declare function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientProps): import("react/jsx-runtime").JSX.Element;
7
+ export declare function FeatureDrawerClient({ view: initialView, urlTab }: FeatureDrawerClientProps): import("react/jsx-runtime").JSX.Element;
6
8
  //# sourceMappingURL=feature-drawer-client.d.ts.map
@@ -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":"AAsCA,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,2CAsiBlF"}
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":"AAsCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CAuiB1F"}
@@ -28,7 +28,7 @@ import { useFeatureActions } from '../../common/feature-drawer/use-feature-actio
28
28
  import { resolveSseEventUpdates } from '../../common/feature-node/derive-feature-state.js';
29
29
  import { deriveInitialTab } from './drawer-view.js';
30
30
  import { useArtifactFetch } from './use-artifact-fetch.js';
31
- export function FeatureDrawerClient({ view: initialView }) {
31
+ export function FeatureDrawerClient({ view: initialView, urlTab }) {
32
32
  const featureFlags = useFeatureFlags();
33
33
  const router = useRouter();
34
34
  const deleteSound = useSoundAction('delete');
@@ -324,7 +324,7 @@ export function FeatureDrawerClient({ view: initialView }) {
324
324
  // ── Body ──────────────────────────────────────────────────────────────
325
325
  let body = null;
326
326
  if (view.type === 'feature' && featureNode) {
327
- body = (_jsx(FeatureDrawerTabs, { featureNode: featureNode, featureId: featureNode.featureId, initialTab: view.initialTab, prdData: prdData, prdSelections: prdSelections, onPrdSelect: (qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId })), onPrdApprove: handlePrdApprove, onPrdReject: handlePrdReject, isPrdLoading: isLoadingPrd, techData: techData, onTechApprove: handleTechApprove, onTechReject: handleTechReject, isTechLoading: isLoadingTech, productData: isLoadingTechProduct ? null : techProductData, mergeData: mergeData, onMergeApprove: handleMergeApprove, onMergeReject: handleMergeReject, isMergeLoading: isLoadingMerge, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput }));
327
+ body = (_jsx(FeatureDrawerTabs, { featureNode: featureNode, featureId: featureNode.featureId, initialTab: view.initialTab, urlTab: urlTab, prdData: prdData, prdSelections: prdSelections, onPrdSelect: (qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId })), onPrdApprove: handlePrdApprove, onPrdReject: handlePrdReject, isPrdLoading: isLoadingPrd, techData: techData, onTechApprove: handleTechApprove, onTechReject: handleTechReject, isTechLoading: isLoadingTech, productData: isLoadingTechProduct ? null : techProductData, mergeData: mergeData, onMergeApprove: handleMergeApprove, onMergeReject: handleMergeReject, isMergeLoading: isLoadingMerge, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput }));
328
328
  }
329
329
  return (_jsx(BaseDrawer, { open: isOpen, onClose: attemptClose, size: "md", modal: false, header: header, "data-testid": view.type === 'feature' ? 'feature-drawer' : 'repository-drawer', children: body }));
330
330
  }
@@ -1 +1 @@
1
- {"version":3,"file":"activity-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,yCAAyC,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAC7C;AAsED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,2CA8D3F"}
1
+ {"version":3,"file":"activity-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/activity-tab.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,qBAAqB,EACtB,MAAM,yCAAyC,CAAC;AAGjD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iBAAiB,CAAC,EAAE,qBAAqB,EAAE,CAAC;CAC7C;AA4ED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,gBAAgB,2CA8D3F"}
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { Loader2, AlertCircle, Clock } from 'lucide-react';
4
+ import { InlineAttachments } from '../../common/inline-attachments/index.js';
4
5
  const NODE_TO_PHASE = {
5
6
  analyze: 'Analyzing',
6
7
  requirements: 'Requirements',
@@ -38,7 +39,7 @@ function groupTimingsByRun(timings) {
38
39
  return groups;
39
40
  }
40
41
  /**
41
- * Map each run:rejected timing entry to its rejection feedback message.
42
+ * Map each run:rejected timing entry to its rejection feedback message and attachments.
42
43
  * Matches by sequential order: 1st rejected event → 1st feedback entry, etc.
43
44
  */
44
45
  function buildRejectionMessageMap(timings, feedback) {
@@ -49,7 +50,8 @@ function buildRejectionMessageMap(timings, feedback) {
49
50
  for (const t of timings) {
50
51
  if (t.phase === 'run:rejected' && rejectionIdx < feedback.length) {
51
52
  const key = `${t.agentRunId}-${t.phase}-${t.startedAt}`;
52
- map.set(key, feedback[rejectionIdx].message);
53
+ const entry = feedback[rejectionIdx];
54
+ map.set(key, { message: entry.message, attachments: entry.attachments });
53
55
  rejectionIdx++;
54
56
  }
55
57
  }
@@ -79,17 +81,18 @@ function RunGroup({ group, groupIdx, multiRun, maxDurationMs, rejectionMessages,
79
81
  return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [multiRun ? (_jsxs("div", { className: "text-muted-foreground text-xs font-medium", children: ["Run #", groupIdx + 1] })) : null, group.timings.map((t) => {
80
82
  if (isLifecycleEvent(t.phase)) {
81
83
  const key = `${t.agentRunId}-${t.phase}-${t.startedAt}`;
82
- const message = t.phase === 'run:rejected' ? rejectionMessages.get(key) : undefined;
83
- return _jsx(LifecycleEventRow, { timing: t, message: message }, key);
84
+ const rejection = t.phase === 'run:rejected' ? rejectionMessages.get(key) : undefined;
85
+ return (_jsx(LifecycleEventRow, { timing: t, message: rejection?.message, attachments: rejection?.attachments }, key));
84
86
  }
85
87
  return (_jsx(NodeTimingRow, { timing: t, maxDurationMs: maxDurationMs }, `${t.agentRunId}-${t.phase}-${t.startedAt}`));
86
88
  })] }));
87
89
  }
88
- function LifecycleEventRow({ timing, message }) {
90
+ function LifecycleEventRow({ timing, message, attachments, }) {
89
91
  const event = LIFECYCLE_EVENTS[timing.phase];
90
92
  if (!event)
91
93
  return null;
92
- return (_jsxs("div", { className: `text-xs ${event.colorClass}`, children: [_jsx("span", { children: event.label }), message ? (_jsxs("span", { "data-testid": "rejection-feedback-text", className: "text-muted-foreground ml-2 font-normal italic", children: ["\u2014 ", message] })) : null] }));
94
+ const hasAttachments = attachments && attachments.length > 0;
95
+ return (_jsxs("div", { className: `text-xs ${event.colorClass}`, children: [_jsx("span", { children: event.label }), message ? (_jsxs("span", { "data-testid": "rejection-feedback-text", className: "text-muted-foreground ml-2 font-normal italic", children: ["\u2014 ", message] })) : null, hasAttachments ? (_jsx("div", { "data-testid": "rejection-feedback-attachments", className: "mt-1.5 ml-2", children: _jsx(InlineAttachments, { text: "", attachmentPaths: attachments }) })) : null] }));
93
96
  }
94
97
  function NodeTimingRow({ timing, maxDurationMs, }) {
95
98
  const label = timing.phase.includes(':')
@@ -9,6 +9,8 @@ export interface FeatureDrawerTabsProps {
9
9
  featureNode: FeatureNodeData;
10
10
  featureId: string;
11
11
  initialTab?: FeatureTabKey;
12
+ /** Tab key from URL path segment (e.g. /feature/[id]/activity → 'activity'). */
13
+ urlTab?: FeatureTabKey;
12
14
  prdData?: PrdQuestionnaireData | null;
13
15
  prdSelections?: Record<string, string>;
14
16
  onPrdSelect?: (questionId: string, optionId: string) => void;
@@ -28,5 +30,5 @@ export interface FeatureDrawerTabsProps {
28
30
  chatInput?: string;
29
31
  onChatInputChange?: (value: string) => void;
30
32
  }
31
- export declare function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
33
+ export declare function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
32
34
  //# sourceMappingURL=feature-drawer-tabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer-tabs.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAQ9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAiD3F,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC;IAG3B,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,QAAQ,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAGjD,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC5E,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAwBD,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,SAAS,EACT,UAAU,EACV,OAAO,EACP,aAAa,EACb,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,EAAE,sBAAsB,2CA4MxB"}
1
+ {"version":3,"file":"feature-drawer-tabs.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;AACjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAQ9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAC;AAiD3F,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,gFAAgF;IAChF,MAAM,CAAC,EAAE,aAAa,CAAC;IAGvB,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,QAAQ,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAGjD,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAC5E,cAAc,CAAC,EAAE,OAAO,CAAC;IAGzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAwBD,wBAAgB,iBAAiB,CAAC,EAChC,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,OAAO,EACP,aAAa,EACb,WAAW,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,WAAW,EACX,SAAS,EACT,iBAAiB,GAClB,EAAE,sBAAsB,2CAmSxB"}
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
4
+ import { usePathname } from 'next/navigation';
4
5
  import { Loader2 } from 'lucide-react';
5
6
  import { Tabs, TabsList, TabsTrigger, TabsContent } from '../../ui/tabs.js';
6
7
  import { getFeaturePhaseTimings } from '../../../app/actions/get-feature-phase-timings.js';
@@ -63,14 +64,91 @@ const TAB_FETCHERS = {
63
64
  activity: fetchActivity,
64
65
  plan: fetchPlan,
65
66
  };
66
- export function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }) {
67
+ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, isRejecting, chatInput, onChatInputChange, }) {
68
+ const pathname = usePathname();
67
69
  const featureLogs = useFeatureLogs(featureId);
68
70
  const visibleTabs = useMemo(() => computeVisibleTabs(featureNode), [featureNode]);
69
71
  const visibleTabDefs = useMemo(() => ALL_TABS.filter((t) => visibleTabs.includes(t.key)), [visibleTabs]);
70
- // Use initialTab if it's visible, otherwise default to 'overview'
71
- const effectiveInitial = initialTab && visibleTabs.includes(initialTab) ? initialTab : 'overview';
72
+ // Derive the base path (without tab segment) from the current pathname.
73
+ // e.g. /feature/abc123/activity /feature/abc123
74
+ const basePath = useMemo(() => {
75
+ const match = pathname.match(/^(\/feature\/[^/]+)/);
76
+ return match ? match[1] : pathname;
77
+ }, [pathname]);
78
+ // Resolve the effective initial tab: URL path tab > initialTab prop > 'overview'
79
+ const effectiveInitial = useMemo(() => {
80
+ if (urlTab && visibleTabs.includes(urlTab))
81
+ return urlTab;
82
+ if (initialTab && visibleTabs.includes(initialTab))
83
+ return initialTab;
84
+ return 'overview';
85
+ // Only compute on mount — subsequent changes are handled by effects below
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ }, []);
72
88
  const [activeTab, setActiveTab] = useState(effectiveInitial);
73
89
  const { tabs, fetchTab, refreshTab } = useTabDataFetch(featureId, TAB_FETCHERS);
90
+ // Sync URL when active tab changes via user interaction.
91
+ // Use window.history.pushState instead of router.push to avoid triggering a
92
+ // server component re-render (which would remount the drawer).
93
+ const isUserInteraction = useRef(false);
94
+ useEffect(() => {
95
+ if (!isUserInteraction.current)
96
+ return;
97
+ isUserInteraction.current = false;
98
+ // Build the target URL from the base path + tab segment
99
+ const targetUrl = activeTab === 'overview' ? basePath : `${basePath}/${activeTab}`;
100
+ // Only update URL if it actually changed
101
+ if (targetUrl !== pathname) {
102
+ window.history.pushState(null, '', targetUrl);
103
+ }
104
+ }, [activeTab, basePath, pathname]);
105
+ // Sync active tab from URL when pathname changes (e.g. browser back/forward).
106
+ // Skip on initial mount — the effectiveInitial handles that via urlTab prop.
107
+ const prevPathnameRef = useRef(pathname);
108
+ useEffect(() => {
109
+ if (prevPathnameRef.current === pathname)
110
+ return; // Skip initial mount
111
+ prevPathnameRef.current = pathname;
112
+ if (isUserInteraction.current)
113
+ return; // Skip — this is our own navigation
114
+ const segments = pathname.split('/');
115
+ // pathname is /feature/[id] or /feature/[id]/[tab]
116
+ const pathTab = segments.length >= 4 ? segments[3] : undefined;
117
+ const resolved = pathTab && visibleTabs.includes(pathTab) ? pathTab : 'overview';
118
+ if (resolved !== activeTab) {
119
+ setActiveTab(resolved);
120
+ if (resolved === 'activity' || resolved === 'plan') {
121
+ fetchTab(resolved);
122
+ }
123
+ }
124
+ }, [pathname]); // eslint-disable-line react-hooks/exhaustive-deps
125
+ // On mount, sync the URL to reflect the effective initial tab when it was
126
+ // derived from feature state (initialTab) rather than from the URL (urlTab).
127
+ // Use replaceState so we don't add a duplicate history entry.
128
+ const initialSyncDone = useRef(false);
129
+ useEffect(() => {
130
+ if (initialSyncDone.current)
131
+ return;
132
+ initialSyncDone.current = true;
133
+ // Only sync if the effective tab came from initialTab (not from URL)
134
+ if (!urlTab && effectiveInitial !== 'overview') {
135
+ const targetUrl = `${basePath}/${effectiveInitial}`;
136
+ if (targetUrl !== pathname) {
137
+ window.history.replaceState(null, '', targetUrl);
138
+ }
139
+ }
140
+ // eslint-disable-next-line react-hooks/exhaustive-deps
141
+ }, []);
142
+ // Trigger lazy fetch for URL-driven initial tab
143
+ const initialFetchDone = useRef(false);
144
+ useEffect(() => {
145
+ if (initialFetchDone.current)
146
+ return;
147
+ initialFetchDone.current = true;
148
+ if (activeTab === 'activity' || activeTab === 'plan') {
149
+ fetchTab(activeTab);
150
+ }
151
+ }, [activeTab, fetchTab]);
74
152
  // Reset tab when featureId changes
75
153
  const prevFeatureIdRef = useRef(featureId);
76
154
  useEffect(() => {
@@ -80,6 +158,7 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData,
80
158
  }
81
159
  }, [featureId]);
82
160
  // When initialTab changes (e.g. SSE updates lifecycle), switch to it if visible
161
+ // and sync the URL with replaceState so the address bar reflects the new tab.
83
162
  const prevInitialTabRef = useRef(initialTab);
84
163
  useEffect(() => {
85
164
  if (prevInitialTabRef.current !== initialTab &&
@@ -87,14 +166,23 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData,
87
166
  visibleTabs.includes(initialTab)) {
88
167
  prevInitialTabRef.current = initialTab;
89
168
  setActiveTab(initialTab);
169
+ // Sync URL to match the new tab
170
+ const targetUrl = initialTab === 'overview' ? basePath : `${basePath}/${initialTab}`;
171
+ if (targetUrl !== window.location.pathname) {
172
+ window.history.replaceState(null, '', targetUrl);
173
+ }
90
174
  }
91
- }, [initialTab, visibleTabs]);
175
+ }, [initialTab, visibleTabs, basePath]);
92
176
  // If the active tab becomes invisible (lifecycle changed), fall back to overview
177
+ // and sync the URL accordingly.
93
178
  useEffect(() => {
94
179
  if (!visibleTabs.includes(activeTab)) {
95
180
  setActiveTab('overview');
181
+ if (window.location.pathname !== basePath) {
182
+ window.history.replaceState(null, '', basePath);
183
+ }
96
184
  }
97
- }, [visibleTabs, activeTab]);
185
+ }, [visibleTabs, activeTab, basePath]);
98
186
  // SSE refresh: re-fetch active lazy tab when featureNode reference changes
99
187
  const featureNodeRef = useRef(featureNode);
100
188
  const activeTabRef = useRef(activeTab);
@@ -110,6 +198,7 @@ export function FeatureDrawerTabs({ featureNode, featureId, initialTab, prdData,
110
198
  }, [featureNode, refreshTab]);
111
199
  const handleTabChange = useCallback((value) => {
112
200
  const tab = value;
201
+ isUserInteraction.current = true;
113
202
  setActiveTab(tab);
114
203
  if (tab === 'activity' || tab === 'plan') {
115
204
  fetchTab(tab);
@@ -1 +1 @@
1
- {"version":3,"file":"overview-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAwCrD"}
1
+ {"version":3,"file":"overview-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAMxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CAwCrD"}