@shepai/cli 1.166.0 → 1.166.1-pr521.4139df8

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 (220) hide show
  1. package/dist/packages/core/src/application/index.d.ts +1 -0
  2. package/dist/packages/core/src/application/index.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/index.js +1 -0
  4. package/dist/packages/core/src/application/ports/output/agents/agent-run-repository.interface.d.ts +12 -0
  5. package/dist/packages/core/src/application/ports/output/agents/agent-run-repository.interface.d.ts.map +1 -1
  6. package/dist/packages/core/src/application/use-cases/features/update-feature-pinned-config.use-case.d.ts +24 -0
  7. package/dist/packages/core/src/application/use-cases/features/update-feature-pinned-config.use-case.d.ts.map +1 -0
  8. package/dist/packages/core/src/application/use-cases/features/update-feature-pinned-config.use-case.js +107 -0
  9. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  10. package/dist/packages/core/src/infrastructure/di/container.js +8 -0
  11. package/dist/packages/core/src/infrastructure/repositories/agent-run.repository.d.ts +2 -1
  12. package/dist/packages/core/src/infrastructure/repositories/agent-run.repository.d.ts.map +1 -1
  13. package/dist/packages/core/src/infrastructure/repositories/agent-run.repository.js +15 -0
  14. package/dist/packages/core/src/infrastructure/services/web-server.service.d.ts +3 -0
  15. package/dist/packages/core/src/infrastructure/services/web-server.service.d.ts.map +1 -1
  16. package/dist/packages/core/src/infrastructure/services/web-server.service.js +10 -0
  17. package/dist/src/presentation/web/app/actions/update-feature-pinned-config.d.ts +5 -0
  18. package/dist/src/presentation/web/app/actions/update-feature-pinned-config.d.ts.map +1 -0
  19. package/dist/src/presentation/web/app/actions/update-feature-pinned-config.js +29 -0
  20. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +100 -9
  22. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts +4 -1
  23. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.js +3 -3
  25. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts +3 -1
  26. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.d.ts.map +1 -1
  27. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.js +21 -10
  28. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts +4 -0
  29. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.d.ts.map +1 -1
  30. package/dist/src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.js +33 -0
  31. package/dist/src/presentation/web/components/common/feature-drawer-tabs/pinned-config-utils.d.ts +18 -0
  32. package/dist/src/presentation/web/components/common/feature-drawer-tabs/pinned-config-utils.d.ts.map +1 -0
  33. package/dist/src/presentation/web/components/common/feature-drawer-tabs/pinned-config-utils.js +17 -0
  34. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.d.ts +2 -0
  35. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.js +27 -0
  37. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/index.d.ts +10 -1
  38. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/index.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/features/settings/AgentModelPicker/index.js +33 -25
  40. package/dist/tsconfig.build.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/web/.next/BUILD_ID +1 -1
  43. package/web/.next/build-manifest.json +2 -2
  44. package/web/.next/fallback-build-manifest.json +2 -2
  45. package/web/.next/prerender-manifest.json +3 -3
  46. package/web/.next/required-server-files.js +3 -3
  47. package/web/.next/required-server-files.json +3 -3
  48. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +29 -29
  49. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  50. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  51. package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +27 -27
  52. package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +30 -30
  55. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  56. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  57. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +89 -74
  58. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +1 -1
  59. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  60. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  61. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +89 -74
  62. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  63. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  64. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  65. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
  66. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
  67. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
  69. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  70. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  71. package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +27 -27
  72. package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
  73. package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +30 -30
  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/server-reference-manifest.json +89 -74
  78. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +1 -1
  79. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  80. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +89 -74
  82. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  83. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  84. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  85. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +27 -27
  86. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  87. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  88. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
  89. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
  90. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
  92. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  93. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  94. package/web/.next/server/app/_global-error.html +2 -2
  95. package/web/.next/server/app/_global-error.rsc +1 -1
  96. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  97. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  98. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  99. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  100. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  101. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +6 -6
  102. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  103. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  104. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  105. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  106. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  107. package/web/.next/server/app/api/interactive/chat/[featureId]/messages/route.js.nft.json +1 -1
  108. package/web/.next/server/app/settings/page/server-reference-manifest.json +9 -9
  109. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  110. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  111. package/web/.next/server/app/skills/page/server-reference-manifest.json +11 -11
  112. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  113. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  114. package/web/.next/server/app/tools/page/server-reference-manifest.json +11 -11
  115. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  116. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  117. package/web/.next/server/app/version/page/server-reference-manifest.json +6 -6
  118. package/web/.next/server/app/version/page.js.nft.json +1 -1
  119. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  120. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  121. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  122. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +3 -3
  124. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
  125. package/web/.next/server/chunks/ssr/[root-of-the-server]__1abe77bb._.js +2 -2
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__1abe77bb._.js.map +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js +1 -1
  128. package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js.map +1 -1
  129. package/web/.next/server/chunks/ssr/[root-of-the-server]__2d0c3840._.js +1 -1
  130. package/web/.next/server/chunks/ssr/[root-of-the-server]__2d0c3840._.js.map +1 -1
  131. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  132. package/web/.next/server/chunks/ssr/[root-of-the-server]__4fb81977._.js +4 -0
  133. package/web/.next/server/chunks/ssr/[root-of-the-server]__4fb81977._.js.map +1 -0
  134. package/web/.next/server/chunks/ssr/[root-of-the-server]__7562afc6._.js +2 -2
  135. package/web/.next/server/chunks/ssr/[root-of-the-server]__7562afc6._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__7dcd0917._.js +4 -0
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__7dcd0917._.js.map +1 -0
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__8b0aac03._.js +1 -1
  139. package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js +1 -1
  140. package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/[root-of-the-server]__ba7f5873._.js +4 -0
  142. package/web/.next/server/chunks/ssr/[root-of-the-server]__ba7f5873._.js.map +1 -0
  143. package/web/.next/server/chunks/ssr/[root-of-the-server]__c5e09f6f._.js +4 -0
  144. package/web/.next/server/chunks/ssr/[root-of-the-server]__c5e09f6f._.js.map +1 -0
  145. package/web/.next/server/chunks/ssr/_02e01240._.js +1 -1
  146. package/web/.next/server/chunks/ssr/_02e01240._.js.map +1 -1
  147. package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
  148. package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
  149. package/web/.next/server/chunks/ssr/_0727935d._.js +1 -1
  150. package/web/.next/server/chunks/ssr/_0727935d._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
  152. package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/_18886033._.js +1 -1
  154. package/web/.next/server/chunks/ssr/_18886033._.js.map +1 -1
  155. package/web/.next/server/chunks/ssr/_22e00a14._.js +1 -1
  156. package/web/.next/server/chunks/ssr/_22e00a14._.js.map +1 -1
  157. package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
  158. package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
  159. package/web/.next/server/chunks/ssr/{_8237a552._.js → _80eef198._.js} +2 -2
  160. package/web/.next/server/chunks/ssr/{_8237a552._.js.map → _80eef198._.js.map} +1 -1
  161. package/web/.next/server/chunks/ssr/_9215e9ec._.js +1 -1
  162. package/web/.next/server/chunks/ssr/_9215e9ec._.js.map +1 -1
  163. package/web/.next/server/chunks/ssr/_a5a5901d._.js +1 -1
  164. package/web/.next/server/chunks/ssr/_a5a5901d._.js.map +1 -1
  165. package/web/.next/server/chunks/ssr/_ad09f271._.js +1 -1
  166. package/web/.next/server/chunks/ssr/_ad09f271._.js.map +1 -1
  167. package/web/.next/server/chunks/ssr/{_42df9dfe._.js → _ad1e8df0._.js} +2 -2
  168. package/web/.next/server/chunks/ssr/{_42df9dfe._.js.map → _ad1e8df0._.js.map} +1 -1
  169. package/web/.next/server/chunks/ssr/_c3f595c6._.js +1 -1
  170. package/web/.next/server/chunks/ssr/_c3f595c6._.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/{_ddc492d1._.js → _cb46c553._.js} +2 -2
  172. package/web/.next/server/chunks/ssr/{_ddc492d1._.js.map → _cb46c553._.js.map} +1 -1
  173. package/web/.next/server/chunks/ssr/_ea9e1556._.js +1 -1
  174. package/web/.next/server/chunks/ssr/_ea9e1556._.js.map +1 -1
  175. package/web/.next/server/chunks/ssr/_f1ba9be6._.js +2 -2
  176. package/web/.next/server/chunks/ssr/_f1ba9be6._.js.map +1 -1
  177. package/web/.next/server/chunks/ssr/_f33cd07e._.js +2 -2
  178. package/web/.next/server/chunks/ssr/_f33cd07e._.js.map +1 -1
  179. package/web/.next/server/chunks/ssr/_f8b45233._.js +1 -1
  180. package/web/.next/server/chunks/ssr/_f8b45233._.js.map +1 -1
  181. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  182. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  183. package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js +1 -1
  184. package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js.map +1 -1
  185. package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
  186. package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js +1 -1
  187. package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  189. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  190. package/web/.next/server/pages/500.html +2 -2
  191. package/web/.next/server/server-reference-manifest.js +1 -1
  192. package/web/.next/server/server-reference-manifest.json +231 -195
  193. package/web/.next/static/chunks/{5aaf70a61ff36c5a.js → 017b47553231a823.js} +1 -1
  194. package/web/.next/static/chunks/{31f0a6a3634a38cc.js → 0b5d6a720a7881a9.js} +1 -1
  195. package/web/.next/static/chunks/{09384992ac14d0b1.js → 1d29dba973313f02.js} +1 -1
  196. package/web/.next/static/chunks/3208dc997aaee4d3.css +1 -0
  197. package/web/.next/static/chunks/39f6493901c3eea0.js +5 -0
  198. package/web/.next/static/chunks/{eca136d997cb8da7.js → 3c1fa8ca0fd213dd.js} +1 -1
  199. package/web/.next/static/chunks/{e2ba7b83074d9104.js → 5afbcdb3d1de34c9.js} +1 -1
  200. package/web/.next/static/chunks/{4db9c7689add55ee.js → 7324fbbe1b204722.js} +2 -2
  201. package/web/.next/static/chunks/{352028876229aa6b.js → 902840b67efbdd64.js} +1 -1
  202. package/web/.next/static/chunks/a260c71a30c63952.js +1 -0
  203. package/web/.next/static/chunks/{dc3ddb095e1af0e0.js → b2ea14e7d98ca3e8.js} +1 -1
  204. package/web/.next/static/chunks/{788183384c8a43ba.js → bd4204d2d43217b4.js} +1 -1
  205. package/web/.next/static/chunks/{e9b6a30fee5ad6c4.js → c26529d3615ad0a3.js} +3 -3
  206. package/web/.next/static/chunks/{6f74c02d56d084bc.js → ed4aa2bcbf8b63e2.js} +1 -1
  207. package/web/.next/server/chunks/ssr/[root-of-the-server]__563e4faf._.js +0 -4
  208. package/web/.next/server/chunks/ssr/[root-of-the-server]__563e4faf._.js.map +0 -1
  209. package/web/.next/server/chunks/ssr/[root-of-the-server]__821a11c1._.js +0 -4
  210. package/web/.next/server/chunks/ssr/[root-of-the-server]__821a11c1._.js.map +0 -1
  211. package/web/.next/server/chunks/ssr/[root-of-the-server]__98740ee4._.js +0 -4
  212. package/web/.next/server/chunks/ssr/[root-of-the-server]__98740ee4._.js.map +0 -1
  213. package/web/.next/server/chunks/ssr/[root-of-the-server]__ba9f9e11._.js +0 -4
  214. package/web/.next/server/chunks/ssr/[root-of-the-server]__ba9f9e11._.js.map +0 -1
  215. package/web/.next/static/chunks/1e6609edc3367244.css +0 -1
  216. package/web/.next/static/chunks/a61378603f8d7259.js +0 -5
  217. package/web/.next/static/chunks/bd53da44edb8c407.js +0 -1
  218. /package/web/.next/static/{5K-9Z8FJofHXgZNGHs_YM → WC6AP64Gn0KyMqwIy1VjS}/_buildManifest.js +0 -0
  219. /package/web/.next/static/{5K-9Z8FJofHXgZNGHs_YM → WC6AP64Gn0KyMqwIy1VjS}/_clientMiddlewareManifest.json +0 -0
  220. /package/web/.next/static/{5K-9Z8FJofHXgZNGHs_YM → WC6AP64Gn0KyMqwIy1VjS}/_ssgManifest.js +0 -0
