@shepai/cli 1.48.0 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  2. package/dist/packages/core/src/infrastructure/di/container.js +3 -0
  3. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +1 -1
  4. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
  5. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +65 -36
  6. package/dist/src/presentation/web/app/actions/approve-feature.d.ts +2 -1
  7. package/dist/src/presentation/web/app/actions/approve-feature.d.ts.map +1 -1
  8. package/dist/src/presentation/web/app/actions/approve-feature.js +2 -2
  9. package/dist/src/presentation/web/app/actions/reject-feature.d.ts +7 -0
  10. package/dist/src/presentation/web/app/actions/reject-feature.d.ts.map +1 -0
  11. package/dist/src/presentation/web/app/actions/reject-feature.js +34 -0
  12. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts +24 -0
  13. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts.map +1 -0
  14. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.js +1 -0
  15. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts +3 -0
  16. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map +1 -0
  17. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +12 -0
  18. package/dist/src/presentation/web/components/common/drawer-action-bar/index.d.ts +3 -0
  19. package/dist/src/presentation/web/components/common/drawer-action-bar/index.d.ts.map +1 -0
  20. package/dist/src/presentation/web/components/common/drawer-action-bar/index.js +1 -0
  21. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.d.ts +11 -0
  22. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.d.ts.map +1 -0
  23. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.js +1 -0
  24. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.d.ts +3 -0
  25. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.d.ts.map +1 -0
  26. package/dist/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.js +18 -0
  27. package/dist/src/presentation/web/components/common/drawer-revision-input/index.d.ts +3 -0
  28. package/dist/src/presentation/web/components/common/drawer-revision-input/index.d.ts.map +1 -0
  29. package/dist/src/presentation/web/components/common/drawer-revision-input/index.js +1 -0
  30. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +4 -2
  31. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -1
  32. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts +1 -1
  33. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts.map +1 -1
  34. package/dist/src/presentation/web/components/common/merge-review/merge-review.js +4 -15
  35. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.js +1 -1
  36. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.d.ts +4 -2
  37. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.d.ts.map +1 -1
  38. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts +1 -1
  39. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map +1 -1
  40. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +6 -15
  41. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts +4 -0
  42. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts.map +1 -1
  43. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js +24 -3
  44. package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.d.ts +3 -0
  45. package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.d.ts.map +1 -0
  46. package/dist/src/presentation/web/components/common/reject-feedback-dialog/index.js +1 -0
  47. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.d.ts +9 -0
  48. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.d.ts.map +1 -0
  49. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.js +1 -0
  50. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.d.ts +3 -0
  51. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.d.ts.map +1 -0
  52. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.js +19 -0
  53. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.d.ts +14 -0
  54. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.d.ts.map +1 -0
  55. package/dist/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.js +46 -0
  56. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts +4 -2
  57. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts.map +1 -1
  58. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts +1 -1
  59. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts.map +1 -1
  60. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js +4 -14
  61. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts +4 -0
  62. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.d.ts.map +1 -1
  63. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.js +24 -6
  64. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  65. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +48 -33
  66. package/dist/tsconfig.build.tsbuildinfo +1 -1
  67. package/package.json +1 -1
  68. package/web/.next/BUILD_ID +1 -1
  69. package/web/.next/build-manifest.json +2 -2
  70. package/web/.next/cache/.previewinfo +1 -1
  71. package/web/.next/cache/.rscinfo +1 -1
  72. package/web/.next/cache/.tsbuildinfo +1 -1
  73. package/web/.next/cache/config.json +3 -3
  74. package/web/.next/fallback-build-manifest.json +2 -2
  75. package/web/.next/prerender-manifest.json +3 -3
  76. package/web/.next/required-server-files.js +1 -1
  77. package/web/.next/required-server-files.json +1 -1
  78. package/web/.next/server/app/_global-error.html +2 -2
  79. package/web/.next/server/app/_global-error.rsc +1 -1
  80. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  81. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  82. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  83. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  84. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  85. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  86. package/web/.next/server/app/page/server-reference-manifest.json +41 -26
  87. package/web/.next/server/app/page.js +2 -1
  88. package/web/.next/server/app/page.js.nft.json +1 -1
  89. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +9 -0
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js.map +1 -0
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js +3 -0
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js.map +1 -0
  98. package/web/.next/server/pages/500.html +2 -2
  99. package/web/.next/server/server-reference-manifest.js +1 -1
  100. package/web/.next/server/server-reference-manifest.json +42 -27
  101. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  102. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  103. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  104. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  105. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  106. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  107. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  108. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  109. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  110. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  111. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  112. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  113. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +41 -26
  114. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +2 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
  116. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  118. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  119. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  120. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +9 -0
  121. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d8fbe735._.js +3 -0
  122. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  123. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  124. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +42 -27
  125. package/web/.next/standalone/src/presentation/web/app/actions/approve-feature.ts +4 -2
  126. package/web/.next/standalone/src/presentation/web/app/actions/reject-feature.ts +52 -0
  127. package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.ts +24 -0
  128. package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx +64 -0
  129. package/web/.next/standalone/src/presentation/web/components/common/drawer-action-bar/index.ts +2 -0
  130. package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.ts +10 -0
  131. package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.tsx +41 -0
  132. package/web/.next/standalone/src/presentation/web/components/common/drawer-revision-input/index.ts +2 -0
  133. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +4 -2
  134. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.stories.tsx +1 -1
  135. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +24 -53
  136. package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.ts +4 -2
  137. package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx +36 -8
  138. package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx +16 -47
  139. package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/index.ts +2 -0
  140. package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.ts +8 -0
  141. package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.tsx +63 -0
  142. package/web/.next/standalone/src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.tsx +78 -0
  143. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts +4 -2
  144. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx +27 -6
  145. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx +14 -42
  146. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +94 -49
  147. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  148. package/web/.next/static/chunks/191ca1529c9868dd.js +10 -0
  149. package/web/.next/static/chunks/59b8bd47023e0249.css +2 -0
  150. package/web/.next/trace +1 -1
  151. package/web/.next/trace-build +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +0 -9
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js.map +0 -1
  154. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +0 -9
  155. package/web/.next/static/chunks/66378a6c055c4e67.js +0 -10
  156. package/web/.next/static/chunks/8668962d3e682263.css +0 -2
  157. /package/web/.next/static/{1kZFDMQ0i-Y8dy1KkHlzv → UT60KjU8SOYIjqeqo2WT-}/_buildManifest.js +0 -0
  158. /package/web/.next/static/{1kZFDMQ0i-Y8dy1KkHlzv → UT60KjU8SOYIjqeqo2WT-}/_clientMiddlewareManifest.json +0 -0
  159. /package/web/.next/static/{1kZFDMQ0i-Y8dy1KkHlzv → UT60KjU8SOYIjqeqo2WT-}/_ssgManifest.js +0 -0
