@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
@@ -78,7 +78,7 @@ const TAB_FETCHERS = {
78
78
  activity: fetchActivity,
79
79
  plan: fetchPlan,
80
80
  };
81
- export 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 = true, onRetry, onStop, onStart, }) {
81
+ export 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 = false, sseEvents, interactiveAgentEnabled = true, onRetry, onStop, onStart, }) {
82
82
  const pathname = usePathname();
83
83
  const visibleTabs = useMemo(() => computeVisibleTabs(featureNode, interactiveAgentEnabled), [featureNode, interactiveAgentEnabled]);
84
84
  const visibleTabDefs = useMemo(() => ALL_TABS.filter((t) => visibleTabs.includes(t.key)).map((t) => t.key === 'merge-review' && featureNode.lifecycle === 'maintain'
@@ -261,9 +261,9 @@ export function FeatureDrawerTabs({ featureName, headerContent, featureNode, fea
261
261
  }) }), _jsxs("div", { className: "bg-muted/40 shrink-0 border-b", children: [featureName ? (_jsxs("div", { className: "flex h-12 items-stretch gap-2 pr-0 pl-4", "data-testid": "feature-drawer-header", children: [_jsx("div", { className: "flex items-center", children: featureNode.fastMode ? (_jsx(Zap, { className: "size-4 shrink-0 text-amber-500" })) : (_jsx(Layers, { className: "text-muted-foreground/50 size-4 shrink-0" })) }), _jsx("h2", { className: "text-foreground flex min-w-0 items-center truncate text-base font-semibold tracking-tight", children: featureName }), featureNode.repositoryName ? (_jsxs("span", { className: "animate-in fade-in flex shrink-0 items-center gap-1.5 self-center duration-200", children: [_jsx("span", { className: "text-muted-foreground/30 text-sm", children: "/" }), featureNode.remoteUrl ? (_jsx("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground text-sm", children: featureNode.repositoryName })) : (_jsx("span", { className: "text-muted-foreground text-sm", children: featureNode.repositoryName }))] })) : (_jsxs("span", { className: "flex items-center gap-1.5 self-center", children: [_jsx("span", { className: "text-muted-foreground/30 text-sm", children: "/" }), _jsx("span", { className: "bg-muted h-4 w-16 animate-pulse rounded" })] })), _jsx(TooltipProvider, { delayDuration: 300, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "ml-auto flex shrink-0 cursor-default items-center self-stretch text-xs font-medium", children: [_jsxs("div", { className: cn('flex items-center gap-1.5 self-stretch px-3', featureNodeStateConfig[featureNode.state].labelClass), children: [featureNode.state === 'running' ? (_jsx(CometSpinner, { size: "sm", className: "shrink-0" })) : ((() => {
262
262
  const I = featureNodeStateConfig[featureNode.state].icon;
263
263
  return _jsx(I, { className: "size-3.5 shrink-0" });
264
- })()), featureNodeStateConfig[featureNode.state].label] }), featureNode.state === 'pending' && onStart ? (_jsxs("button", { type: "button", onClick: () => onStart(featureNode.featureId), className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-green-500/10 hover:text-green-600 dark:hover:text-green-400", "data-testid": "feature-drawer-start-button", children: [_jsx(Play, { className: "size-3.5" }), " Start"] })) : featureNode.state === 'error' && onRetry ? (_jsxs("button", { type: "button", onClick: () => onRetry(featureNode.featureId), className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 dark:hover:text-red-400", "data-testid": "feature-drawer-retry-button", children: [_jsx(RotateCcw, { className: "size-3.5" }), " Retry"] })) : featureNode.state === 'running' && onStop ? (_jsxs("button", { type: "button", onClick: () => onStop(featureNode.featureId), className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 dark:hover:text-red-400", "data-testid": "feature-drawer-stop-button", children: [_jsx(Square, { className: "size-3.5" }), " Stop"] })) : null] }) }), featureNode.errorMessage ? (_jsxs(TooltipContent, { side: "bottom", align: "end", sideOffset: 4, className: "z-[100] max-w-xs cursor-pointer text-xs leading-relaxed select-text", onClick: () => {
264
+ })()), featureNodeStateConfig[featureNode.state].label] }), featureNode.state === 'pending' && onStart ? (_jsxs("button", { type: "button", onClick: () => onStart(featureNode.featureId), disabled: continuationActionsDisabled, className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-green-500/10 hover:text-green-600 disabled:pointer-events-none disabled:opacity-50 dark:hover:text-green-400", "data-testid": "feature-drawer-start-button", children: [_jsx(Play, { className: "size-3.5" }), " Start"] })) : featureNode.state === 'error' && onRetry ? (_jsxs("button", { type: "button", onClick: () => onRetry(featureNode.featureId), disabled: continuationActionsDisabled, className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 disabled:pointer-events-none disabled:opacity-50 dark:hover:text-red-400", "data-testid": "feature-drawer-retry-button", children: [_jsx(RotateCcw, { className: "size-3.5" }), " Retry"] })) : featureNode.state === 'running' && onStop ? (_jsxs("button", { type: "button", onClick: () => onStop(featureNode.featureId), className: "text-muted-foreground flex items-center gap-1 self-stretch px-3 hover:bg-red-500/10 hover:text-red-500 dark:hover:text-red-400", "data-testid": "feature-drawer-stop-button", children: [_jsx(Square, { className: "size-3.5" }), " Stop"] })) : null] }) }), featureNode.errorMessage ? (_jsxs(TooltipContent, { side: "bottom", align: "end", sideOffset: 4, className: "z-[100] max-w-xs cursor-pointer text-xs leading-relaxed select-text", onClick: () => {
265
265
  void navigator.clipboard.writeText(featureNode.errorMessage);
266
- }, children: [featureNode.errorMessage, _jsx("span", { className: "text-muted-foreground ml-1 text-[10px] italic", children: "(click to copy)" })] })) : null] }) })] })) : null, headerContent] }), _jsx(TabsContent, { value: "overview", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(OverviewTab, { data: featureNode, syncStatus: syncStatus, syncLoading: syncLoading, syncError: syncError, onRefreshSync: onRefreshSync, onRebaseOnMain: onRebaseOnMain, rebaseLoading: rebaseLoading, rebaseError: rebaseError }) }), _jsx(TabsContent, { value: "activity", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(ActivityTab, { timings: tabs.activity.data?.timings ?? null, loading: tabs.activity.loading, error: tabs.activity.error, rejectionFeedback: tabs.activity.data?.rejectionFeedback }) }), _jsx(TabsContent, { value: "log", className: "mt-0 flex-1 overflow-hidden", children: _jsx(LogTab, { content: featureLogs.content, isConnected: featureLogs.isConnected, error: featureLogs.error }) }), _jsx(TabsContent, { value: "plan", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(PlanTab, { plan: tabs.plan.data, loading: tabs.plan.loading, error: tabs.plan.error }) }), visibleTabs.includes('prd-review') ? (_jsx(TabsContent, { value: "prd-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections ?? {}, onSelect: onPrdSelect ?? (() => undefined), onApprove: onPrdApprove ?? (() => undefined), onReject: onPrdReject, isProcessing: isPrdLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('tech-decisions') ? (_jsx(TabsContent, { value: "tech-decisions", className: "mt-0 flex min-h-0 flex-1 flex-col", children: techData ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(TechDecisionsContent, { data: techData }) }), _jsx(DrawerActionBarForTech, { onApprove: onTechApprove ?? (() => undefined), onReject: onTechReject, isProcessing: isTechLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })] })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('product-decisions') ? (_jsx(TabsContent, { value: "product-decisions", className: "mt-0 flex-1 overflow-y-auto", children: productData === null ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : productData ? (_jsx(ProductDecisionsSummary, { data: productData })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No product decisions available." })) })) : null, visibleTabs.includes('merge-review') ? (_jsx(TabsContent, { value: "merge-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: mergeData ? (_jsx(MergeReview, { data: mergeData, readOnly: featureNode.lifecycle === 'maintain', onApprove: onMergeApprove ?? (() => undefined), onReject: onMergeReject, isProcessing: isMergeLoading, isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: isMergeLoading ? (_jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" })) : (_jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-2 text-sm", children: [_jsx(AlertCircle, { className: "h-6 w-6" }), _jsx("span", { children: "Merge review data unavailable" })] })) })) })) : null, visibleTabs.includes('chat') ? (_jsx(TabsContent, { value: "chat", className: "mt-0 flex min-h-0 flex-1 flex-col overflow-hidden", children: _jsx(ChatTab, { featureId: featureId, worktreePath: featureNode.worktreePath }) })) : null] }) }));
266
+ }, children: [featureNode.errorMessage, _jsx("span", { className: "text-muted-foreground ml-1 text-[10px] italic", children: "(click to copy)" })] })) : null] }) })] })) : null, headerContent] }), _jsx(TabsContent, { value: "overview", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(OverviewTab, { data: featureNode, pinnedConfig: pinnedConfig, syncStatus: syncStatus, syncLoading: syncLoading, syncError: syncError, onRefreshSync: onRefreshSync, onRebaseOnMain: onRebaseOnMain, rebaseLoading: rebaseLoading, rebaseError: rebaseError }) }), _jsx(TabsContent, { value: "activity", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(ActivityTab, { timings: tabs.activity.data?.timings ?? null, loading: tabs.activity.loading, error: tabs.activity.error, rejectionFeedback: tabs.activity.data?.rejectionFeedback }) }), _jsx(TabsContent, { value: "log", className: "mt-0 flex-1 overflow-hidden", children: _jsx(LogTab, { content: featureLogs.content, isConnected: featureLogs.isConnected, error: featureLogs.error }) }), _jsx(TabsContent, { value: "plan", className: "mt-0 flex-1 overflow-y-auto", children: _jsx(PlanTab, { plan: tabs.plan.data, loading: tabs.plan.loading, error: tabs.plan.error }) }), visibleTabs.includes('prd-review') ? (_jsx(TabsContent, { value: "prd-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections ?? {}, onSelect: onPrdSelect ?? (() => undefined), onApprove: onPrdApprove ?? (() => undefined), onReject: onPrdReject, isProcessing: Boolean((isPrdLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('tech-decisions') ? (_jsx(TabsContent, { value: "tech-decisions", className: "mt-0 flex min-h-0 flex-1 flex-col", children: techData ? (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(TechDecisionsContent, { data: techData }) }), _jsx(DrawerActionBarForTech, { onApprove: onTechApprove ?? (() => undefined), onReject: onTechReject, isProcessing: Boolean((isTechLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })] })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) })) : null, visibleTabs.includes('product-decisions') ? (_jsx(TabsContent, { value: "product-decisions", className: "mt-0 flex-1 overflow-y-auto", children: productData === null ? (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) })) : productData ? (_jsx(ProductDecisionsSummary, { data: productData })) : (_jsx("p", { className: "text-muted-foreground p-4 text-center text-sm", children: "No product decisions available." })) })) : null, visibleTabs.includes('merge-review') ? (_jsx(TabsContent, { value: "merge-review", className: "mt-0 flex min-h-0 flex-1 flex-col", children: mergeData ? (_jsx(MergeReview, { data: mergeData, readOnly: featureNode.lifecycle === 'maintain', onApprove: onMergeApprove ?? (() => undefined), onReject: onMergeReject, isProcessing: Boolean((isMergeLoading ?? false) || continuationActionsDisabled), isRejecting: isRejecting, chatInput: chatInput, onChatInputChange: onChatInputChange })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: isMergeLoading ? (_jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" })) : (_jsxs("div", { className: "text-muted-foreground flex flex-col items-center gap-2 text-sm", children: [_jsx(AlertCircle, { className: "h-6 w-6" }), _jsx("span", { children: "Merge review data unavailable" })] })) })) })) : null, visibleTabs.includes('chat') ? (_jsx(TabsContent, { value: "chat", className: "mt-0 flex min-h-0 flex-1 flex-col overflow-hidden", children: _jsx(ChatTab, { featureId: featureId, worktreePath: featureNode.worktreePath }) })) : null] }) }));
267
267
  }
