@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
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiGrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CA0NrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiGrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CA6NrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -246,6 +246,9 @@ export async function initializeContainer() {
246
246
  container.register('ApproveAgentRunUseCase', {
247
247
  useFactory: (c) => c.resolve(ApproveAgentRunUseCase),
248
248
  });
249
+ container.register('RejectAgentRunUseCase', {
250
+ useFactory: (c) => c.resolve(RejectAgentRunUseCase),
251
+ });
249
252
  container.register('GetFeatureArtifactUseCase', {
250
253
  useFactory: (c) => c.resolve(GetFeatureArtifactUseCase),
251
254
  });
@@ -176,7 +176,7 @@ export function createFeatureAgentGraph(depsOrExecutor, checkpointer) {
176
176
  graph
177
177
  .addNode('merge', createMergeNode(mergeNodeDeps))
178
178
  .addEdge('implement', 'merge')
179
- .addEdge('merge', END);
179
+ .addConditionalEdges('merge', routeReexecution('merge', END));
180
180
  }
181
181
  else {
182
182
  graph.addEdge('implement', END);
@@ -1 +1 @@
1
- {"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iEAAiE,CAAC;AAkBnG,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;CACpE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAoI7E"}
1
+ {"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iEAAiE,CAAC;AAqBnG,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;CACpE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAoK7E"}
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
11
11
  import { SdlcLifecycle, PrStatus } from '../../../../../domain/generated/output.js';
12
- import { createNodeLogger, shouldInterrupt, retryExecute, buildExecutorOptions, } from './node-helpers.js';
12
+ import { createNodeLogger, shouldInterrupt, retryExecute, buildExecutorOptions, getCompletedPhases, clearCompletedPhase, markPhaseComplete, } from './node-helpers.js';
13
13
  import { reportNodeStart } from '../heartbeat.js';
14
14
  import { recordPhaseStart, recordPhaseEnd, recordApprovalWaitStart, } from '../phase-timing-context.js';
15
15
  import { updateNodeLifecycle } from '../lifecycle-context.js';
@@ -27,6 +27,24 @@ export function createMergeNode(deps) {
27
27
  log.info('Starting merge flow');
28
28
  reportNodeStart('merge');
29
29
  await updateNodeLifecycle('merge');
30
+ // --- Rejection detection on resume (same pattern as executeNode) ---
31
+ // On resume after interrupt, check if merge was already completed.
32
+ // Rejection: clear phase, schedule re-execution via conditional edge.
33
+ // Approval: fall through to post-interrupt work (lifecycle update, optional merge/squash).
34
+ const completedPhases = getCompletedPhases(state.specDir);
35
+ const isResumeAfterInterrupt = completedPhases.includes('merge') && shouldInterrupt('merge', state.approvalGates);
36
+ if (isResumeAfterInterrupt && state._approvalAction === 'rejected') {
37
+ const feedback = state._rejectionFeedback ?? '(no feedback)';
38
+ log.info(`Merge rejected with feedback: "${feedback}" — scheduling re-execution`);
39
+ clearCompletedPhase(state.specDir, 'merge', log);
40
+ return {
41
+ currentNode: 'merge',
42
+ messages: [`[merge] Rejected — will re-execute`],
43
+ _approvalAction: null,
44
+ _rejectionFeedback: null,
45
+ _needsReexecution: true,
46
+ };
47
+ }
30
48
  const messages = [];
31
49
  const startTime = Date.now();
32
50
  // Record merge phase timing
@@ -39,46 +57,54 @@ export function createMergeNode(deps) {
39
57
  const branch = feature?.branch ?? `feat/${state.featureId}`;
40
58
  const baseBranch = await deps.getDefaultBranch(cwd);
41
59
  const options = buildExecutorOptions(state);
42
- // --- Check for git remote ---
43
- const remoteAvailable = await deps.hasRemote(cwd);
44
- if (!remoteAvailable) {
45
- log.info('No git remote configured — skipping push and PR, will merge locally');
46
- }
47
- // Override push/openPr when no remote is available
48
- const effectiveState = remoteAvailable ? state : { ...state, push: false, openPr: false };
49
- // --- Agent Call 1: Commit + Push + PR ---
50
- log.info('Agent call 1: commit + push + PR');
51
- const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch);
52
- const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
53
- logger: log,
54
- });
55
- // Parse structured data from agent output
56
- const commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
57
- messages.push(`[merge] Agent completed commit/push/PR operations`);
60
+ let commitHash = state.commitHash;
58
61
  let prUrl = state.prUrl;
59
62
  let prNumber = state.prNumber;
60
63
  const ciStatus = state.ciStatus;
61
- if (effectiveState.openPr) {
62
- const prResult = parsePrUrl(commitResult.result);
63
- if (prResult) {
64
- prUrl = prResult.url;
65
- prNumber = prResult.number;
66
- messages.push(`[merge] PR created: ${prUrl}`);
64
+ // --- Agent Call 1: Commit + Push + PR (skip on approval resume) ---
65
+ if (!isResumeAfterInterrupt) {
66
+ // --- Check for git remote ---
67
+ const remoteAvailable = await deps.hasRemote(cwd);
68
+ if (!remoteAvailable) {
69
+ log.info('No git remote configured — skipping push and PR, will merge locally');
67
70
  }
68
- }
69
- // --- Merge approval gate ---
70
- if (shouldInterrupt('merge', state.approvalGates)) {
71
- log.info('Interrupting for merge approval');
72
- await recordPhaseEnd(mergeTimingId, Date.now() - startTime);
73
- await recordApprovalWaitStart(mergeTimingId);
74
- const diffSummary = await deps.getDiffSummary(cwd, baseBranch);
75
- interrupt({
76
- node: 'merge',
77
- message: 'Merge approval required. Review the changes and approve to continue.',
78
- diffSummary,
79
- prUrl,
80
- prNumber,
71
+ // Override push/openPr when no remote is available
72
+ const effectiveState = remoteAvailable ? state : { ...state, push: false, openPr: false };
73
+ log.info('Agent call 1: commit + push + PR');
74
+ const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch);
75
+ const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
76
+ logger: log,
81
77
  });
78
+ // Parse structured data from agent output
79
+ commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
80
+ messages.push(`[merge] Agent completed commit/push/PR operations`);
81
+ if (effectiveState.openPr) {
82
+ const prResult = parsePrUrl(commitResult.result);
83
+ if (prResult) {
84
+ prUrl = prResult.url;
85
+ prNumber = prResult.number;
86
+ messages.push(`[merge] PR created: ${prUrl}`);
87
+ }
88
+ }
89
+ // --- Merge approval gate ---
90
+ if (shouldInterrupt('merge', state.approvalGates)) {
91
+ log.info('Interrupting for merge approval');
92
+ markPhaseComplete(state.specDir, 'merge', log);
93
+ await recordPhaseEnd(mergeTimingId, Date.now() - startTime);
94
+ await recordApprovalWaitStart(mergeTimingId);
95
+ const diffSummary = await deps.getDiffSummary(cwd, baseBranch);
96
+ interrupt({
97
+ node: 'merge',
98
+ message: 'Merge approval required. Review the changes and approve to continue.',
99
+ diffSummary,
100
+ prUrl,
101
+ prNumber,
102
+ });
103
+ }
104
+ }
105
+ else {
106
+ log.info('Merge approved — skipping commit/push/PR, continuing to post-merge');
107
+ messages.push(`[merge] Approved — continuing`);
82
108
  }
83
109
  // --- Agent Call 2: Merge (if enabled) ---
84
110
  let merged = false;
@@ -121,6 +147,9 @@ export function createMergeNode(deps) {
121
147
  prUrl,
122
148
  prNumber,
123
149
  ciStatus,
150
+ _approvalAction: null,
151
+ _rejectionFeedback: null,
152
+ _needsReexecution: false,
124
153
  };
125
154
  }
126
155
  catch (err) {
@@ -1,4 +1,5 @@
1
- export declare function approveFeature(featureId: string): Promise<{
1
+ import type { PrdApprovalPayload } from '../../../../../packages/core/src/domain/generated/output.js';
2
+ export declare function approveFeature(featureId: string, payload?: PrdApprovalPayload): Promise<{
2
3
  approved: boolean;
3
4
  error?: string;
4
5
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"approve-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/approve-feature.ts"],"names":[],"mappings":"AAMA,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BhD"}
1
+ {"version":3,"file":"approve-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/approve-feature.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAE/E,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6BhD"}
@@ -1,6 +1,6 @@
1
1
  'use server';
2
2
  import { resolve } from '../../lib/server-container.js';
3
- export async function approveFeature(featureId) {
3
+ export async function approveFeature(featureId, payload) {
4
4
  if (!featureId.trim()) {
5
5
  return { approved: false, error: 'Feature id is required' };
6
6
  }
@@ -14,7 +14,7 @@ export async function approveFeature(featureId) {
14
14
  return { approved: false, error: 'Feature has no agent run' };
15
15
  }
16
16
  const approveUseCase = resolve('ApproveAgentRunUseCase');
17
- const result = await approveUseCase.execute(feature.agentRunId);
17
+ const result = await approveUseCase.execute(feature.agentRunId, payload);
18
18
  if (!result.approved) {
19
19
  return { approved: false, error: result.reason };
20
20
  }
@@ -0,0 +1,7 @@
1
+ export declare function rejectFeature(featureId: string, feedback: string): Promise<{
2
+ rejected: boolean;
3
+ iteration?: number;
4
+ iterationWarning?: boolean;
5
+ error?: string;
6
+ }>;
7
+ //# sourceMappingURL=reject-feature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/reject-feature.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IACT,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAqCD"}
@@ -0,0 +1,34 @@
1
+ 'use server';
2
+ import { resolve } from '../../lib/server-container.js';
3
+ export async function rejectFeature(featureId, feedback) {
4
+ if (!featureId.trim()) {
5
+ return { rejected: false, error: 'Feature id is required' };
6
+ }
7
+ if (!feedback.trim()) {
8
+ return { rejected: false, error: 'Feedback is required' };
9
+ }
10
+ try {
11
+ const featureRepo = resolve('IFeatureRepository');
12
+ const feature = await featureRepo.findById(featureId);
13
+ if (!feature) {
14
+ return { rejected: false, error: 'Feature not found' };
15
+ }
16
+ if (!feature.agentRunId) {
17
+ return { rejected: false, error: 'Feature has no agent run' };
18
+ }
19
+ const rejectUseCase = resolve('RejectAgentRunUseCase');
20
+ const result = await rejectUseCase.execute(feature.agentRunId, feedback);
21
+ if (!result.rejected) {
22
+ return { rejected: false, error: result.reason };
23
+ }
24
+ return {
25
+ rejected: true,
26
+ iteration: result.iteration,
27
+ iterationWarning: result.iterationWarning,
28
+ };
29
+ }
30
+ catch (error) {
31
+ const message = error instanceof Error ? error.message : 'Failed to reject feature';
32
+ return { rejected: false, error: message };
33
+ }
34
+ }
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface DrawerActionBarProps {
3
+ /** Callback when user rejects with feedback (inline input or dialog) */
4
+ onReject?: (feedback: string) => void;
5
+ /** Callback when user approves */
6
+ onApprove: () => void;
7
+ /** Label for the approve button */
8
+ approveLabel: string;
9
+ /** Icon element for the approve button */
10
+ approveIcon?: ReactNode;
11
+ /** Placeholder for the inline revision input */
12
+ revisionPlaceholder?: string;
13
+ /** Title for the reject feedback dialog */
14
+ rejectDialogTitle?: string;
15
+ /** Whether an approval/processing operation is in flight */
16
+ isProcessing?: boolean;
17
+ /** Whether a reject operation is in flight */
18
+ isRejecting?: boolean;
19
+ /** Whether to show the reject button (defaults to true when onReject is provided) */
20
+ showRejectButton?: boolean;
21
+ /** Content rendered between revision input and action buttons (e.g. progress bar) */
22
+ children?: ReactNode;
23
+ }
24
+ //# sourceMappingURL=drawer-action-bar-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-action-bar-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,kCAAkC;IAClC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ import type { DrawerActionBarProps } from './drawer-action-bar-config.js';
2
+ export declare function DrawerActionBar({ onReject, onApprove, approveLabel, approveIcon, revisionPlaceholder, rejectDialogTitle, isProcessing, isRejecting, showRejectButton, children, }: DrawerActionBarProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=drawer-action-bar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-action-bar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EACjB,YAAoB,EACpB,WAAmB,EACnB,gBAAuB,EACvB,QAAQ,GACT,EAAE,oBAAoB,2CA2CtB"}
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { X } from 'lucide-react';
5
+ import { Button } from '../../ui/button.js';
6
+ import { RejectFeedbackDialog } from '../../common/reject-feedback-dialog/index.js';
7
+ import { DrawerRevisionInput } from '../../common/drawer-revision-input/index.js';
8
+ export function DrawerActionBar({ onReject, onApprove, approveLabel, approveIcon, revisionPlaceholder, rejectDialogTitle, isProcessing = false, isRejecting = false, showRejectButton = true, children, }) {
9
+ const [rejectDialogOpen, setRejectDialogOpen] = useState(false);
10
+ const disabled = isProcessing || isRejecting;
11
+ return (_jsxs("div", { className: "border-border shrink-0 border-t", children: [children, onReject ? (_jsx(DrawerRevisionInput, { onSubmit: onReject, placeholder: revisionPlaceholder, disabled: disabled || !onReject })) : null, _jsxs("div", { className: "flex items-center gap-2 px-4 pb-4", children: [onReject && showRejectButton ? (_jsxs(_Fragment, { children: [_jsxs(Button, { type: "button", variant: "outline", className: "text-destructive hover:text-destructive", disabled: disabled, onClick: () => setRejectDialogOpen(true), children: [_jsx(X, { className: "mr-1.5 h-4 w-4" }), "Reject"] }), _jsx(RejectFeedbackDialog, { open: rejectDialogOpen, onOpenChange: setRejectDialogOpen, onConfirm: onReject, isSubmitting: isRejecting, title: rejectDialogTitle })] })) : null, _jsxs(Button, { type: "button", className: "flex-1", disabled: disabled, onClick: onApprove, children: [approveIcon, approveLabel] })] })] }));
12
+ }
@@ -0,0 +1,3 @@
1
+ export { DrawerActionBar } from './drawer-action-bar.js';
2
+ export type { DrawerActionBarProps } from './drawer-action-bar-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/drawer-action-bar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1 @@
1
+ export { DrawerActionBar } from './drawer-action-bar.js';
@@ -0,0 +1,11 @@
1
+ export interface DrawerRevisionInputProps {
2
+ /** Callback when user submits revision text */
3
+ onSubmit: (text: string) => void;
4
+ /** Placeholder text for the input */
5
+ placeholder?: string;
6
+ /** Accessible label for the input */
7
+ ariaLabel?: string;
8
+ /** Whether the input should be disabled */
9
+ disabled?: boolean;
10
+ }
11
+ //# sourceMappingURL=drawer-revision-input-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-revision-input-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-revision-input/drawer-revision-input-config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,3 @@
1
+ import type { DrawerRevisionInputProps } from './drawer-revision-input-config.js';
2
+ export declare function DrawerRevisionInput({ onSubmit, placeholder, ariaLabel, disabled, }: DrawerRevisionInputProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=drawer-revision-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer-revision-input.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-revision-input/drawer-revision-input.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAE/E,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,WAAmC,EACnC,SAAS,EACT,QAAgB,GACjB,EAAE,wBAAwB,2CA2B1B"}
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { Send } from 'lucide-react';
5
+ import { Button } from '../../ui/button.js';
6
+ import { Input } from '../../ui/input.js';
7
+ export function DrawerRevisionInput({ onSubmit, placeholder = 'Ask AI to revise...', ariaLabel, disabled = false, }) {
8
+ const [chatInput, setChatInput] = useState('');
9
+ function handleSubmit(e) {
10
+ e.preventDefault();
11
+ const text = chatInput.trim();
12
+ if (!text)
13
+ return;
14
+ onSubmit(text);
15
+ setChatInput('');
16
+ }
17
+ return (_jsxs("form", { onSubmit: handleSubmit, className: "flex items-center gap-2 p-4", children: [_jsx(Input, { type: "text", placeholder: placeholder, "aria-label": ariaLabel ?? placeholder, disabled: disabled, value: chatInput, onChange: (e) => setChatInput(e.target.value), className: "flex-1" }), _jsx(Button, { type: "submit", variant: "secondary", size: "icon", "aria-label": "Send", disabled: disabled, children: _jsx(Send, {}) })] }));
18
+ }
@@ -0,0 +1,3 @@
1
+ export { DrawerRevisionInput } from './drawer-revision-input.js';
2
+ export type { DrawerRevisionInputProps } from './drawer-revision-input-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/drawer-revision-input/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -0,0 +1 @@
1
+ export { DrawerRevisionInput } from './drawer-revision-input.js';
@@ -46,10 +46,12 @@ export interface MergeReviewProps {
46
46
  data: MergeReviewData;
47
47
  /** Approve merge callback */
48
48
  onApprove: () => void;
49
- /** Send refinement text to AI */
50
- onRefine: (text: string) => void;
49
+ /** Reject merge callback — opens feedback dialog when provided; also used for inline text rejection */
50
+ onReject?: (feedback: string) => void;
51
51
  /** Controls disabled state during approval */
52
52
  isProcessing?: boolean;
53
+ /** Whether a reject operation is in flight */
54
+ isRejecting?: boolean;
53
55
  }
54
56
  /** Props for the merge review drawer (shell wrapper) */
55
57
  export interface MergeReviewDrawerProps extends MergeReviewProps {
@@ -1 +1 @@
1
- {"version":3,"file":"merge-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAE/E,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,uEAAuE;IACvE,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,6BAA6B;IAC7B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,iCAAiC;IACjC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wDAAwD;AACxD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,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,gEAAgE;IAChE,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":"merge-review-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAE/E,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,2CAA2C;AAC3C,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB;IAChC,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,EAAE,CAAC,EAAE,aAAa,CAAC;IACnB,uEAAuE;IACvE,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,2CAA2C;IAC3C,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,6BAA6B;IAC7B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,uGAAuG;IACvG,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wDAAwD;AACxD,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,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,gEAAgE;IAChE,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 { MergeReviewProps } from './merge-review-config.js';
2
- export declare function MergeReview({ data, onApprove, onRefine, isProcessing }: MergeReviewProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MergeReview({ data, onApprove, onReject, isProcessing, isRejecting, }: MergeReviewProps): import("react/jsx-runtime").JSX.Element;
3
3
  //# sourceMappingURL=merge-review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"merge-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AA0DhF,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAoB,EAAE,EAAE,gBAAgB,2CA4KhG"}
1
+ {"version":3,"file":"merge-review.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AA0DhF,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,GACpB,EAAE,gBAAgB,2CA4IlB"}
@@ -1,11 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import { CheckCircle2, ExternalLink, GitMerge, Loader2, XCircle, AlertTriangle, FileDiff, GitCommitHorizontal, GitBranch, ArrowRight, Layers, Send, } from 'lucide-react';
3
+ import { CheckCircle2, ExternalLink, GitMerge, Loader2, XCircle, AlertTriangle, FileDiff, GitCommitHorizontal, GitBranch, ArrowRight, Layers, } from 'lucide-react';
5
4
  import { CiStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
6
5
  import { Badge } from '../../ui/badge.js';
7
- import { Button } from '../../ui/button.js';
8
- import { Input } from '../../ui/input.js';
6
+ import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
9
7
  function CiStatusBadge({ status }) {
10
8
  switch (status) {
11
9
  case CiStatus.Success:
@@ -19,18 +17,9 @@ function CiStatusBadge({ status }) {
19
17
  function PhaseList({ phases }) {
20
18
  return (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "px-4 py-3", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(Layers, { className: "text-muted-foreground h-4 w-4" }), _jsx("span", { className: "text-foreground text-xs font-semibold", children: "Implementation Phases" })] }), _jsx("ol", { className: "space-y-2", children: phases.map((phase, i) => (_jsxs("li", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-emerald-100 text-[10px] font-bold text-emerald-700", children: i + 1 }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "text-foreground text-xs font-medium", children: phase.name }), phase.description ? (_jsx("p", { className: "text-muted-foreground mt-0.5 text-[11px] leading-relaxed", children: phase.description })) : null] })] }, phase.id))) })] }) }));
21
19
  }
22
- export function MergeReview({ data, onApprove, onRefine, isProcessing = false }) {
20
+ export function MergeReview({ data, onApprove, onReject, isProcessing = false, isRejecting = false, }) {
23
21
  const { pr, diffSummary, phases, branch, warning } = data;
24
- const [chatInput, setChatInput] = useState('');
25
- function handleSubmit(e) {
26
- e.preventDefault();
27
- const text = chatInput.trim();
28
- if (!text)
29
- return;
30
- onRefine(text);
31
- setChatInput('');
32
- }
33
22
  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-emerald-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h2", { className: "text-foreground text-sm font-bold", children: "Merge Review" }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs leading-relaxed", children: pr
34
23
  ? 'Review the pull request details and approve to merge.'
35
- : 'Review the changes and approve to merge.' })] })] }), branch ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(GitBranch, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx(Badge, { variant: "secondary", className: "font-mono text-[11px]", children: branch.source }), _jsx(ArrowRight, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0" }), _jsx(Badge, { variant: "outline", className: "font-mono text-[11px]", children: branch.target })] }) })) : null, pr ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "space-y-3 px-4 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("a", { href: pr.url, target: "_blank", rel: "noopener noreferrer", className: "text-primary flex items-center gap-1.5 text-sm font-semibold underline underline-offset-2", children: ["PR #", pr.number, _jsx(ExternalLink, { className: "h-3.5 w-3.5" })] }), _jsx(Badge, { variant: "outline", className: "text-xs", children: pr.status })] }), pr.ciStatus ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "CI Status" }), _jsx(CiStatusBadge, { status: pr.ciStatus })] })) : null, pr.commitHash ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "Commit" }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(GitCommitHorizontal, { className: "text-muted-foreground h-3.5 w-3.5" }), _jsx("code", { className: "bg-muted text-foreground rounded-md px-1.5 py-0.5 font-mono text-[11px]", children: pr.commitHash.slice(0, 7) })] })] })) : null] }) })) : null, diffSummary ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "px-4 py-3", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(FileDiff, { className: "text-muted-foreground h-4 w-4" }), _jsx("span", { className: "text-foreground text-xs font-semibold", children: "Changes" })] }), _jsxs("div", { className: "grid grid-cols-4 gap-3", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-foreground text-sm font-bold", children: diffSummary.filesChanged }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "files" })] }), _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "text-sm font-bold text-green-600", children: ["+", diffSummary.additions] }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "additions" })] }), _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "text-sm font-bold text-red-600", children: ["-", diffSummary.deletions] }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "deletions" })] }), _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-foreground text-sm font-bold", children: diffSummary.commitCount }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "commits" })] })] })] }) })) : warning ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(AlertTriangle, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx("span", { className: "text-muted-foreground text-xs", children: warning })] }) })) : null, phases && phases.length > 0 ? _jsx(PhaseList, { phases: phases }) : null] }), _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 before merging...", "aria-label": "Ask AI to revise before merging", 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, "aria-label": "Approve Merge", children: [isProcessing ? (_jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" })) : (_jsx(GitMerge, { className: "mr-1.5 h-4 w-4" })), "Approve Merge"] }) })] })] }));
24
+ : 'Review the changes and approve to merge.' })] })] }), branch ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(GitBranch, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx(Badge, { variant: "secondary", className: "font-mono text-[11px]", children: branch.source }), _jsx(ArrowRight, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0" }), _jsx(Badge, { variant: "outline", className: "font-mono text-[11px]", children: branch.target })] }) })) : null, pr ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "space-y-3 px-4 py-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("a", { href: pr.url, target: "_blank", rel: "noopener noreferrer", className: "text-primary flex items-center gap-1.5 text-sm font-semibold underline underline-offset-2", children: ["PR #", pr.number, _jsx(ExternalLink, { className: "h-3.5 w-3.5" })] }), _jsx(Badge, { variant: "outline", className: "text-xs", children: pr.status })] }), pr.ciStatus ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "CI Status" }), _jsx(CiStatusBadge, { status: pr.ciStatus })] })) : null, pr.commitHash ? (_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "Commit" }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(GitCommitHorizontal, { className: "text-muted-foreground h-3.5 w-3.5" }), _jsx("code", { className: "bg-muted text-foreground rounded-md px-1.5 py-0.5 font-mono text-[11px]", children: pr.commitHash.slice(0, 7) })] })] })) : null] }) })) : null, diffSummary ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "px-4 py-3", children: [_jsxs("div", { className: "mb-3 flex items-center gap-2", children: [_jsx(FileDiff, { className: "text-muted-foreground h-4 w-4" }), _jsx("span", { className: "text-foreground text-xs font-semibold", children: "Changes" })] }), _jsxs("div", { className: "grid grid-cols-4 gap-3", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-foreground text-sm font-bold", children: diffSummary.filesChanged }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "files" })] }), _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "text-sm font-bold text-green-600", children: ["+", diffSummary.additions] }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "additions" })] }), _jsxs("div", { className: "text-center", children: [_jsxs("div", { className: "text-sm font-bold text-red-600", children: ["-", diffSummary.deletions] }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "deletions" })] }), _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-foreground text-sm font-bold", children: diffSummary.commitCount }), _jsx("div", { className: "text-muted-foreground text-[10px]", children: "commits" })] })] })] }) })) : warning ? (_jsx("div", { className: "border-border rounded-lg border", children: _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(AlertTriangle, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx("span", { className: "text-muted-foreground text-xs", children: warning })] }) })) : null, phases && phases.length > 0 ? _jsx(PhaseList, { phases: phases }) : null] }), _jsx(DrawerActionBar, { onReject: onReject, onApprove: onApprove, approveLabel: "Approve Merge", approveIcon: isProcessing ? (_jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" })) : (_jsx(GitMerge, { className: "mr-1.5 h-4 w-4" })), revisionPlaceholder: "Ask AI to revise before merging...", rejectDialogTitle: "Reject Merge", isProcessing: isProcessing, isRejecting: isRejecting })] }));
36
25
  }
@@ -30,7 +30,7 @@ const fullData = {
30
30
  };
31
31
  const defaultActions = {
32
32
  onApprove: fn().mockName('onApprove'),
33
- onRefine: fn().mockName('onRefine'),
33
+ onReject: fn().mockName('onReject'),
34
34
  };
35
35
  /* ─── Standalone MergeReview ─── */
36
36
  const meta = {
@@ -7,12 +7,14 @@ export interface PrdQuestionnaireProps {
7
7
  selections: Record<string, string>;
8
8
  /** Selection change callback */
9
9
  onSelect: (questionId: string, optionId: string) => void;
10
- /** Chat refinement submit callback */
11
- onRefine: (text: string) => void;
12
10
  /** Finalize requirements callback */
13
11
  onApprove: (actionId: string) => void;
12
+ /** Reject requirements callback — opens feedback dialog when provided; also used for inline text rejection */
13
+ onReject?: (feedback: string) => void;
14
14
  /** Controls disabled/animated state during refinement */
15
15
  isProcessing?: boolean;
16
+ /** Whether a reject operation is in flight */
17
+ isRejecting?: boolean;
16
18
  /** Show the goal/context header (default: false) */
17
19
  showHeader?: boolean;
18
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"prd-questionnaire-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAE9C,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,oBAAoB,EAAE,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,IAAI,EAAE,oBAAoB,CAAC;IAC3B,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,gCAAgC;IAChC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,sCAAsC;IACtC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,qCAAqC;IACrC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,yDAAyD;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA4B,SAAQ,qBAAqB;IACxE,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,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":"prd-questionnaire-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,cAAc,EACd,oBAAoB,EACrB,MAAM,sCAAsC,CAAC;AAE9C,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,oBAAoB,EAAE,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,IAAI,EAAE,oBAAoB,CAAC;IAC3B,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,gCAAgC;IAChC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,qCAAqC;IACrC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,yDAAyD;IACzD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA4B,SAAQ,qBAAqB;IACxE,iCAAiC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,wCAAwC;IACxC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,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 { PrdQuestionnaireProps } from './prd-questionnaire-config.js';
2
- export declare function PrdQuestionnaire({ data, selections, onSelect, onRefine, onApprove, isProcessing, showHeader, }: PrdQuestionnaireProps): import("react/jsx-runtime").JSX.Element | null;
2
+ export declare function PrdQuestionnaire({ data, selections, onSelect, onApprove, onReject, isProcessing, isRejecting, showHeader, }: PrdQuestionnaireProps): import("react/jsx-runtime").JSX.Element | null;
3
3
  //# sourceMappingURL=prd-questionnaire.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAoB,EACpB,UAAkB,GACnB,EAAE,qBAAqB,kDAqMvB"}
1
+ {"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,EACnB,UAAkB,GACnB,EAAE,qBAAqB,kDAqKvB"}
@@ -1,15 +1,14 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Send, Check, ChevronLeft, ChevronRight } from 'lucide-react';
3
+ import { Check, ChevronLeft, ChevronRight } from 'lucide-react';
4
4
  import { useCallback, useMemo, useState } from 'react';
5
5
  import { cn } from '../../../lib/utils.js';
6
6
  import { Button } from '../../ui/button.js';
7
- import { Input } from '../../ui/input.js';
8
7
  import { Badge } from '../../ui/badge.js';
9
- export function PrdQuestionnaire({ data, selections, onSelect, onRefine, onApprove, isProcessing = false, showHeader = false, }) {
8
+ import { DrawerActionBar } from '../../common/drawer-action-bar/index.js';
9
+ export function PrdQuestionnaire({ data, selections, onSelect, onApprove, onReject, isProcessing = false, isRejecting = false, showHeader = false, }) {
10
10
  const { question, context, questions, finalAction } = data;
11
11
  const [currentStep, setCurrentStep] = useState(0);
12
- const [chatInput, setChatInput] = useState('');
13
12
  const total = questions.length;
14
13
  const isFirstStep = currentStep === 0;
15
14
  const isLastStep = currentStep === total - 1;
@@ -22,21 +21,13 @@ export function PrdQuestionnaire({ data, selections, onSelect, onRefine, onAppro
22
21
  setTimeout(() => setCurrentStep((s) => s + 1), 250);
23
22
  }
24
23
  }, [onSelect, isLastStep]);
25
- function handleSubmit(e) {
26
- e.preventDefault();
27
- const text = chatInput.trim();
28
- if (!text)
29
- return;
30
- onRefine(text);
31
- setChatInput('');
32
- }
33
24
  if (total === 0)
34
25
  return null;
35
26
  return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto p-4", children: [showHeader ? (_jsxs("div", { className: "border-border flex items-start gap-3 border-b pb-3", children: [_jsx("div", { className: "mt-1.5 h-2 w-2 shrink-0 rounded-full bg-amber-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-foreground mb-1.5 text-sm font-bold", children: question }), _jsx("p", { className: "text-muted-foreground text-xs leading-relaxed", children: context })] })] })) : null, _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx("label", { className: "text-foreground min-w-0 flex-1 text-sm font-semibold", children: currentQuestion.question }), _jsx("div", { className: "mt-1.5 flex shrink-0 gap-1", children: questions.map((q, idx) => (_jsx("button", { type: "button", "aria-label": `Go to question ${idx + 1}`, className: cn('h-1.5 rounded-full transition-all duration-200', idx === currentStep ? 'bg-primary w-4' : 'w-1.5', idx !== currentStep && selections[q.id] ? 'bg-primary/50' : '', idx !== currentStep && !selections[q.id] ? 'bg-muted-foreground/25' : ''), onClick: () => setCurrentStep(idx) }, q.id))) })] }), _jsx("div", { className: "space-y-2", children: currentQuestion.options.map((opt, optIdx) => {
36
27
  const selected = selections[currentQuestion.id] === opt.id;
37
28
  const letter = String.fromCharCode(65 + optIdx);
38
29
  return (_jsx("button", { type: "button", className: cn('border-border w-full rounded-md border px-3 py-3 text-left text-xs transition-all', 'hover:border-primary/70 hover:bg-primary/5 group', selected && 'border-primary bg-primary/5', opt.isNew && 'animate-option-highlight'), disabled: isProcessing, onClick: () => handleSelect(currentQuestion.id, opt.id), children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("span", { className: "text-muted-foreground mt-0.5 font-mono text-xs", children: [letter, "."] }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "mb-0.5 flex items-center gap-2", children: [_jsx("span", { className: "text-foreground text-xs font-semibold", children: opt.label }), opt.recommended ? (_jsx(Badge, { className: "px-1.5 py-0 text-[10px]", children: "AI Recommended" })) : null, opt.isNew ? (_jsx(Badge, { className: "border-transparent bg-emerald-600 px-1.5 py-0 text-[10px] text-white hover:bg-emerald-600/80", children: "New" })) : null] }), _jsx("div", { className: "text-muted-foreground text-xs leading-snug", children: opt.rationale })] })] }) }, opt.id));