@@ -23,4 +23,8 @@ export declare const InDrawerWithSelections: DrawerStory;
23
23
  export declare const WithDeleteButton: DrawerStory;
24
24
  /** Drawer with delete in progress (button disabled). */
25
25
  export declare const DeletingState: DrawerStory;
26
+ /** All answered with reject button visible on last step. */
27
+ export declare const WithRejectButton: Story;
28
+ /** Rejecting state — reject button disabled with spinner while reject action is in flight. */
29
+ export declare const RejectingState: Story;
26
30
  //# sourceMappingURL=prd-questionnaire.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAmKpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAmBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,sFAAsF;AACtF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,KAW5B,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,sBAAsB,CAAC,CAAC;AA2C3D,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,WAepC,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAW9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAY3B,CAAC"}
1
+ {"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAiKpE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAkBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,sFAAsF;AACtF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,KAW5B,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,sBAAsB,CAAC,CAAC;AA0C3D,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,WAepC,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAW9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAY3B,CAAC;AAaF,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAE,KAQ9B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
@@ -140,7 +140,7 @@ const mockFinalAction = {
140
140
  /* ─── Interactive wrapper for stories ─── */
141
141
  function InteractiveQuestionnaire({ selections: initialSelections = {}, ...props }) {
142
142
  const [selections, setSelections] = useState(initialSelections);
143
- return (_jsx(PrdQuestionnaire, { ...props, selections: selections, onSelect: (qId, optId) => setSelections((prev) => ({ ...prev, [qId]: optId })), onRefine: fn().mockName('onRefine'), onApprove: fn().mockName('onApprove') }));
143
+ return (_jsx(PrdQuestionnaire, { ...props, selections: selections, onSelect: (qId, optId) => setSelections((prev) => ({ ...prev, [qId]: optId })), onApprove: fn().mockName('onApprove') }));
144
144
  }
145
145
  /* ─── Standalone PrdQuestionnaire ─── */
146
146
  const meta = {
@@ -152,7 +152,6 @@ const meta = {
152
152
  },
153
153
  argTypes: {
154
154
  onSelect: { action: 'onSelect' },
155
- onRefine: { action: 'onRefine' },
156
155
  onApprove: { action: 'onApprove' },
157
156
  },
158
157
  decorators: [
@@ -239,7 +238,7 @@ const drawerMeta = {
239
238
  function DrawerTemplate({ selections: initialSelections = {}, ...props }) {
240
239
  const [open, setOpen] = useState(true);
241
240
  const [selections, setSelections] = useState(initialSelections);
242
- return (_jsxs("div", { style: { height: '100vh', background: '#f8fafc', padding: '2rem' }, children: [_jsx("button", { type: "button", onClick: () => setOpen(true), style: { padding: '8px 16px', border: '1px solid #ccc', borderRadius: '6px' }, children: "Open Drawer" }), _jsx(PrdQuestionnaireDrawer, { ...props, open: open, onClose: () => setOpen(false), selections: selections, onSelect: (qId, optId) => setSelections((prev) => ({ ...prev, [qId]: optId })), onRefine: fn().mockName('onRefine'), onApprove: fn().mockName('onApprove') })] }));
241
+ return (_jsxs("div", { style: { height: '100vh', background: '#f8fafc', padding: '2rem' }, children: [_jsx("button", { type: "button", onClick: () => setOpen(true), style: { padding: '8px 16px', border: '1px solid #ccc', borderRadius: '6px' }, children: "Open Drawer" }), _jsx(PrdQuestionnaireDrawer, { ...props, open: open, onClose: () => setOpen(false), selections: selections, onSelect: (qId, optId) => setSelections((prev) => ({ ...prev, [qId]: optId })), onApprove: fn().mockName('onApprove') })] }));
243
242
  }
244
243
  /** Drawer with stepper — navigate questions one at a time. */
245
244
  export const InDrawer = {
@@ -265,3 +264,25 @@ export const DeletingState = {
265
264
  ...drawerMeta,
266
265
  render: () => (_jsx(DrawerTemplate, { featureName: "User Authentication Flow", featureId: "FEAT-042", lifecycleLabel: "Requirements", data: mockData, onDelete: fn().mockName('onDelete'), isDeleting: true })),
267
266
  };
267
+ /* ─── Reject Variants ─── */
268
+ const allAnsweredSelections = {
269
+ problem: 'user_pain',
270
+ priority: 'p1',
271
+ success: 'adoption',
272
+ timeline: 'sprint',
273
+ scope: 'mvp',
274
+ stakeholders: 'end_users',
275
+ };
276
+ /** All answered with reject button visible on last step. */
277
+ export const WithRejectButton = {
278
+ render: () => (_jsx(InteractiveQuestionnaire, { data: mockData, selections: allAnsweredSelections, onReject: fn().mockName('onReject') })),
279
+ };
280
+ /** Rejecting state — reject button disabled with spinner while reject action is in flight. */
281
+ export const RejectingState = {
282
+ args: {
283
+ data: mockData,
284
+ selections: allAnsweredSelections,
285
+ onReject: fn().mockName('onReject'),
286
+ isRejecting: true,
287
+ },
288
+ };
@@ -0,0 +1,3 @@
1
+ export { RejectFeedbackDialog } from './reject-feedback-dialog.js';
2
+ export type { RejectFeedbackDialogProps } from './reject-feedback-dialog-config.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/reject-feedback-dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC"}
@@ -0,0 +1 @@
1
+ export { RejectFeedbackDialog } from './reject-feedback-dialog.js';
@@ -0,0 +1,9 @@
1
+ export interface RejectFeedbackDialogProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ onConfirm: (feedback: string) => void;
5
+ isSubmitting: boolean;
6
+ title?: string;
7
+ description?: string;
8
+ }
9
+ //# sourceMappingURL=reject-feedback-dialog-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject-feedback-dialog-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog-config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ import type { RejectFeedbackDialogProps } from './reject-feedback-dialog-config.js';
2
+ export declare function RejectFeedbackDialog({ open, onOpenChange, onConfirm, isSubmitting, title, description, }: RejectFeedbackDialogProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=reject-feedback-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject-feedback-dialog.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAMjF,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,KAAqB,EACrB,WAAiC,GAClC,EAAE,yBAAyB,2CAiD3B"}
@@ -0,0 +1,19 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { Loader2 } from 'lucide-react';
5
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '../../ui/alert-dialog.js';
6
+ import { Textarea } from '../../ui/textarea.js';
7
+ const DEFAULT_TITLE = 'Reject Requirements';
8
+ const DEFAULT_DESCRIPTION = 'Provide feedback for the agent to address in the next iteration. Feedback is required.';
9
+ export function RejectFeedbackDialog({ open, onOpenChange, onConfirm, isSubmitting, title = DEFAULT_TITLE, description = DEFAULT_DESCRIPTION, }) {
10
+ const [feedback, setFeedback] = useState('');
11
+ // Reset feedback when dialog opens
12
+ useEffect(() => {
13
+ if (open) {
14
+ setFeedback('');
15
+ }
16
+ }, [open]);
17
+ const isFeedbackEmpty = feedback.trim().length === 0;
18
+ return (_jsx(AlertDialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: title }), _jsx(AlertDialogDescription, { children: description })] }), _jsx(Textarea, { "aria-label": "Rejection feedback", placeholder: "Describe what needs to change...", value: feedback, onChange: (e) => setFeedback(e.target.value), disabled: isSubmitting, rows: 4 }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isSubmitting, onClick: () => onOpenChange(false), children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isFeedbackEmpty || isSubmitting, onClick: () => onConfirm(feedback.trim()), children: isSubmitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Rejecting\u2026"] })) : ('Confirm Reject') })] })] }) }));
19
+ }
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { RejectFeedbackDialog } from './reject-feedback-dialog.js';
3
+ declare const meta: Meta<typeof RejectFeedbackDialog>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof RejectFeedbackDialog>;
6
+ /** Default — dialog open with empty feedback; confirm button disabled. */
7
+ export declare const Default: Story;
8
+ /** With feedback entered — confirm button enabled. */
9
+ export declare const WithFeedback: Story;
10
+ /** Submitting state — spinner shown, buttons disabled. */
11
+ export declare const Submitting: Story;
12
+ /** Custom title and description for tech decisions context. */
13
+ export declare const CustomTitle: Story;
14
+ //# sourceMappingURL=reject-feedback-dialog.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject-feedback-dialog.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/reject-feedback-dialog/reject-feedback-dialog.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,oBAAoB,CAa3C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEnD,0EAA0E;AAC1E,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,sDAAsD;AACtD,eAAO,MAAM,YAAY,EAAE,KAoB1B,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,UAAU,EAAE,KAIxB,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { fn } from '@storybook/test';
2
+ import { RejectFeedbackDialog } from './reject-feedback-dialog.js';
3
+ const meta = {
4
+ title: 'Composed/RejectFeedbackDialog',
5
+ component: RejectFeedbackDialog,
6
+ tags: ['autodocs'],
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ args: {
11
+ open: true,
12
+ onOpenChange: fn().mockName('onOpenChange'),
13
+ onConfirm: fn().mockName('onConfirm'),
14
+ isSubmitting: false,
15
+ },
16
+ };
17
+ export default meta;
18
+ /** Default — dialog open with empty feedback; confirm button disabled. */
19
+ export const Default = {};
20
+ /** With feedback entered — confirm button enabled. */
21
+ export const WithFeedback = {
22
+ play: async ({ canvasElement }) => {
23
+ // Type feedback into the textarea to show enabled state
24
+ const textarea = canvasElement.ownerDocument.querySelector('textarea[aria-label="Rejection feedback"]');
25
+ if (textarea) {
26
+ // Simulate React-compatible input
27
+ const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value')?.set;
28
+ nativeInputValueSetter?.call(textarea, 'The requirements are missing error handling for edge cases. Please add validation for empty inputs.');
29
+ textarea.dispatchEvent(new Event('input', { bubbles: true }));
30
+ textarea.dispatchEvent(new Event('change', { bubbles: true }));
31
+ }
32
+ },
33
+ };
34
+ /** Submitting state — spinner shown, buttons disabled. */
35
+ export const Submitting = {
36
+ args: {
37
+ isSubmitting: true,
38
+ },
39
+ };
40
+ /** Custom title and description for tech decisions context. */
41
+ export const CustomTitle = {
42
+ args: {
43
+ title: 'Reject Plan',
44
+ description: 'Provide feedback on the technical plan for the agent to revise. Be specific about which decisions need changes.',
45
+ },
46
+ };
@@ -9,12 +9,14 @@ export interface TechDecisionsReviewData {
9
9
  export interface TechDecisionsReviewProps {
10
10
  /** Tech decisions data from the research artifact */
11
11
  data: TechDecisionsReviewData;
12
- /** Chat refinement callback — sends user feedback to the agent */
13
- onRefine: (text: string) => void;
14
12
  /** Approve plan callback */
15
13
  onApprove: () => void;
14
+ /** Reject plan callback — opens feedback dialog when provided; also used for inline text rejection */
15
+ onReject?: (feedback: string) => void;
16
16
  /** Controls disabled state during loading */
17
17
  isProcessing?: boolean;
18
+ /** Whether a reject operation is in flight */
19
+ isRejecting?: boolean;
18
20
  }
19
21
  export interface TechDecisionsDrawerProps extends TechDecisionsReviewProps {
20
22
  /** Whether the drawer is open */
@@ -1 +1 @@
1
- {"version":3,"file":"tech-decisions-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,kEAAkE;IAClE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
1
+ {"version":3,"file":"tech-decisions-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,qDAAqD;IACrD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,4BAA4B;IAC5B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,6CAA6C;IAC7C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,wBAAyB,SAAQ,wBAAwB;IACxE,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
@@ -1,3 +1,3 @@
1
1
  import type { TechDecisionsReviewProps } from './tech-decisions-review-config.js';
2
- export declare function TechDecisionsReview({ data, onRefine, onApprove, isProcessing, }: TechDecisionsReviewProps): import("react/jsx-runtime").JSX.Element | null;
2
+ export declare function TechDecisionsReview({ data, onApprove, onReject, isProcessing, isRejecting, }: TechDecisionsReviewProps): import("react/jsx-runtime").JSX.Element | null;
3
3
  //# sourceMappingURL=tech-decisions-review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,wBAAwB,EAAgB,MAAM,gCAAgC,CAAC;AAoG7F,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,YAAoB,GACrB,EAAE,wBAAwB,kDAyE1B"}
1
+ {"version":3,"file":"tech-decisions-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAgB,MAAM,gCAAgC,CAAC;AAoG7F,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,GACpB,EAAE,wBAAwB,kDA6C1B"}
@@ -2,10 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
4
  import Markdown from 'react-markdown';
5
- import { Check, ChevronRight, GitCompareArrows, Layers, Send } from 'lucide-react';
5
+ import { Check, ChevronRight, GitCompareArrows, Layers } from 'lucide-react';
6
6
  import { Badge } from '../../ui/badge.js';
7
- import { Button } from '../../ui/button.js';
8
- import { Input } from '../../ui/input.js';
7
+ import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
9
8
  const markdownComponents = {
10
9
  p: ({ children }) => (_jsx("p", { className: "text-muted-foreground mb-2 text-xs leading-relaxed last:mb-0", children: children })),
11
10
  strong: ({ children }) => _jsx("strong", { className: "text-foreground font-semibold", children: children }),
@@ -22,18 +21,9 @@ function DecisionCard({ decision, index }) {
22
21
  return (_jsxs("div", { className: "border-border rounded-lg border", children: [_jsxs("div", { className: "space-y-3 px-4 py-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold", children: index + 1 }), _jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "text-foreground text-sm leading-tight font-semibold", children: decision.title }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: decision.chosen })] })] }), 'decisionName' in decision &&
23
22
  decision.decisionName ? (_jsx(Badge, { variant: "secondary", className: "bg-primary/10 text-primary shrink-0", children: decision.decisionName })) : null] }), decision.rationale ? (_jsx(Markdown, { components: markdownComponents, children: decision.rationale })) : null] }), decision.rejected.length > 0 ? (_jsxs("div", { className: "border-border border-t", children: [_jsxs("button", { type: "button", onClick: () => setAlternativesOpen((prev) => !prev), className: "text-muted-foreground hover:bg-muted/50 flex w-full items-center gap-1.5 px-4 py-3 text-xs font-medium transition-colors", children: [_jsx(ChevronRight, { className: `h-3.5 w-3.5 transition-transform ${alternativesOpen ? 'rotate-90' : ''}` }), _jsx(Layers, { className: "h-3.5 w-3.5" }), "Other Options Considered (", decision.rejected.length, ")"] }), alternativesOpen ? (_jsx("div", { className: "space-y-1.5 px-4 pb-3", children: decision.rejected.map((alt) => (_jsx("div", { className: "bg-primary/5 rounded-md px-3 py-2", children: _jsx("span", { className: "text-foreground text-xs", children: alt }) }, alt))) })) : null] })) : null] }));