268
268
  // ── Private helper ──────────────────────────────────────────────────────
269
269
  function DrawerActionBarForTech({ onApprove, onReject, isProcessing, isRejecting, chatInput, onChatInputChange, }) {
@@ -1,7 +1,9 @@
1
1
  import type { FeatureNodeData } from '../../common/feature-node/index.js';
2
2
  import type { BranchSyncData } from '../../../hooks/use-branch-sync-status.js';
3
+ import { type FeatureDrawerPinnedConfig } from './pinned-config-utils.js';
3
4
  export interface OverviewTabProps {
4
5
  data: FeatureNodeData;
6
+ pinnedConfig?: FeatureDrawerPinnedConfig;
5
7
  syncStatus?: BranchSyncData | null;
6
8
  syncLoading?: boolean;
7
9
  syncError?: string | null;
@@ -10,5 +12,5 @@ export interface OverviewTabProps {
10
12
  rebaseLoading?: boolean;
11
13
  rebaseError?: string | null;
12
14
  }
13
- export declare function OverviewTab({ data, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, }: OverviewTabProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function OverviewTab({ data, pinnedConfig, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, }: OverviewTabProps): import("react/jsx-runtime").JSX.Element;
14
16
  //# sourceMappingURL=overview-tab.d.ts.map
@@ -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":"AA4BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAOxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AA2GrE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,UAAU,EACV,WAAW,EACX,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,WAAW,GACZ,EAAE,gBAAgB,2CAuLlB"}
1
+ {"version":3,"file":"overview-tab.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAQxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAyB,KAAK,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AA2G9F,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,eAAe,CAAC;IACtB,YAAY,CAAC,EAAE,yBAAyB,CAAC;IACzC,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,WAAW,EACX,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,WAAW,GACZ,EAAE,gBAAgB,2CAuLlB"}
@@ -10,9 +10,11 @@ import { CiStatusBadge } from '../../common/ci-status-badge/index.js';
10
10
  import { CometSpinner } from '../../ui/comet-spinner.js';
11
11
  import { ActionButton } from '../../common/action-button/index.js';
12
12
  import { featureNodeStateConfig } from '../../common/feature-node/index.js';
13
+ import { AgentModelPicker } from '../../features/settings/AgentModelPicker/index.js';
13
14
  import { getAgentTypeIcon, agentTypeLabels, } from '../../common/feature-node/agent-type-icons.js';
14
15
  import { getModelMeta } from '../../../lib/model-metadata.js';
15
16
  import { formatDuration } from '../../../lib/format-duration.js';
17
+ import { canSwitchPinnedConfig } from './pinned-config-utils.js';
16
18
  // ── Primitives ──────────────────────────────────────────────────────
17
19
  function Section({ icon: Icon, title, children, }) {
18
20
  return (_jsxs("div", { className: "px-3 pt-4 pb-1", children: [_jsxs("div", { className: "text-foreground mb-2 flex items-center gap-1.5 text-sm font-semibold tracking-wider uppercase", children: [_jsx(Icon, { className: "size-4 opacity-50" }), title] }), children] }));
@@ -74,7 +76,7 @@ const prColor = {
74
76
  [PrStatus.Merged]: 'text-purple-600 dark:text-purple-400',
75
77
  [PrStatus.Closed]: 'text-red-600 dark:text-red-400',
76
78
  };
77
- export function OverviewTab({ data, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, }) {
79
+ export function OverviewTab({ data, pinnedConfig, syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, }) {
78
80
  const isCompleted = data.lifecycle === 'maintain';
79
81
  const isRunning = data.state === 'running' || data.state === 'action-required';
80
82
  const elapsedTime = useElapsedTime(isRunning ? data.startedAt : undefined);
@@ -86,7 +88,7 @@ export function OverviewTab({ data, syncStatus, syncLoading, syncError, onRefres
86
88
  return _jsx(I, { className: "size-3.5 shrink-0 opacity-50" });
87
89
  })()
88
90
  : null, data.agentType ? (_jsx("span", { children: agentTypeLabels[data.agentType] ??
89
- data.agentType })) : null, data.agentType && data.modelId ? (_jsx("span", { className: "text-foreground/20", children: "/" })) : null, data.modelId ? (_jsx("span", { className: "text-foreground/50 text-[12px]", children: getModelMeta(data.modelId).displayName || data.modelId })) : null] }) }) })) : null, data.createdAt ? (_jsx(Card, { children: _jsx(KV, { label: "Created", children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Clock, { className: "text-foreground/30 size-3 shrink-0" }), formatRelativeTime(data.createdAt)] }) }) })) : null, data.fastMode ? (_jsx(Card, { children: _jsx(KV, { label: "Mode", children: _jsxs("span", { className: "inline-flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [_jsx(Zap, { className: "size-3.5" }), " Fast"] }) }) })) : null, data.runtime || elapsedTime ? (_jsx(Card, { children: _jsx(KV, { label: data.runtime ? 'Runtime' : 'Elapsed', children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Clock, { className: "text-foreground/30 size-3 shrink-0" }), data.runtime ?? elapsedTime] }) }) })) : null] }), data.blockedBy || data.errorMessage ? (_jsx(Section, { icon: AlertTriangle, title: "Issues", children: _jsxs(Card, { className: "border-destructive/20 bg-destructive/5", children: [data.blockedBy ? _jsx(KV, { label: "Blocked By", children: data.blockedBy }) : null, data.errorMessage ? (_jsx(KV, { label: "Error", children: _jsx("span", { className: "text-destructive", children: data.errorMessage }) })) : null] }) })) : null, onRebaseOnMain && data.branch && onRefreshSync ? (_jsx(Section, { icon: RefreshCw, title: "Branch Sync", children: _jsx(SyncCard, { syncStatus: syncStatus ?? null, syncLoading: syncLoading ?? false, syncError: syncError ?? null, onRefreshSync: onRefreshSync, onRebaseOnMain: onRebaseOnMain, rebaseLoading: rebaseLoading ?? false, rebaseError: rebaseError ?? null }) })) : null, _jsx(SettingsBlock, { data: data })] }));
91
+ data.agentType })) : null, data.agentType && data.modelId ? (_jsx("span", { className: "text-foreground/20", children: "/" })) : null, data.modelId ? (_jsx("span", { className: "text-foreground/50 text-[12px]", children: getModelMeta(data.modelId).displayName || data.modelId })) : null] }) }) })) : null, data.createdAt ? (_jsx(Card, { children: _jsx(KV, { label: "Created", children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Clock, { className: "text-foreground/30 size-3 shrink-0" }), formatRelativeTime(data.createdAt)] }) }) })) : null, data.fastMode ? (_jsx(Card, { children: _jsx(KV, { label: "Mode", children: _jsxs("span", { className: "inline-flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [_jsx(Zap, { className: "size-3.5" }), " Fast"] }) }) })) : null, data.runtime || elapsedTime ? (_jsx(Card, { children: _jsx(KV, { label: data.runtime ? 'Runtime' : 'Elapsed', children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [_jsx(Clock, { className: "text-foreground/30 size-3 shrink-0" }), data.runtime ?? elapsedTime] }) }) })) : null] }), data.blockedBy || data.errorMessage ? (_jsx(Section, { icon: AlertTriangle, title: "Issues", children: _jsxs(Card, { className: "border-destructive/20 bg-destructive/5", children: [data.blockedBy ? _jsx(KV, { label: "Blocked By", children: data.blockedBy }) : null, data.errorMessage ? (_jsx(KV, { label: "Error", children: _jsx("span", { className: "text-destructive", children: data.errorMessage }) })) : null] }) })) : null, onRebaseOnMain && data.branch && onRefreshSync ? (_jsx(Section, { icon: RefreshCw, title: "Branch Sync", children: _jsx(SyncCard, { syncStatus: syncStatus ?? null, syncLoading: syncLoading ?? false, syncError: syncError ?? null, onRefreshSync: onRefreshSync, onRebaseOnMain: onRebaseOnMain, rebaseLoading: rebaseLoading ?? false, rebaseError: rebaseError ?? null }) })) : null, _jsx(SettingsBlock, { data: data, pinnedConfig: pinnedConfig })] }));
90
92
  }
91
93
  // ── Sync card ───────────────────────────────────────────────────────
92
94
  function SyncCard({ syncStatus, syncLoading, syncError, onRefreshSync, onRebaseOnMain, rebaseLoading, rebaseError, }) {
@@ -97,19 +99,28 @@ function SyncCard({ syncStatus, syncLoading, syncError, onRefreshSync, onRebaseO
97
99
  return (_jsxs(Card, { children: [_jsxs("div", { "data-testid": "branch-sync-status", className: "flex items-center justify-between", children: [_jsx("div", { className: "flex items-center gap-1.5 text-[13px]", children: syncLoading && !syncStatus ? (_jsxs(_Fragment, { children: [_jsx(CometSpinner, { size: "sm" }), _jsx("span", { className: "text-foreground/40", children: "Checking..." })] })) : syncError ? (_jsxs(_Fragment, { children: [_jsx(AlertTriangle, { className: "size-3.5 text-red-500" }), _jsx("span", { className: "text-destructive text-xs", children: syncError })] })) : rebaseLoading ? (_jsxs(_Fragment, { children: [_jsx(CometSpinner, { size: "sm" }), _jsxs("span", { children: ["Rebasing on ", _jsx("code", { className: "font-mono text-[11px]", children: base }), "..."] })] })) : isBehind ? (_jsxs(_Fragment, { children: [_jsx(AlertTriangle, { className: "size-3.5 text-orange-500" }), _jsxs("span", { children: [syncStatus.behind, " behind ", _jsx("code", { className: "font-mono text-[11px]", children: base }), syncStatus.ahead > 0 ? (_jsxs("span", { className: "text-foreground/30 ml-1 text-[11px]", children: ["\u00B7 ", syncStatus.ahead, " ahead"] })) : null] })] })) : isUpToDate ? (_jsxs(_Fragment, { children: [_jsx(CheckCircle2, { className: "size-3.5 text-green-500" }), _jsxs("span", { children: ["Up to date \u00B7 ", _jsx("code", { className: "font-mono text-[11px]", children: base }), syncStatus.ahead > 0 ? (_jsxs("span", { className: "text-foreground/30 ml-1 text-[11px]", children: ["\u00B7 ", syncStatus.ahead, " ahead"] })) : null] })] })) : null }), (syncStatus || syncError) && !rebaseLoading ? (_jsx("button", { onClick: onRefreshSync, disabled: syncLoading, className: "text-foreground/30 hover:text-foreground/60 hover:bg-foreground/5 inline-flex size-6 items-center justify-center rounded-sm disabled:opacity-50", "aria-label": t('branchSyncStatus.refreshSyncStatus'), children: _jsx(RefreshCw, { className: cn('size-3', syncLoading && 'animate-spin') }) })) : null] }), isBehind && !rebaseLoading ? (_jsx("div", { className: "pt-2", children: _jsx(ActionButton, { label: t('branchSyncStatus.rebaseOnMain'), onClick: onRebaseOnMain, loading: false, error: !!rebaseError, icon: GitMerge, variant: "outline", size: "sm" }) })) : null, rebaseError ? _jsx("p", { className: "text-destructive pt-1 text-[11px]", children: rebaseError }) : null] }));
98
100
  }
99
101
  // ── Settings ────────────────────────────────────────────────────────
100
- function SettingsBlock({ data }) {
101
- const has = data.approvalGates != null ||
102
+ function PinnedConfigCard({ pinnedConfig }) {
103
+ const AgentIcon = getAgentTypeIcon(pinnedConfig.agentType);
104
+ const modelName = pinnedConfig.modelId
105
+ ? getModelMeta(pinnedConfig.modelId).displayName || pinnedConfig.modelId
106
+ : 'No model selected';
107
+ return (_jsxs(Card, { "data-testid": "feature-pinned-config-card", className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-foreground/40 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(Settings, { className: "size-3" }), " Pinned Execution"] }), _jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(AgentIcon, { className: "size-4 shrink-0 opacity-60" }), _jsx("span", { className: "font-medium", children: agentTypeLabels[pinnedConfig.agentType] ??
108
+ pinnedConfig.agentType }), _jsx("span", { className: "text-foreground/20", children: "/" }), _jsx("span", { className: "text-foreground/60", children: modelName })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Change the pinned agent and model before the next start, approval, or retry." })] }), _jsx(AgentModelPicker, { initialAgentType: pinnedConfig.agentType, initialModel: pinnedConfig.modelId, agentType: pinnedConfig.agentType, model: pinnedConfig.modelId, onSave: pinnedConfig.onSave, saveError: pinnedConfig.error, saving: pinnedConfig.saving, disabled: pinnedConfig.saving, mode: "settings" })] }));
109
+ }
110
+ function SettingsBlock({ data, pinnedConfig, }) {
111
+ const hasSettings = data.approvalGates != null ||
102
112
  data.push != null ||
103
113
  data.openPr != null ||
104
114
  data.ciWatchEnabled != null ||
105
115
  data.enableEvidence != null ||
106
116
  data.forkAndPr != null ||
107
117
  data.commitSpecs != null;
108
- if (!has)
118
+ const showPinnedConfig = pinnedConfig != null && canSwitchPinnedConfig(data.state);
119
+ if (!hasSettings && !showPinnedConfig)
109
120
  return null;
110
- return (_jsx(Section, { icon: Settings, title: "Settings", children: _jsxs("div", { className: "grid grid-cols-3 gap-2", children: [data.approvalGates ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(ShieldCheck, { className: "size-3" }), " Approve"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Flag, { on: data.approvalGates.allowPrd, label: "PRD" }), _jsx(Flag, { on: data.approvalGates.allowPlan, label: "Plan" }), _jsx(Flag, { on: data.approvalGates.allowMerge, label: "Merge" })] })] })) : null, data.enableEvidence != null ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(FileSearch, { className: "size-3" }), " Evidence"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Flag, { on: data.enableEvidence, label: "Collect" }), data.commitEvidence != null ? (_jsx(Flag, { on: data.commitEvidence, label: "Add to PR" })) : null] })] })) : null, data.push != null ||
111
- data.openPr != null ||
112
- data.ciWatchEnabled != null ||
113
- data.commitSpecs != null ||
114
- data.forkAndPr != null ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(GitBranch, { className: "size-3" }), " Git"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [data.push != null ? _jsx(Flag, { on: data.push, label: "Push" }) : null, data.openPr != null ? _jsx(Flag, { on: data.openPr, label: "PR" }) : null, data.ciWatchEnabled != null ? _jsx(Flag, { on: data.ciWatchEnabled, label: "Watch" }) : null, data.commitSpecs != null ? _jsx(Flag, { on: data.commitSpecs, label: "Specs" }) : null, data.forkAndPr != null ? _jsx(Flag, { on: data.forkAndPr, label: "Fork" }) : null] })] })) : null] }) }));
121
+ return (_jsx(Section, { icon: Settings, title: "Settings", children: _jsxs("div", { className: "flex flex-col gap-2", children: [showPinnedConfig ? _jsx(PinnedConfigCard, { pinnedConfig: pinnedConfig }) : null, hasSettings ? (_jsxs("div", { className: "grid grid-cols-3 gap-2", children: [data.approvalGates ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(ShieldCheck, { className: "size-3" }), " Approve"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Flag, { on: data.approvalGates.allowPrd, label: "PRD" }), _jsx(Flag, { on: data.approvalGates.allowPlan, label: "Plan" }), _jsx(Flag, { on: data.approvalGates.allowMerge, label: "Merge" })] })] })) : null, data.enableEvidence != null ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(FileSearch, { className: "size-3" }), " Evidence"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx(Flag, { on: data.enableEvidence, label: "Collect" }), data.commitEvidence != null ? (_jsx(Flag, { on: data.commitEvidence, label: "Add to PR" })) : null] })] })) : null, data.push != null ||
122
+ data.openPr != null ||
123
+ data.ciWatchEnabled != null ||
124
+ data.commitSpecs != null ||
125
+ data.forkAndPr != null ? (_jsxs(Card, { children: [_jsxs("div", { className: "text-foreground/40 mb-1.5 flex items-center gap-1 text-[10px] font-medium tracking-wider uppercase", children: [_jsx(GitBranch, { className: "size-3" }), " Git"] }), _jsxs("div", { className: "flex flex-col gap-0.5", children: [data.push != null ? _jsx(Flag, { on: data.push, label: "Push" }) : null, data.openPr != null ? _jsx(Flag, { on: data.openPr, label: "PR" }) : null, data.ciWatchEnabled != null ? (_jsx(Flag, { on: data.ciWatchEnabled, label: "Watch" })) : null, data.commitSpecs != null ? _jsx(Flag, { on: data.commitSpecs, label: "Specs" }) : null, data.forkAndPr != null ? _jsx(Flag, { on: data.forkAndPr, label: "Fork" }) : null] })] })) : null] })) : null] }) }));
115
126
  }