@@ -13,6 +13,7 @@ export { ShowFeatureUseCase } from './use-cases/features/show-feature.use-case.j
13
13
  export { CreateFeatureUseCase } from './use-cases/features/create/create-feature.use-case.js';
14
14
  export { DeleteFeatureUseCase } from './use-cases/features/delete-feature.use-case.js';
15
15
  export { ResumeFeatureUseCase } from './use-cases/features/resume-feature.use-case.js';
16
+ export { UpdateFeaturePinnedConfigUseCase } from './use-cases/features/update-feature-pinned-config.use-case.js';
16
17
  export { RunAgentUseCase } from './use-cases/agents/run-agent.use-case.js';
17
18
  export { StopAgentRunUseCase } from './use-cases/agents/stop-agent-run.use-case.js';
18
19
  export { ApproveAgentRunUseCase } from './use-cases/agents/approve-agent-run.use-case.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/src/application/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,2BAA2B,EAC3B,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,GACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,EAC5B,aAAa,EACb,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sDAAsD,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kDAAkD,CAAC;AAGzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wDAAwD,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AAGvF,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/src/application/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,0BAA0B,EAC1B,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,2BAA2B,EAC3B,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,uBAAuB,EACvB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,GACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,EAC5B,aAAa,EACb,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,sDAAsD,CAAC;AACjG,OAAO,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kDAAkD,CAAC;AAGzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wDAAwD,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iDAAiD,CAAC;AACvF,OAAO,EAAE,gCAAgC,EAAE,MAAM,+DAA+D,CAAC;AAGjH,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AAC1F,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8CAA8C,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iDAAiD,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AACvF,OAAO,EAAE,wBAAwB,EAAE,MAAM,oDAAoD,CAAC"}