24
23
  }
25
- export function TechDecisionsReview({ data, onRefine, onApprove, isProcessing = false, }) {
24
+ export function TechDecisionsReview({ data, onApprove, onReject, isProcessing = false, isRejecting = false, }) {
26
25
  const { summary, decisions } = data;
27
- const [chatInput, setChatInput] = useState('');
28
- function handleSubmit(e) {
29
- e.preventDefault();
30
- const text = chatInput.trim();
31
- if (!text)
32
- return;
33
- onRefine(text);
34
- setChatInput('');
35
- }
36
26
  if (decisions.length === 0)
37
27
  return null;
38
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-bold", children: "Technical Implementation Plan Review" }), summary ? (_jsx("p", { className: "text-muted-foreground mt-1 text-xs leading-relaxed", children: summary })) : null] })] }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(GitCompareArrows, { className: "text-primary h-4 w-4" }), _jsx("h3", { className: "text-foreground text-sm font-bold", children: "Technical Decisions" })] }), decisions.map((decision, i) => (_jsx(DecisionCard, { decision: decision, index: i }, decision.title)))] }), _jsxs("div", { className: "border-border shrink-0 border-t", children: [_jsxs("form", { onSubmit: handleSubmit, className: "flex items-center gap-2 p-4 pb-2", children: [_jsx(Input, { type: "text", placeholder: "Ask AI to revise the plan...", "aria-label": "Ask AI to revise the plan", disabled: isProcessing, value: chatInput, onChange: (e) => setChatInput(e.target.value), className: "flex-1" }), _jsx(Button, { type: "submit", variant: "secondary", size: "icon", "aria-label": "Send", disabled: isProcessing, children: _jsx(Send, {}) })] }), _jsx("div", { className: "px-4 pt-2 pb-4", children: _jsxs(Button, { type: "button", className: "w-full", disabled: isProcessing, onClick: onApprove, children: [_jsx(Check, { className: "mr-1.5 h-4 w-4" }), "Approve Plan"] }) })] })] }));
28
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-bold", children: "Technical Implementation Plan Review" }), summary ? (_jsx("p", { className: "text-muted-foreground mt-1 text-xs leading-relaxed", children: summary })) : null] })] }), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsx(GitCompareArrows, { className: "text-primary h-4 w-4" }), _jsx("h3", { className: "text-foreground text-sm font-bold", children: "Technical Decisions" })] }), decisions.map((decision, i) => (_jsx(DecisionCard, { decision: decision, index: i }, decision.title)))] }), _jsx(DrawerActionBar, { onReject: onReject, onApprove: onApprove, approveLabel: "Approve Plan", approveIcon: _jsx(Check, { className: "mr-1.5 h-4 w-4" }), revisionPlaceholder: "Ask AI to revise the plan...", rejectDialogTitle: "Reject Plan", isProcessing: isProcessing, isRejecting: isRejecting })] }));
39
29
  }
@@ -19,4 +19,8 @@ export declare const InDrawer: DrawerStory;
19
19
  export declare const WithDeleteButton: DrawerStory;
20
20
  /** Drawer with delete in progress (button disabled). */
21
21
  export declare const DeletingState: DrawerStory;
22
+ /** With reject button visible next to approve. */
23
+ export declare const WithRejectButton: Story;
24
+ /** Rejecting state — reject button disabled while reject action is in flight. */
25
+ export declare const RejectingState: Story;
22
26
  //# sourceMappingURL=tech-decisions-review.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,oDAAoD;AACpD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,uBAAuB;AACvB,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA8BxD,uCAAuC;AACvC,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAY9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAa3B,CAAC"}
1
+ {"version":3,"file":"tech-decisions-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA0C9D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAc1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAElD,oDAAoD;AACpD,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,uBAAuB;AACvB,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AA8BxD,uCAAuC;AACvC,eAAO,MAAM,QAAQ,EAAE,WAWtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAY9B,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,WAa3B,CAAC;AAIF,kDAAkD;AAClD,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
@@ -51,7 +51,7 @@ export default meta;
51
51
  export const Default = {
52
52
  args: {
53
53
  data: mockData,
54
- onRefine: fn().mockName('onRefine'),
54
+ onReject: fn().mockName('onReject'),
55
55
  onApprove: fn().mockName('onApprove'),
56
56
  },
57
57
  };
@@ -67,7 +67,7 @@ export const Processing = {
67
67
  export const SingleDecision = {
68
68
  args: {
69
69
  data: { ...mockData, decisions: [mockData.decisions[0]] },
70
- onRefine: fn().mockName('onRefine'),
70
+ onReject: fn().mockName('onReject'),
71
71
  onApprove: fn().mockName('onApprove'),
72
72
  },
73
73
  };
@@ -75,7 +75,7 @@ export const SingleDecision = {
75
75
  export const NoTechnologies = {
76
76
  args: {
77
77
  data: { ...mockData, technologies: [] },
78
- onRefine: fn().mockName('onRefine'),
78
+ onReject: fn().mockName('onReject'),
79
79
  onApprove: fn().mockName('onApprove'),
80
80
  },
81
81
  };
@@ -94,15 +94,33 @@ function DrawerTemplate(props) {
94
94
  /** Drawer with tech decisions list. */
95
95
  export const InDrawer = {
96
96
  ...drawerMeta,
97
- render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onRefine: fn().mockName('onRefine'), onApprove: fn().mockName('onApprove') })),
97
+ render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject') })),
98
98
  };
99
99
  /** Drawer with delete button visible. */
100
100
  export const WithDeleteButton = {
101
101
  ...drawerMeta,
102
- render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onRefine: fn().mockName('onRefine'), onApprove: fn().mockName('onApprove'), onDelete: fn().mockName('onDelete') })),
102
+ render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject'), onDelete: fn().mockName('onDelete') })),
103
103
  };