39
- }) })] }), _jsxs("div", { className: "flex items-center justify-between pt-2", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isFirstStep || isProcessing, onClick: () => setCurrentStep((s) => s - 1), children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), "Previous"] }), isLastStep ? (_jsxs(Button, { type: "button", size: "sm", disabled: isProcessing || answeredCount < total, onClick: () => onApprove(finalAction.id), children: [_jsx(Check, { className: "mr-1 h-4 w-4" }), finalAction.label] })) : (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isProcessing, onClick: () => setCurrentStep((s) => s + 1), children: [selections[currentQuestion.id] ? 'Next' : 'Skip', _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] }))] })] }), _jsxs("div", { className: "border-border bg-background shrink-0 border-t", children: [_jsx("div", { className: cn('bg-muted h-1.5 overflow-hidden', (answeredCount > 0 && answeredCount < total) || isProcessing
40
- ? 'opacity-100'
41
- : 'opacity-0', 'transition-opacity duration-200'), "data-testid": "progress-bar-container", children: isProcessing ? (_jsx("div", { className: "bg-primary animate-indeterminate-progress h-full w-1/3" })) : (_jsx("div", { className: "bg-primary h-full transition-all duration-300", style: { width: `${total > 0 ? (answeredCount / total) * 100 : 0}%` }, "data-testid": "progress-bar" })) }), _jsxs("form", { onSubmit: handleSubmit, className: "flex items-center gap-2 p-4", children: [_jsx(Input, { type: "text", placeholder: "Ask AI to refine requirements...", "aria-label": "Ask AI to refine requirements", 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, {}) })] })] })] }));
30
+ }) })] }), _jsxs("div", { className: "flex items-center justify-between pt-2", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isFirstStep || isProcessing, onClick: () => setCurrentStep((s) => s - 1), children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), "Previous"] }), !isLastStep ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isProcessing, onClick: () => setCurrentStep((s) => s + 1), children: [selections[currentQuestion.id] ? 'Next' : 'Skip', _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })) : null] })] }), _jsx(DrawerActionBar, { onReject: onReject, onApprove: () => onApprove(finalAction.id), approveLabel: finalAction.label, approveIcon: _jsx(Check, { className: "mr-1.5 h-4 w-4" }), revisionPlaceholder: "Ask AI to refine requirements...", isProcessing: isProcessing, isRejecting: isRejecting, children: _jsx("div", { className: cn('bg-muted h-1.5 overflow-hidden', (answeredCount > 0 && answeredCount < total) || isProcessing
31
+ ? 'opacity-100'
32
+ : 'opacity-0', 'transition-opacity duration-200'), "data-testid": "progress-bar-container", children: isProcessing ? (_jsx("div", { className: "bg-primary animate-indeterminate-progress h-full w-1/3" })) : (_jsx("div", { className: "bg-primary h-full transition-all duration-300", style: { width: `${total > 0 ? (answeredCount / total) * 100 : 0}%` }, "data-testid": "progress-bar" })) }) })] }));
42
33
  }