@@ -14,6 +14,7 @@ export { ShowFeatureUseCase } from './use-cases/features/show-feature.use-case.j
14
14
  export { CreateFeatureUseCase } from './use-cases/features/create/create-feature.use-case.js';
15
15
  export { DeleteFeatureUseCase } from './use-cases/features/delete-feature.use-case.js';
16
16
  export { ResumeFeatureUseCase } from './use-cases/features/resume-feature.use-case.js';
17
+ export { UpdateFeaturePinnedConfigUseCase } from './use-cases/features/update-feature-pinned-config.use-case.js';
17
18
  // Agent use cases
18
19
  export { RunAgentUseCase } from './use-cases/agents/run-agent.use-case.js';
19
20
  export { StopAgentRunUseCase } from './use-cases/agents/stop-agent-run.use-case.js';
@@ -9,6 +9,11 @@
9
9
  * - Infrastructure layer provides concrete implementations
10
10
  */
11
11
  import type { AgentRun, AgentRunStatus } from '../../../../domain/generated/output.js';
12
+ export interface AgentRunPinnedConfigUpdate {
13
+ agentType: AgentRun['agentType'];
14
+ modelId?: AgentRun['modelId'];
15
+ updatedAt: AgentRun['updatedAt'];
16
+ }
12
17
  /**
13
18
  * Repository interface for AgentRun entity persistence.
14
19
  *
@@ -46,6 +51,13 @@ export interface IAgentRunRepository {
46
51
  * @param updates - Optional additional fields to update
47
52
  */
48
53
  updateStatus(id: string, status: AgentRunStatus, updates?: Partial<AgentRun>): Promise<void>;