104
104
  /** Drawer with delete in progress (button disabled). */
105
105
  export const DeletingState = {
106
106
  ...drawerMeta,
107
- render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onRefine: fn().mockName('onRefine'), onApprove: fn().mockName('onApprove'), onDelete: fn().mockName('onDelete'), isDeleting: true })),
107
+ render: () => (_jsx(DrawerTemplate, { featureName: "Agent Executor Abstraction", featureId: "FEAT-099", data: mockData, onApprove: fn().mockName('onApprove'), onReject: fn().mockName('onReject'), onDelete: fn().mockName('onDelete'), isDeleting: true })),
108
+ };
109
+ /* ─── Reject Variants ─── */
110
+ /** With reject button visible next to approve. */
111
+ export const WithRejectButton = {
112
+ args: {
113
+ data: mockData,
114
+ onApprove: fn().mockName('onApprove'),
115
+ onReject: fn().mockName('onReject'),
116
+ },
117
+ };
118
+ /** Rejecting state — reject button disabled while reject action is in flight. */
119
+ export const RejectingState = {
120
+ args: {
121
+ data: mockData,
122
+ onApprove: fn().mockName('onApprove'),
123
+ onReject: fn().mockName('onReject'),
124
+ isRejecting: true,
125
+ },
108
126
  };