@@ -15,6 +15,10 @@ export declare const DoneWithMergedPr: Story;
15
15
  export declare const Blocked: Story;
16
16
  /** Error state showing error message detail. */
17
17
  export declare const Error: Story;
18
+ /** Pending feature with the pinned execution switch visible. */
19
+ export declare const PendingWithPinnedConfigSwitch: Story;
20
+ /** Pending feature showing inline save feedback for the pinned execution switch. */
21
+ export declare const PendingWithPinnedConfigError: Story;
18
22
  /** Error state with retry button visible. */
19
23
  export declare const ErrorWithRetry: Story;
20
24
  /** Running state with stop button visible. */
@@ -1 +1 @@
1
- {"version":3,"file":"overview-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AA0G1C,uEAAuE;AACvE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAExB,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAOF,6CAA6C;AAC7C,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAwBF,mEAAmE;AACnE,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,oBAAoB;AACpB,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,KAclC,CAAC;AAqBF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,KAEpC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,eAAe,EAAE,KAgB7B,CAAC;AAMF,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,KAY7B,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAE,KAYlC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,EAAE,KAQjC,CAAC;AAMF,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AAEF,sCAAsC;AACtC,eAAO,MAAM,aAAa,EAAE,KAO3B,CAAC;AAEF,mCAAmC;AACnC,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC"}
1
+ {"version":3,"file":"overview-tab.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/overview-tab.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AA0G1C,uEAAuE;AACvE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAExB,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,iDAAiD;AACjD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,gDAAgD;AAChD,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,6BAA6B,EAAE,KAc3C,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,4BAA4B,EAAE,KAe1C,CAAC;AAOF,6CAA6C;AAC7C,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,eAAe,EAAE,KAE7B,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAwBF,mEAAmE;AACnE,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF,0BAA0B;AAC1B,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,oBAAoB;AACpB,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,sBAAsB;AACtB,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAE,KAclC,CAAC;AAqBF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,KAEpC,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,eAAe,EAAE,KAgB7B,CAAC;AAMF,oFAAoF;AACpF,eAAO,MAAM,eAAe,EAAE,KAY7B,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,uBAAuB,EAAE,KAYrC,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAE,KAYlC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,EAAE,KAQjC,CAAC;AAMF,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AAEF,sCAAsC;AACtC,eAAO,MAAM,aAAa,EAAE,KAO3B,CAAC;AAEF,mCAAmC;AACnC,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC"}
@@ -133,6 +133,39 @@ export const Blocked = {
133
133
  export const Error = {
134
134
  args: { data: errorData },
135
135
  };
136
+ /** Pending feature with the pinned execution switch visible. */
137
+ export const PendingWithPinnedConfigSwitch = {
138
+ args: {
139
+ data: {
140
+ ...noProgressData,
141
+ state: 'pending',
142
+ agentType: 'codex-cli',
143
+ modelId: 'gpt-5.4',
144
+ },
145
+ pinnedConfig: {
146
+ agentType: 'codex-cli',
147
+ modelId: 'gpt-5.4',
148
+ onSave: async () => ({ ok: true }),
149
+ },
150
+ },
151
+ };
152
+ /** Pending feature showing inline save feedback for the pinned execution switch. */
153
+ export const PendingWithPinnedConfigError = {
154
+ args: {
155
+ data: {
156
+ ...noProgressData,
157
+ state: 'pending',
158
+ agentType: 'claude-code',
159
+ modelId: 'claude-sonnet-4-6',
160
+ },
161
+ pinnedConfig: {
162
+ agentType: 'claude-code',
163
+ modelId: 'claude-sonnet-4-6',
164
+ error: 'Could not save pinned config',
165
+ onSave: async () => ({ ok: false, error: 'Could not save pinned config' }),
166
+ },
167
+ },
168
+ };
136
169
  const errorWithRetryData = {
137
170
  ...errorData,
138
171
  onRetry: fn(),
@@ -0,0 +1,18 @@
1
+ import type { FeatureNodeData } from '../../common/feature-node/index.js';
2
+ export interface PinnedConfigSelection {
3
+ agentType: NonNullable<FeatureNodeData['agentType']>;
4
+ modelId: string;
5
+ }
6
+ export interface FeatureDrawerPinnedConfig {
7
+ agentType: string;
8
+ modelId: string;
9
+ saving?: boolean;
10
+ error?: string | null;
11
+ onSave: (agentType: string, modelId: string) => Promise<{
12
+ ok: boolean;
13
+ error?: string;
14
+ }>;
15
+ }
16
+ export declare function canSwitchPinnedConfig(state: FeatureNodeData['state']): boolean;
17
+ export declare function getPinnedConfigSelection(node: Pick<FeatureNodeData, 'agentType' | 'modelId'> | null | undefined): PinnedConfigSelection | null;
18
+ //# sourceMappingURL=pinned-config-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-config-utils.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer-tabs/pinned-config-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAQxE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC;IACrD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1F;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,OAAO,CAE9E;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,GACtE,qBAAqB,GAAG,IAAI,CAS9B"}
@@ -0,0 +1,17 @@
1
+ const ELIGIBLE_PINNED_CONFIG_STATES = new Set([
2
+ 'pending',
3
+ 'action-required',
4
+ 'error',
5
+ ]);
6
+ export function canSwitchPinnedConfig(state) {
7
+ return ELIGIBLE_PINNED_CONFIG_STATES.has(state);
8
+ }
9
+ export function getPinnedConfigSelection(node) {
10
+ if (!node?.agentType) {
11
+ return null;
12
+ }
13
+ return {
14
+ agentType: node.agentType,
15
+ modelId: node.modelId ?? '',
16
+ };
17
+ }
@@ -10,4 +10,6 @@ export declare const CodexCliSelected: Story;
10
10
  export declare const DemoAgent: Story;
11
11
  export declare const OverrideMode: Story;
12
12
  export declare const Disabled: Story;
13
+ export declare const SavingState: Story;
14
+ export declare const ParentDrivenSelection: Story;
13
15
  //# sourceMappingURL=AgentModelPicker.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentModelPicker.stories.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAevC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC"}
1
+ {"version":3,"file":"AgentModelPicker.stories.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAevC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAqBnC,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,KASnC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from 'react';
2
3
  import { fn } from '@storybook/test';
3
4
  import { AgentModelPicker } from './index.js';
4
5
  const meta = {
@@ -14,6 +15,16 @@ const meta = {
14
15
  },
15
16
  };
16
17
  export default meta;
18
+ function ParentDrivenSelectionDemo(props) {
19
+ const [selection, setSelection] = React.useState({
20
+ agentType: props.initialAgentType,
21
+ model: props.initialModel,
22
+ });
23
+ return (_jsx(AgentModelPicker, { ...props, agentType: selection.agentType, model: selection.model, onSave: async (agentType, model) => {
24
+ setSelection({ agentType, model });
25
+ return { ok: true };
26
+ } }));
27
+ }
17
28
  export const ClaudeCodeDefault = {
18
29
  args: {
19
30
  initialAgentType: 'claude-code',
@@ -64,3 +75,19 @@ export const Disabled = {
64
75
  disabled: true,
65
76
  },
66
77
  };
78
+ export const SavingState = {
79
+ args: {
80
+ initialAgentType: 'codex-cli',
81
+ initialModel: 'gpt-5.4',
82
+ mode: 'settings',
83
+ saving: true,
84
+ },
85
+ };
86
+ export const ParentDrivenSelection = {
87
+ render: (args) => (_jsx(ParentDrivenSelectionDemo, { ...args })),
88
+ args: {
89
+ initialAgentType: 'claude-code',
90
+ initialModel: 'claude-sonnet-4-6',
91
+ mode: 'settings',
92
+ },
93
+ };
@@ -1,11 +1,20 @@
1
1
  export interface AgentModelPickerProps {
2
2
  initialAgentType: string;
3
3
  initialModel: string;
4
+ agentType?: string;
5
+ model?: string;
4
6
  onAgentModelChange?: (agentType: string, model: string) => void;
7
+ onSave?: (agentType: string, model: string) => Promise<AgentModelPickerSaveResult | void>;
8
+ saveError?: string | null;
9
+ saving?: boolean;
5
10
  disabled?: boolean;
6
11
  className?: string;
7
12
  /** 'settings' persists to DB; 'override' only calls onAgentModelChange */
8
13
  mode: 'settings' | 'override';
9
14
  }
10
- export declare function AgentModelPicker({ initialAgentType, initialModel, onAgentModelChange, disabled, className, mode, }: AgentModelPickerProps): import("react/jsx-runtime").JSX.Element;
15
+ export interface AgentModelPickerSaveResult {
16
+ ok: boolean;
17
+ error?: string;
18
+ }
19
+ export declare function AgentModelPicker({ initialAgentType, initialModel, agentType: controlledAgentType, model: controlledModel, onAgentModelChange, onSave, saveError, saving, disabled, className, mode, }: AgentModelPickerProps): import("react/jsx-runtime").JSX.Element;
11
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/components/features/settings/AgentModelPicker/index.tsx"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;CAC/B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,QAAQ,EACR,SAAS,EACT,IAAI,GACL,EAAE,qBAAqB,2CAqNvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/components/features/settings/AgentModelPicker/index.tsx"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChE,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAAC;IAC1F,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;CAC/B;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,gBAAgB,EAChB,YAAY,EACZ,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,eAAe,EACtB,kBAAkB,EAClB,MAAM,EACN,SAAS,EACT,MAAM,EACN,QAAQ,EACR,SAAS,EACT,IAAI,GACL,EAAE,qBAAqB,2CAiOvB"}
@@ -9,13 +9,14 @@ import { getModelMeta } from '../../../../lib/model-metadata.js';
9
9
  import { Button } from '../../../ui/button.js';
10
10
  import { Popover, PopoverContent, PopoverTrigger } from '../../../ui/popover.js';
11
11
  import { cn } from '../../../../lib/utils.js';
12
- export function AgentModelPicker({ initialAgentType, initialModel, onAgentModelChange, disabled, className, mode, }) {
12
+ export function AgentModelPicker({ initialAgentType, initialModel, agentType: controlledAgentType, model: controlledModel, onAgentModelChange, onSave, saveError, saving, disabled, className, mode, }) {
13
13
  const [open, setOpen] = React.useState(false);
14
14
  const [groups, setGroups] = React.useState([]);
15
15
  const [loading, setLoading] = React.useState(true);
16
- const [agentType, setAgentType] = React.useState(initialAgentType);
17
- const [model, setModel] = React.useState(initialModel);
18
- const [error, setError] = React.useState(null);
16
+ const [agentType, setAgentType] = React.useState(controlledAgentType ?? initialAgentType);
17
+ const [model, setModel] = React.useState(controlledModel ?? initialModel);
18
+ const [internalSaving, setInternalSaving] = React.useState(false);
19
+ const [internalError, setInternalError] = React.useState(null);
19
20
  // 0 = agent list visible, 1 = model list visible
20
21
  const [level, setLevel] = React.useState(0);
21
22
  // Which agent's models to show (kept separate from level for animation)
@@ -25,9 +26,18 @@ export function AgentModelPicker({ initialAgentType, initialModel, onAgentModelC
25
26
  .then(setGroups)
26
27
  .finally(() => setLoading(false));
27
28
  }, []);
28
- // Reset drill-down when popover closes
29
29
  React.useEffect(() => {
30
- if (!open) {
30
+ setAgentType(controlledAgentType ?? initialAgentType);
31
+ }, [controlledAgentType, initialAgentType]);
32
+ React.useEffect(() => {
33
+ setModel(controlledModel ?? initialModel);
34
+ }, [controlledModel, initialModel]);
35
+ // Reset drill-down when popover transitions from open → closed (not on initial mount)
36
+ const prevOpenRef = React.useRef(open);
37
+ React.useEffect(() => {
38
+ const wasOpen = prevOpenRef.current;
39
+ prevOpenRef.current = open;
40
+ if (wasOpen && !open) {
31
41
  const t = setTimeout(() => {
32
42
  setLevel(0);
33
43
  setDrillAgent(null);
@@ -49,37 +59,35 @@ export function AgentModelPicker({ initialAgentType, initialModel, onAgentModelC
49
59
  setOpen(false);
50
60
  if (newAgentType === agentType && newModel === model)
51
61
  return;
62
+ setInternalError(null);
52
63
  if (mode === 'override') {
53
64
  setAgentType(newAgentType);
54
65
  setModel(newModel);
55
66
  onAgentModelChange?.(newAgentType, newModel);
56
67
  return;
57
68
  }
58
- // mode === 'settings' — optimistically update, then persist
59
- const prevAgent = agentType;
60
- const prevModel = model;
61
- setAgentType(newAgentType);
62
- setModel(newModel);
63
- onAgentModelChange?.(newAgentType, newModel);
64
- setError(null);
69
+ const persistSelection = onSave ??
70
+ (async (nextAgentType, nextModel) => updateAgentAndModel(nextAgentType, nextModel || null));
71
+ setInternalSaving(true);
65
72
  try {
66
- const result = await updateAgentAndModel(newAgentType, newModel || null);
67
- if (!result.ok) {
68
- // Revert on failure
69
- setAgentType(prevAgent);
70
- setModel(prevModel);
71
- onAgentModelChange?.(prevAgent, prevModel);
72
- setError(result.error ?? 'Failed to save');
73
+ const result = await persistSelection(newAgentType, newModel);
74
+ if (result && 'ok' in result && !result.ok) {
75
+ setInternalError(result.error ?? 'Failed to save');
76
+ return;
73
77
  }
78
+ setAgentType(newAgentType);
79
+ setModel(newModel);
80
+ onAgentModelChange?.(newAgentType, newModel);
74
81
  }
75
82
  catch {
76
- setAgentType(prevAgent);
77
- setModel(prevModel);
78
- onAgentModelChange?.(prevAgent, prevModel);
79
- setError('Failed to save');
83
+ setInternalError('Failed to save');
84
+ }
85
+ finally {
86
+ setInternalSaving(false);
80
87
  }
81
88
  };
82
- const isDisabled = (disabled ?? false) || loading;
89
+ const isDisabled = (disabled ?? false) || loading || (saving ?? false) || internalSaving;
90
+ const error = saveError ?? internalError;
83
91
  const AgentIcon = getAgentTypeIcon(agentType);
84
92
  const agentLabel = groups.find((g) => g.agentType === agentType)?.label ?? agentType;
85
93
  const modelName = model ? getModelMeta(model).displayName || model : null;