54
+ /**
55
+ * Update the pinned executor config for an existing run.
56
+ *
57
+ * @param id - The agent run ID
58
+ * @param updates - The pinned config fields to persist
59
+ */
60
+ updatePinnedConfig(id: string, updates: AgentRunPinnedConfigUpdate): Promise<void>;
49
61
  /**
50
62
  * Find all running agent runs for a given process ID.
51
63
  * Used for crash recovery to detect orphaned processes.
@@ -1 +1 @@
1
- {"version":3,"file":"agent-run-repository.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/agents/agent-run-repository.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAEvF;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAE/C;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAE3D;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7F;;;;;;OAMG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEnD;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC"}
1
+ {"version":3,"file":"agent-run-repository.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/agents/agent-run-repository.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAEvF,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC9B,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAE/C;;;;;OAKG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAE3D;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7F;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnF;;;;;;OAMG;IACH,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEnD;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE5B;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC"}
@@ -0,0 +1,24 @@
1
+ import type { IFeatureRepository } from '../../ports/output/repositories/feature-repository.interface.js';
2
+ import type { IAgentRunRepository } from '../../ports/output/agents/agent-run-repository.interface.js';
3
+ import type { IAgentExecutorFactory } from '../../ports/output/agents/agent-executor-factory.interface.js';
4
+ import { type AgentType } from '../../../domain/generated/output.js';
5
+ export interface UpdateFeaturePinnedConfigInput {
6
+ featureId: string;
7
+ agentType: string;
8
+ modelId?: string | null;
9
+ }
10
+ export interface UpdateFeaturePinnedConfigResult {
11
+ featureId: string;
12
+ agentRunId: string;
13
+ agentType: AgentType;
14
+ modelId: string;
15
+ updatedAt: Date;
16
+ }
17
+ export declare class UpdateFeaturePinnedConfigUseCase {
18
+ private readonly featureRepository;
19
+ private readonly agentRunRepository;
20
+ private readonly agentExecutorFactory;
21
+ constructor(featureRepository: IFeatureRepository, agentRunRepository: IAgentRunRepository, agentExecutorFactory: IAgentExecutorFactory);
22
+ execute(input: UpdateFeaturePinnedConfigInput): Promise<UpdateFeaturePinnedConfigResult>;
23
+ }
24
+ //# sourceMappingURL=update-feature-pinned-config.use-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-feature-pinned-config.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/features/update-feature-pinned-config.use-case.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+DAA+D,CAAC;AAC3G,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,qCAAqC,CAAC;AAgB7C,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,+BAA+B;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AA8BD,qBACa,gCAAgC;IAGzC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAJpB,iBAAiB,EAAE,kBAAkB,EAErC,kBAAkB,EAAE,mBAAmB,EAEvC,oBAAoB,EAAE,qBAAqB;IAGxD,OAAO,CAAC,KAAK,EAAE,8BAA8B,GAAG,OAAO,CAAC,+BAA+B,CAAC;CAkD/F"}
@@ -0,0 +1,107 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from 'tsyringe';
14
+ import { AgentRunStatus, SdlcLifecycle, } from '../../../domain/generated/output.js';
15
+ const ELIGIBLE_RESUME_STATUSES = new Set([
16
+ AgentRunStatus.waitingApproval,
17
+ AgentRunStatus.failed,
18
+ AgentRunStatus.interrupted,
19
+ ]);
20
+ const INELIGIBLE_LIFECYCLES = new Set([
21
+ SdlcLifecycle.Archived,
22
+ SdlcLifecycle.AwaitingUpstream,
23
+ SdlcLifecycle.Blocked,
24
+ SdlcLifecycle.Deleting,
25
+ SdlcLifecycle.Maintain,
26
+ ]);
27
+ function normalizeRequiredString(value, fieldName) {
28
+ const trimmed = value.trim();
29
+ if (!trimmed) {
30
+ throw new Error(`${fieldName} is required`);
31
+ }
32
+ return trimmed;
33
+ }
34
+ function normalizeRequiredModelId(value) {
35
+ const trimmed = value?.trim();
36
+ if (!trimmed) {
37
+ throw new Error('modelId is required');
38
+ }
39
+ return trimmed;
40
+ }
41
+ function canUpdatePinnedConfig(feature, run) {
42
+ if (feature.lifecycle === SdlcLifecycle.Pending) {
43
+ return run.status === AgentRunStatus.pending;
44
+ }
45
+ if (INELIGIBLE_LIFECYCLES.has(feature.lifecycle)) {
46
+ return false;
47
+ }
48
+ return ELIGIBLE_RESUME_STATUSES.has(run.status);
49
+ }
50
+ let UpdateFeaturePinnedConfigUseCase = class UpdateFeaturePinnedConfigUseCase {
51
+ featureRepository;
52
+ agentRunRepository;
53
+ agentExecutorFactory;
54
+ constructor(featureRepository, agentRunRepository, agentExecutorFactory) {
55
+ this.featureRepository = featureRepository;
56
+ this.agentRunRepository = agentRunRepository;
57
+ this.agentExecutorFactory = agentExecutorFactory;
58
+ }
59
+ async execute(input) {
60
+ const featureId = normalizeRequiredString(input.featureId, 'featureId');
61
+ const agentType = normalizeRequiredString(input.agentType, 'agentType');
62
+ const modelId = normalizeRequiredModelId(input.modelId);
63
+ const feature = await this.featureRepository.findById(featureId);
64
+ if (!feature) {
65
+ throw new Error(`Feature not found: ${featureId}`);
66
+ }
67
+ if (!feature.agentRunId) {
68
+ throw new Error(`Feature "${feature.name}" has no current agent run`);
69
+ }
70
+ const run = await this.agentRunRepository.findById(feature.agentRunId);
71
+ if (!run) {
72
+ throw new Error(`Current agent run not found for feature "${feature.name}"`);
73
+ }
74
+ if (!canUpdatePinnedConfig(feature, run)) {
75
+ throw new Error(`Feature "${feature.name}" cannot change pinned agent/model while lifecycle is "${feature.lifecycle}" and run status is "${run.status}"`);
76
+ }
77
+ const supportedAgents = this.agentExecutorFactory.getSupportedAgents();
78
+ if (!supportedAgents.includes(agentType)) {
79
+ throw new Error(`Unsupported agent type: ${agentType}`);
80
+ }
81
+ const supportedModels = this.agentExecutorFactory.getSupportedModels(agentType);
82
+ if (!supportedModels.includes(modelId)) {
83
+ throw new Error(`Unsupported model "${modelId}" for agent "${agentType}"`);
84
+ }
85
+ const updatedAt = new Date();
86
+ await this.agentRunRepository.updatePinnedConfig(run.id, {
87
+ agentType,
88
+ modelId,
89
+ updatedAt,
90
+ });
91
+ return {
92
+ featureId: feature.id,
93
+ agentRunId: run.id,
94
+ agentType,
95
+ modelId,
96
+ updatedAt,
97
+ };
98
+ }
99
+ };
100
+ UpdateFeaturePinnedConfigUseCase = __decorate([
101
+ injectable(),
102
+ __param(0, inject('IFeatureRepository')),
103
+ __param(1, inject('IAgentRunRepository')),
104
+ __param(2, inject('IAgentExecutorFactory')),
105
+ __metadata("design:paramtypes", [Object, Object, Object])
106
+ ], UpdateFeaturePinnedConfigUseCase);
107
+ export { UpdateFeaturePinnedConfigUseCase };
@@ -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;AAmJrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAgbrE;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;AAoJrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAubrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -67,6 +67,7 @@ import { ShowFeatureUseCase } from '../../application/use-cases/features/show-fe
67
67
  import { DeleteFeatureUseCase } from '../../application/use-cases/features/delete-feature.use-case.js';
68
68
  import { ResumeFeatureUseCase } from '../../application/use-cases/features/resume-feature.use-case.js';
69
69
  import { StartFeatureUseCase } from '../../application/use-cases/features/start-feature.use-case.js';
70
+ import { UpdateFeaturePinnedConfigUseCase } from '../../application/use-cases/features/update-feature-pinned-config.use-case.js';
70
71
  import { AdoptBranchUseCase } from '../../application/use-cases/features/adopt-branch.use-case.js';
71
72
  import { GetFeatureArtifactUseCase } from '../../application/use-cases/features/get-feature-artifact.use-case.js';
72
73
  import { GetResearchArtifactUseCase } from '../../application/use-cases/features/get-research-artifact.use-case.js';
@@ -305,6 +306,7 @@ export async function initializeContainer() {
305
306
  container.registerSingleton(DeleteFeatureUseCase);
306
307
  container.registerSingleton(ResumeFeatureUseCase);
307
308
  container.registerSingleton(StartFeatureUseCase);
309
+ container.registerSingleton(UpdateFeaturePinnedConfigUseCase);
308
310
  container.registerSingleton(AdoptBranchUseCase);
309
311
  container.registerSingleton(GetFeatureArtifactUseCase);
310
312
  container.registerSingleton(GetResearchArtifactUseCase);
@@ -372,9 +374,15 @@ export async function initializeContainer() {
372
374
  container.register('StartFeatureUseCase', {
373
375
  useFactory: (c) => c.resolve(StartFeatureUseCase),
374
376
  });
377
+ container.register('UpdateFeaturePinnedConfigUseCase', {
378
+ useFactory: (c) => c.resolve(UpdateFeaturePinnedConfigUseCase),
379
+ });
375
380
  container.register('AdoptBranchUseCase', {
376
381
  useFactory: (c) => c.resolve(AdoptBranchUseCase),
377
382
  });
383
+ container.register('StopAgentRunUseCase', {
384
+ useFactory: (c) => c.resolve(StopAgentRunUseCase),
385
+ });
378
386
  container.register('ApproveAgentRunUseCase', {
379
387
  useFactory: (c) => c.resolve(ApproveAgentRunUseCase),
380
388
  });
@@ -5,7 +5,7 @@
5
5
  * Uses prepared statements to prevent SQL injection.
6
6
  */