@@ -1 +1 @@
1
- {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAW1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAU5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAyVzF"}
1
+ {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAgB1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAU5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAiYzF"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  import { useCallback, useEffect, useState } from 'react';
4
4
  import { toast } from 'sonner';
5
5
  import { approveFeature } from '../../../app/actions/approve-feature.js';
6
+ import { rejectFeature } from '../../../app/actions/reject-feature.js';
6
7
  import { getFeatureArtifact } from '../../../app/actions/get-feature-artifact.js';
7
8
  import { getResearchArtifact } from '../../../app/actions/get-research-artifact.js';
8
9
  import { getWorkflowDefaults } from '../../../app/actions/get-workflow-defaults.js';
@@ -28,9 +29,10 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
28
29
  }, []);
29
30
  // PRD questionnaire drawer state
30
31
  const [prdSelections, setPrdSelections] = useState({});
31
- const [isPrdProcessing, setIsPrdProcessing] = useState(false);
32
32
  const [questionnaireData, setQuestionnaireData] = useState(null);
33
33
  const [isLoadingQuestionnaire, setIsLoadingQuestionnaire] = useState(false);
34
+ // Reject state (shared by both drawers)
35
+ const [isRejecting, setIsRejecting] = useState(false);
34
36
  // Tech decisions drawer state