7
7
  import type Database from 'better-sqlite3';
8
- import type { IAgentRunRepository } from '../../application/ports/output/agents/agent-run-repository.interface.js';
8
+ import type { IAgentRunRepository, AgentRunPinnedConfigUpdate } from '../../application/ports/output/agents/agent-run-repository.interface.js';
9
9
  import type { AgentRun, AgentRunStatus } from '../../domain/generated/output.js';
10
10
  /**
11
11
  * SQLite implementation of IAgentRunRepository.
@@ -18,6 +18,7 @@ export declare class SQLiteAgentRunRepository implements IAgentRunRepository {
18
18
  findById(id: string): Promise<AgentRun | null>;
19
19
  findByThreadId(threadId: string): Promise<AgentRun | null>;
20
20
  updateStatus(id: string, status: AgentRunStatus, updates?: Partial<AgentRun>): Promise<void>;
21
+ updatePinnedConfig(id: string, updates: AgentRunPinnedConfigUpdate): Promise<void>;
21
22
  findRunningByPid(pid: number): Promise<AgentRun[]>;
22
23
  list(): Promise<AgentRun[]>;
23
24
  delete(id: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-run.repository.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/repositories/agent-run.repository.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yEAAyE,CAAC;AACnH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAkBjF;;;GAGG;AACH,qBACa,wBAAyB,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAE5C,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBzC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAW9C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAW1D,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC;IAqDV,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAOlD,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO3B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIxC"}
1
+ {"version":3,"file":"agent-run.repository.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/repositories/agent-run.repository.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,yEAAyE,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAkBjF;;;GAGG;AACH,qBACa,wBAAyB,YAAW,mBAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAE5C,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBzC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAW9C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAW1D,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC;IAqDV,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlF,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAOlD,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAO3B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAIxC"}
@@ -115,6 +115,21 @@ let SQLiteAgentRunRepository = class SQLiteAgentRunRepository {
115
115
  const stmt = this.db.prepare(`UPDATE agent_runs SET ${setClauses.join(', ')} WHERE id = @id`);
116
116
  stmt.run(params);
117
117
  }
118
+ async updatePinnedConfig(id, updates) {
119
+ const stmt = this.db.prepare(`
120
+ UPDATE agent_runs
121
+ SET agent_type = @agent_type,
122
+ model_id = @model_id,
123
+ updated_at = @updated_at
124
+ WHERE id = @id
125
+ `);
126
+ stmt.run({
127
+ id,
128
+ agent_type: updates.agentType,
129
+ model_id: updates.modelId ?? null,
130
+ updated_at: toTimestamp(updates.updatedAt) ?? Date.now(),
131
+ });
132
+ }
118
133
  async findRunningByPid(pid) {
119
134
  const stmt = this.db.prepare('SELECT * FROM agent_runs WHERE pid = ? AND status = ?');
120
135
  const rows = stmt.all(pid, 'running');
@@ -22,6 +22,9 @@ export interface WebServerDeps {
22
22
  * Development: import.meta.dirname = <root>/packages/core/src/infrastructure/services/
23
23
  * → 5 levels up → <root>/src/presentation/web/
24
24
  *
25
+ * Workspace dist: import.meta.dirname = <root>/dist/packages/core/src/infrastructure/services/
26
+ * → 6 levels up → <root>/src/presentation/web/
27
+ *
25
28
  * Production (npm install): import.meta.dirname = <root>/dist/packages/core/src/infrastructure/services/
26
29
  * → 6 levels up → <root>/web/
27
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"web-server.service.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/services/web-server.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yEAAyE,CAAC;AAKjH,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,OAAO,IAAI,CAAC;IAC3B,gBAAgB,EAAE,OAAO,IAAI,CAAC,YAAY,CAAC;CAC5C;AAOD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAsB7D;AAED,qBACa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;gBAEzB,IAAI,GAAE,OAAO,CAAC,aAAa,CAAM;IAI7C;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CjE;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAuB5B"}
1
+ {"version":3,"file":"web-server.service.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/services/web-server.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yEAAyE,CAAC;AAKjH,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,OAAO,IAAI,CAAC;IAC3B,gBAAgB,EAAE,OAAO,IAAI,CAAC,YAAY,CAAC;CAC5C;AAOD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAiC7D;AAED,qBACa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;gBAEzB,IAAI,GAAE,OAAO,CAAC,aAAa,CAAM;IAI7C;;;;;OAKG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0CjE;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAuB5B"}
@@ -34,6 +34,9 @@ const defaultDeps = {
34
34
  * Development: import.meta.dirname = <root>/packages/core/src/infrastructure/services/
35
35
  * → 5 levels up → <root>/src/presentation/web/
36
36
  *
37
+ * Workspace dist: import.meta.dirname = <root>/dist/packages/core/src/infrastructure/services/
38
+ * → 6 levels up → <root>/src/presentation/web/
39
+ *
37
40
  * Production (npm install): import.meta.dirname = <root>/dist/packages/core/src/infrastructure/services/
38
41
  * → 6 levels up → <root>/web/
39
42
  */
@@ -44,6 +47,12 @@ export function resolveWebDir() {
44
47
  if (fs.existsSync(path.join(devDir, 'next.config.ts'))) {
45
48
  return { dir: devDir, dev: true };
46
49
  }
50
+ // Dist CLI inside a workspace checkout: the built CLI lives under dist/,
51
+ // but the source web app still exists at the repository root.
52
+ const workspaceDevDir = path.resolve(import.meta.dirname, '../../../../../../src/presentation/web');
53
+ if (fs.existsSync(path.join(workspaceDevDir, 'next.config.ts'))) {
54
+ return { dir: workspaceDevDir, dev: true };
55
+ }
47
56
  // Production: web UI is shipped alongside dist/ in the package
48
57
  // From dist/packages/core/src/infrastructure/services/ → 6 levels up to package root
49
58
  const prodDir = path.resolve(import.meta.dirname, '../../../../../../web');
@@ -53,6 +62,7 @@ export function resolveWebDir() {
53
62
  throw new Error(`Web UI directory not found. Ensure the web UI is built (pnpm build:web).\n` +
54
63
  ` Searched:\n` +
55
64
  ` dev: ${devDir} (next.config.ts: ${fs.existsSync(path.join(devDir, 'next.config.ts'))})\n` +
65
+ ` workspace: ${workspaceDevDir} (next.config.ts: ${fs.existsSync(path.join(workspaceDevDir, 'next.config.ts'))})\n` +
56
66
  ` prod: ${prodDir} (.next: ${fs.existsSync(path.join(prodDir, '.next'))})\n` +
57
67
  ` import.meta.dirname: ${import.meta.dirname}`);
58
68
  }
@@ -0,0 +1,5 @@
1
+ export declare function updateFeaturePinnedConfig(featureId: string, agentType: string, modelId: string): Promise<{
2
+ ok: boolean;
3
+ error?: string;
4
+ }>;
5
+ //# sourceMappingURL=update-feature-pinned-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-feature-pinned-config.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/update-feature-pinned-config.ts"],"names":[],"mappings":"AAKA,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6B1C"}
@@ -0,0 +1,29 @@
1
+ 'use server';
2
+ import { resolve } from '../../lib/server-container.js';
3
+ export async function updateFeaturePinnedConfig(featureId, agentType, modelId) {
4
+ const normalizedFeatureId = featureId.trim();
5
+ if (!normalizedFeatureId) {
6
+ return { ok: false, error: 'Feature id is required' };
7
+ }
8
+ const normalizedAgentType = agentType.trim();
9
+ if (!normalizedAgentType) {
10
+ return { ok: false, error: 'Agent type is required' };
11
+ }
12
+ const normalizedModelId = modelId.trim();
13
+ if (!normalizedModelId) {
14
+ return { ok: false, error: 'Model id is required' };
15
+ }
16
+ try {
17
+ const useCase = resolve('UpdateFeaturePinnedConfigUseCase');
18
+ await useCase.execute({
19
+ featureId: normalizedFeatureId,
20
+ agentType: normalizedAgentType,
21
+ modelId: normalizedModelId,
22
+ });
23
+ return { ok: true };
24
+ }
25
+ catch (error) {
26
+ const message = error instanceof Error ? error.message : 'Failed to update feature pinned config';
27
+ return { ok: false, error: message };
28
+ }
29
+ }
@@ -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":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EAAE,WAAW,EACjB,MAAM,EACN,uBAA8B,GAC/B,EAAE,wBAAwB,2CAoxB1B"}
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":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAW/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qFAAqF;IACrF,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EAAE,WAAW,EACjB,MAAM,EACN,uBAA8B,GAC/B,EAAE,wBAAwB,2CAq4B1B"}
@@ -31,6 +31,8 @@ import { deriveInitialTab } from './drawer-view.js';
31
31
  import { useArtifactFetch } from './use-artifact-fetch.js';
32
32
  import { useDrawerSync } from './use-drawer-sync.js';
33
33
  import { useBranchSyncStatus } from '../../../hooks/use-branch-sync-status.js';
34
+ import { updateFeaturePinnedConfig } from '../../../app/actions/update-feature-pinned-config.js';
35
+ import { canSwitchPinnedConfig, getPinnedConfigSelection, } from '../../common/feature-drawer-tabs/pinned-config-utils.js';
34
36
  export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgentEnabled = true, }) {
35
37
  const featureFlags = useFeatureFlags();
36
38
  const { t } = useTranslation('web');
@@ -38,6 +40,11 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
38
40
  const rejectSound = useSoundAction('reject');
39
41
  // Track the view locally so SSE events can update the drawer type in real-time
40
42
  const [view, setView] = useState(initialView);
43
+ const [pinnedConfigSelection, setPinnedConfigSelection] = useState(() => (initialView.type === 'feature' ? getPinnedConfigSelection(initialView.node) : null));
44
+ const [lastSavedPinnedConfig, setLastSavedPinnedConfig] = useState(() => (initialView.type === 'feature' ? getPinnedConfigSelection(initialView.node) : null));
45
+ const [pinnedConfigSaving, setPinnedConfigSaving] = useState(false);
46
+ const [pinnedConfigError, setPinnedConfigError] = useState(null);
47
+ const syncedPinnedConfigKeyRef = useRef(null);
41
48
  // Sync when server re-renders with new props (e.g. after navigation).
42
49
  // When reopening the SAME feature, merge server data into the existing view
43
50
  // to preserve enriched fields (repositoryName, baseBranch, oneLiner, remoteUrl)
@@ -56,6 +63,25 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
56
63
  });