35
37
  const [techDecisionsData, setTechDecisionsData] = useState(null);
36
38
  const [isLoadingTechDecisions, setIsLoadingTechDecisions] = useState(false);
@@ -43,18 +45,26 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
43
45
  const handlePrdSelect = useCallback((questionId, optionId) => {
44
46
  setPrdSelections((prev) => ({ ...prev, [questionId]: optionId }));
45
47
  }, []);
46
- const handlePrdRefine = useCallback(async (_text) => {
47
- setIsPrdProcessing(true);
48
- // TODO: Call API to refine requirements
49
- // For now simulate a delay
50
- await new Promise((resolve) => setTimeout(resolve, 1500));
51
- setIsPrdProcessing(false);
52
- }, []);
53
48
  const handlePrdApprove = useCallback(async (_actionId) => {
54
49
  const featureId = selectedNode?.featureId;
55
50
  if (!featureId)
56
51
  return;
57
- const result = await approveFeature(featureId);
52
+ let payload;
53
+ if (questionnaireData) {
54
+ const changedSelections = [];
55
+ for (const [questionId, optionId] of Object.entries(prdSelections)) {
56
+ const question = questionnaireData.questions.find((q) => q.id === questionId);
57
+ const option = question?.options.find((o) => o.id === optionId);
58
+ if (question && option) {
59
+ changedSelections.push({
60
+ questionId: question.question,
61
+ selectedOption: option.label,
62
+ });
63
+ }
64
+ }
65
+ payload = { approved: true, changedSelections };
66
+ }
67
+ const result = await approveFeature(featureId, payload);
58
68
  if (!result.approved) {
59
69
  toast.error(result.error ?? 'Failed to approve requirements');
60
70
  return;
@@ -62,43 +72,48 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
62
72
  toast.success('Requirements approved — agent resuming');
63
73
  clearSelection();
64
74
  setPrdSelections({});
65
- }, [selectedNode?.featureId, clearSelection]);
66
- const handleTechDecisionsRefine = useCallback(async (_text) => {
67
- setIsLoadingTechDecisions(true);
68
- // TODO: Call API to refine tech decisions
69
- await new Promise((resolve) => setTimeout(resolve, 1500));
70
- setIsLoadingTechDecisions(false);
71
- }, []);
72
- const handleTechDecisionsApprove = useCallback(async () => {
75
+ }, [selectedNode?.featureId, clearSelection, questionnaireData, prdSelections]);
76
+ // Shared reject handler all drawers use the same rejectFeature flow
77
+ const handleReject = useCallback(async (feedback, label, onDone) => {
73
78
  const featureId = selectedNode?.featureId;
74
79
  if (!featureId)
75
80
  return;
76
- const result = await approveFeature(featureId);
77
- if (!result.approved) {
78
- toast.error(result.error ?? 'Failed to approve plan');
79
- return;
81
+ setIsRejecting(true);
82
+ try {
83
+ const result = await rejectFeature(featureId, feedback);
84
+ if (!result.rejected) {
85
+ toast.error(result.error ?? `Failed to reject ${label.toLowerCase()}`);
86
+ return;
87
+ }
88
+ toast.success(`${label} rejected — agent re-iterating (iteration ${result.iteration})`);
89
+ if (result.iterationWarning) {
90
+ toast.warning(`Iteration ${result.iteration} — consider approving or adjusting feedback to avoid excessive iterations`);
91
+ }
92
+ clearSelection();
93
+ onDone?.();
94
+ }
95
+ finally {
96
+ setIsRejecting(false);
80
97
  }
81
- toast.success('Plan approved — agent resuming');
82
- clearSelection();
83
98
  }, [selectedNode?.featureId, clearSelection]);
84
- const handleMergeApprove = useCallback(async () => {
99
+ const handlePrdReject = useCallback((feedback) => handleReject(feedback, 'Requirements', () => setPrdSelections({})), [handleReject]);
100
+ const handleTechDecisionsReject = useCallback((feedback) => handleReject(feedback, 'Plan'), [handleReject]);
101
+ const handleMergeReject = useCallback((feedback) => handleReject(feedback, 'Merge'), [handleReject]);
102
+ // Shared approve handler — tech decisions and merge use identical approve flows
103
+ const handleSimpleApprove = useCallback(async (label) => {
85
104
  const featureId = selectedNode?.featureId;
86
105
  if (!featureId)
87
106
  return;
88
107
  const result = await approveFeature(featureId);
89
108
  if (!result.approved) {
90
- toast.error(result.error ?? 'Failed to approve merge');
109
+ toast.error(result.error ?? `Failed to approve ${label.toLowerCase()}`);
91
110
  return;
92
111
  }
93
- toast.success('Merge approved — agent resuming');
112
+ toast.success(`${label} approved — agent resuming`);
94
113
  clearSelection();
95
114
  }, [selectedNode?.featureId, clearSelection]);
96
- const handleMergeRefine = useCallback(async (_text) => {
97
- setIsLoadingMergeReview(true);
98
- // TODO: Call API to refine merge
99
- await new Promise((resolve) => setTimeout(resolve, 1500));
100
- setIsLoadingMergeReview(false);
101
- }, []);
115
+ const handleTechDecisionsApprove = useCallback(() => handleSimpleApprove('Plan'), [handleSimpleApprove]);
116
+ const handleMergeApprove = useCallback(() => handleSimpleApprove('Merge'), [handleSimpleApprove]);
102
117
  // Fetch questionnaire data and reset selections when a different feature is selected
103
118
  const prdFeatureId = showPrdDrawer ? selectedNode?.featureId : null;
104
119
  useEffect(() => {
@@ -212,5 +227,5 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
212
227
  if (!hasRepositories) {
213
228
  return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
214
229
  }
215
- return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositoryDelete: handleDeleteRepository, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: showPrdDrawer || showTechDecisionsDrawer || showMergeReviewDrawer ? null : selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), questionnaireData ? (_jsx(PrdQuestionnaireDrawer, { open: showPrdDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureDescription: selectedNode?.description, featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: questionnaireData, selections: prdSelections, onSelect: handlePrdSelect, onRefine: handlePrdRefine, onApprove: handlePrdApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isPrdProcessing || isLoadingQuestionnaire })) : null, techDecisionsData ? (_jsx(TechDecisionsDrawer, { open: showTechDecisionsDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: techDecisionsData, onRefine: handleTechDecisionsRefine, onApprove: handleTechDecisionsApprove, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingTechDecisions })) : null, mergeReviewData ? (_jsx(MergeReviewDrawer, { open: showMergeReviewDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: mergeReviewData, onApprove: handleMergeApprove, onRefine: handleMergeRefine, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingMergeReview })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
230
+ return (_jsxs(_Fragment, { children: [_jsx(NotificationPermissionBanner, {}), _jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositoryDelete: handleDeleteRepository, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: showPrdDrawer || showTechDecisionsDrawer || showMergeReviewDrawer ? null : selectedNode, onClose: clearSelection, onDelete: handleDeleteFeature, isDeleting: isDeleting }), questionnaireData ? (_jsx(PrdQuestionnaireDrawer, { open: showPrdDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureDescription: selectedNode?.description, featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: questionnaireData, selections: prdSelections, onSelect: handlePrdSelect, onApprove: handlePrdApprove, onReject: handlePrdReject, isRejecting: isRejecting, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingQuestionnaire })) : null, techDecisionsData ? (_jsx(TechDecisionsDrawer, { open: showTechDecisionsDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: techDecisionsData, onApprove: handleTechDecisionsApprove, onReject: handleTechDecisionsReject, isRejecting: isRejecting, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingTechDecisions })) : null, mergeReviewData ? (_jsx(MergeReviewDrawer, { open: showMergeReviewDrawer, onClose: clearSelection, featureName: selectedNode?.name ?? '', featureId: selectedNode?.featureId, repositoryPath: selectedNode?.repositoryPath, branch: selectedNode?.branch, specPath: selectedNode?.specPath, data: mergeReviewData, onApprove: handleMergeApprove, onReject: handleMergeReject, isRejecting: isRejecting, onDelete: handleDeleteFeature, isDeleting: isDeleting, isProcessing: isLoadingMergeReview })) : null, _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, repositoryPath: pendingRepositoryPath, workflowDefaults: workflowDefaults })] }));
216
231
  }