57
64
  }, [initialView]);
58
65
  const featureNode = view.type === 'feature' ? view.node : null;
66
+ const canSwitchPinnedConfigForFeature = featureNode
67
+ ? canSwitchPinnedConfig(featureNode.state)
68
+ : false;
69
+ useEffect(() => {
70
+ if (view.type !== 'feature' || pinnedConfigSaving) {
71
+ return;
72
+ }
73
+ const nextSelection = getPinnedConfigSelection(view.node);
74
+ const nextKey = nextSelection
75
+ ? `${view.node.featureId}:${nextSelection.agentType}:${nextSelection.modelId}`
76
+ : `${view.node.featureId}:none`;
77
+ const changed = syncedPinnedConfigKeyRef.current !== nextKey;
78
+ syncedPinnedConfigKeyRef.current = nextKey;
79
+ setPinnedConfigSelection(nextSelection);
80
+ setLastSavedPinnedConfig(nextSelection);
81
+ if (changed) {
82
+ setPinnedConfigError(null);
83
+ }
84
+ }, [view, pinnedConfigSaving]);
59
85
  // SSE: update drawer view when feature state changes
60
86
  const { events } = useAgentEventsContext();
61
87
  const processedCountRef = useRef(0);
@@ -222,7 +248,7 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
222
248
  const { attemptClose } = useGuardedDrawerClose({ open: isOpen, isDirty, onClose, onReset });
223
249
  // ── Approve / reject handlers ─────────────────────────────────────────
224
250
  const handleReject = useCallback(async (feedback, label, attachments = [], onDone) => {
225
- if (!featureNode?.featureId)
251
+ if (pinnedConfigSaving || !featureNode?.featureId)
226
252
  return;
227
253
  isRejectingRef.current = true;
228
254
  setIsRejecting(true);
@@ -254,12 +280,12 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
254
280
  isRejectingRef.current = false;
255
281
  setIsRejecting(false);
256
282
  }
257
- }, [featureNode, onClose, rejectSound]);
283
+ }, [featureNode, onClose, pinnedConfigSaving, rejectSound]);
258
284
  const handlePrdReject = useCallback((feedback, attachments) => handleReject(feedback, 'Requirements', attachments, () => setPrdSelections({})), [handleReject]);
259
285
  const handleTechReject = useCallback((feedback, attachments) => handleReject(feedback, 'Plan', attachments), [handleReject]);
260
286
  const handleMergeReject = useCallback((feedback, attachments) => handleReject(feedback, 'Merge', attachments), [handleReject]);
261
287
  const handleSimpleApprove = useCallback(async (label) => {
262
- if (!featureNode?.featureId)
288
+ if (pinnedConfigSaving || !featureNode?.featureId)
263
289
  return;
264
290
  const result = await approveFeature(featureNode.featureId);
265
291
  if (!result.approved) {
@@ -273,9 +299,9 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
273
299
  detail: { featureId: featureNode.featureId },
274
300
  }));
275
301
  onClose();
276
- }, [featureNode, onClose]);
302
+ }, [featureNode, onClose, pinnedConfigSaving]);
277
303
  const handlePrdApprove = useCallback(async (_actionId) => {
278
- if (view.type !== 'feature' || !featureNode)
304
+ if (pinnedConfigSaving || view.type !== 'feature' || !featureNode)
279
305
  return;
280
306
  let payload;
281
307
  if (prdData) {
@@ -302,7 +328,7 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
302
328
  }));
303
329
  setPrdSelections({});
304
330
  onClose();
305
- }, [view, featureNode, prdData, prdSelections, onClose]);
331
+ }, [view, featureNode, pinnedConfigSaving, prdData, prdSelections, onClose]);
306
332
  const handleTechApprove = useCallback(() => handleSimpleApprove('Plan'), [handleSimpleApprove]);
307
333
  const handleMergeApprove = useCallback(() => handleSimpleApprove('Merge'), [handleSimpleApprove]);
308
334
  const handleDelete = useCallback(async (featureId, cleanup, cascadeDelete, closePr) => {
@@ -332,6 +358,8 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
332
358
  router.push('/');
333
359
  }, [router]);
334
360
  const handleRetry = useCallback(async (featureId) => {
361
+ if (pinnedConfigSaving)
362
+ return;
335
363
  const result = await resumeFeature(featureId);
336
364
  if (result.error) {
337
365
  toast.error(result.error);
@@ -346,7 +374,7 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
346
374
  return prev;
347
375
  return { ...prev, node: { ...prev.node, state: 'running' } };
348
376
  });
349
- }, []);
377
+ }, [pinnedConfigSaving]);
350
378
  const handleStop = useCallback(async (featureId) => {
351
379
  const result = await stopFeature(featureId);
352
380
  if (!result.stopped) {
@@ -361,6 +389,8 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
361
389
  });
362
390
  }, []);
363
391
  const handleStart = useCallback(async (featureId) => {
392
+ if (pinnedConfigSaving)
393
+ return;
364
394
  const result = await startFeature(featureId);
365
395
  if (result.error) {
366
396
  toast.error(result.error);
@@ -373,7 +403,61 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
373
403
  return prev;
374
404
  return { ...prev, node: { ...prev.node, state: 'running' } };
375
405
  });
376
- }, []);
406
+ }, [pinnedConfigSaving]);
407
+ const handlePinnedConfigSave = useCallback(async (agentType, modelId) => {
408
+ if (!featureNode) {
409
+ return { ok: false, error: 'Feature is not loaded' };
410
+ }
411
+ if (!canSwitchPinnedConfig(featureNode.state)) {
412
+ return {
413
+ ok: false,
414
+ error: 'Pinned execution can only be changed before start, approval, or retry',
415
+ };
416
+ }
417
+ const previousSelection = lastSavedPinnedConfig ?? getPinnedConfigSelection(featureNode);
418
+ const nextSelection = {
419
+ agentType: agentType,
420
+ modelId,
421
+ };
422
+ setPinnedConfigSelection(nextSelection);
423
+ setPinnedConfigError(null);
424
+ setPinnedConfigSaving(true);
425
+ try {
426
+ const result = await updateFeaturePinnedConfig(featureNode.featureId, agentType, modelId);
427
+ if (!result.ok) {
428
+ const error = result.error ?? 'Failed to save pinned config';
429
+ setPinnedConfigSelection(previousSelection);
430
+ setPinnedConfigError(error);
431
+ toast.error(error);
432
+ return { ok: false, error };
433
+ }
434
+ setLastSavedPinnedConfig(nextSelection);
435
+ setView((prev) => {
436
+ if (prev.type !== 'feature' || prev.node.featureId !== featureNode.featureId) {
437
+ return prev;
438
+ }
439
+ return {
440
+ ...prev,
441
+ node: {
442
+ ...prev.node,
443
+ agentType: nextSelection.agentType,
444
+ modelId,
445
+ },
446
+ };
447
+ });
448
+ return { ok: true };
449
+ }
450
+ catch (error) {
451
+ const message = error instanceof Error ? error.message : 'Failed to save pinned config';
452
+ setPinnedConfigSelection(previousSelection);
453
+ setPinnedConfigError(message);
454
+ toast.error(message);
455
+ return { ok: false, error: message };
456
+ }
457
+ finally {
458
+ setPinnedConfigSaving(false);
459
+ }
460
+ }, [featureNode, lastSavedPinnedConfig]);
377
461
  // ── Hooks (always called unconditionally per Rules of Hooks) ──────────
378
462
  const featureActionsInput = featureNode?.repositoryPath && featureNode?.branch
379
463
  ? {
@@ -449,7 +533,14 @@ export function FeatureDrawerClient({ view: initialView, urlTab, interactiveAgen
449
533
  ...(featureNode.state === 'error' && { onRetry: handleRetry }),
450
534
  ...(featureNode.state === 'pending' && { onStart: handleStart }),
451
535
  };
452
- body = (_jsx(FeatureDrawerTabs, { featureName: featureNode.name, headerContent: headerContent, featureNode: enrichedNode, featureId: featureNode.featureId, initialTab: view.initialTab, urlTab: urlTab, sseEvents: events, 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, syncStatus: syncFeatureId ? syncData : undefined, syncLoading: syncLoading, syncError: syncError, onRefreshSync: syncFeatureId ? refreshSync : undefined, onRebaseOnMain: syncFeatureId ? featureActions.rebaseOnMain : undefined, rebaseLoading: featureActions.rebaseLoading, rebaseError: featureActions.rebaseError, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput, interactiveAgentEnabled: interactiveAgentEnabled, onRetry: handleRetry, onStop: handleStop, onStart: handleStart }));
536
+ body = (_jsx(FeatureDrawerTabs, { featureName: featureNode.name, headerContent: headerContent, featureNode: enrichedNode, featureId: featureNode.featureId, initialTab: view.initialTab, urlTab: urlTab, sseEvents: events, 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, syncStatus: syncFeatureId ? syncData : undefined, syncLoading: syncLoading, syncError: syncError, onRefreshSync: syncFeatureId ? refreshSync : undefined, onRebaseOnMain: syncFeatureId ? featureActions.rebaseOnMain : undefined, rebaseLoading: featureActions.rebaseLoading, rebaseError: featureActions.rebaseError, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: setChatInput, pinnedConfig: canSwitchPinnedConfigForFeature && pinnedConfigSelection
537
+ ? {
538
+ ...pinnedConfigSelection,
539
+ saving: pinnedConfigSaving,
540
+ error: pinnedConfigError,
541
+ onSave: handlePinnedConfigSave,
542
+ }
543
+ : undefined, continuationActionsDisabled: pinnedConfigSaving, interactiveAgentEnabled: interactiveAgentEnabled, onRetry: handleRetry, onStop: handleStop, onStart: handleStart }));
453
544
  }
454
545
  return (_jsx(BaseDrawer, { open: isOpen, onClose: attemptClose, size: "lg", modal: false, "data-testid": view.type === 'feature' ? 'feature-drawer' : 'repository-drawer', children: body }));
455
546
  }
@@ -7,6 +7,7 @@ import type { MergeReviewData } from '../../common/merge-review/index.js';
7
7
  import type { RejectAttachment } from '../../common/drawer-action-bar/index.js';
8
8
  import type { FeatureTabKey } from '../../common/control-center-drawer/drawer-view.js';
9
9
  import type { BranchSyncData } from '../../../hooks/use-branch-sync-status.js';
10
+ import type { FeatureDrawerPinnedConfig } from './pinned-config-utils.js';
10
11
  export interface FeatureDrawerTabsProps {
11
12
  /** Feature name rendered in the inline header. */
12
13
  featureName?: string;
@@ -48,8 +49,10 @@ export interface FeatureDrawerTabsProps {
48
49
  isRejecting?: boolean;
49
50
  chatInput?: string;
50
51
  onChatInputChange?: (value: string) => void;
52
+ pinnedConfig?: FeatureDrawerPinnedConfig;
53
+ continuationActionsDisabled?: boolean;
51
54
  /** When false, the Chat tab is hidden from the tab bar (FR-17). Defaults to true. */
52
55
  interactiveAgentEnabled?: boolean;
53
56
  }
54
- export declare function FeatureDrawerTabs({ featureName, headerContent, featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, isRejecting, chatInput, onChatInputChange, sseEvents, interactiveAgentEnabled, onRetry, onStop, onStart, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
57
+ export declare function FeatureDrawerTabs({ featureName, headerContent, featureNode, featureId, initialTab, urlTab, prdData, prdSelections, onPrdSelect, onPrdApprove, onPrdReject, isPrdLoading, techData, onTechApprove, onTechReject, isTechLoading, productData, mergeData, onMergeApprove, onMergeReject, isMergeLoading, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, isRejecting, chatInput, onChatInputChange, pinnedConfig, continuationActionsDisabled, sseEvents, interactiveAgentEnabled, onRetry, onStop, onStart, }: FeatureDrawerTabsProps): import("react/jsx-runtime").JSX.Element;
55
58
  //# 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":"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"}
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":"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"}