@shepai/cli 1.47.0 → 1.48.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 (161) hide show
  1. package/apis/json-schema/ApprovalGateDefaults.yaml +26 -0
  2. package/apis/json-schema/Feature.yaml +3 -0
  3. package/apis/json-schema/Repository.yaml +16 -0
  4. package/apis/json-schema/Settings.yaml +5 -0
  5. package/apis/json-schema/WorkflowConfig.yaml +4 -20
  6. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +17 -0
  7. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +11 -1
  9. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
  10. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +3 -1
  11. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  12. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +11 -4
  13. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts +19 -0
  14. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts.map +1 -0
  15. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.js +52 -0
  16. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/di/container.js +5 -0
  18. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  19. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +2 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts +2 -0
  21. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +10 -3
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +15 -7
  25. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +2 -0
  26. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  27. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +41 -0
  28. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +2 -1
  29. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
  30. package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +29 -4
  31. package/dist/src/presentation/cli/ui/messages.d.ts.map +1 -1
  32. package/dist/src/presentation/cli/ui/messages.js +1 -7
  33. package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts +7 -0
  34. package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts.map +1 -0
  35. package/dist/src/presentation/web/app/actions/get-merge-review-data.js +49 -0
  36. package/dist/src/presentation/web/app/page.d.ts.map +1 -1
  37. package/dist/src/presentation/web/app/page.js +1 -0
  38. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +8 -1
  40. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
  41. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
  42. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +22 -1
  43. package/dist/src/presentation/web/components/common/merge-review/index.d.ts +4 -0
  44. package/dist/src/presentation/web/components/common/merge-review/index.d.ts.map +1 -0
  45. package/dist/src/presentation/web/components/common/merge-review/index.js +2 -0
  46. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +75 -0
  47. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -0
  48. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.js +1 -0
  49. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts +3 -0
  50. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts.map +1 -0
  51. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.js +7 -0
  52. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts +3 -0
  53. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts.map +1 -0
  54. package/dist/src/presentation/web/components/common/merge-review/merge-review.js +36 -0
  55. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts +32 -0
  56. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts.map +1 -0
  57. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.js +165 -0
  58. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  59. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +55 -1
  60. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  61. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +15 -0
  62. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  63. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +37 -15
  64. package/dist/tsconfig.build.tsbuildinfo +1 -1
  65. package/package.json +1 -1
  66. package/web/.next/BUILD_ID +1 -1
  67. package/web/.next/build-manifest.json +2 -2
  68. package/web/.next/cache/.previewinfo +1 -1
  69. package/web/.next/cache/.rscinfo +1 -1
  70. package/web/.next/cache/.tsbuildinfo +1 -1
  71. package/web/.next/cache/config.json +3 -3
  72. package/web/.next/fallback-build-manifest.json +2 -2
  73. package/web/.next/prerender-manifest.json +3 -3
  74. package/web/.next/required-server-files.js +1 -1
  75. package/web/.next/required-server-files.json +1 -1
  76. package/web/.next/server/app/_global-error.html +2 -2
  77. package/web/.next/server/app/_global-error.rsc +1 -1
  78. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  80. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  81. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  82. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  83. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  84. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  85. package/web/.next/server/app/page/server-reference-manifest.json +39 -24
  86. package/web/.next/server/app/page.js +1 -1
  87. package/web/.next/server/app/page.js.nft.json +1 -1
  88. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  89. package/web/.next/server/app/version/page.js.nft.json +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]__19d52794._.js +9 -0
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js.map +1 -0
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  96. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/_3ac3601c._.js → server/chunks/ssr/_1fafa9db._.js} +2 -2
  97. package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +1 -0
  98. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  99. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  101. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  102. package/web/.next/server/pages/500.html +2 -2
  103. package/web/.next/server/server-reference-manifest.js +1 -1
  104. package/web/.next/server/server-reference-manifest.json +40 -25
  105. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  106. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  107. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  108. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  109. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  110. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  111. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  112. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  113. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  114. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  116. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  118. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +39 -24
  119. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
  120. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
  121. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  122. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  123. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  124. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  125. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
  126. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  127. package/web/.next/{server/chunks/ssr/_3ac3601c._.js → standalone/src/presentation/web/.next/server/chunks/ssr/_1fafa9db._.js} +2 -2
  128. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  129. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  130. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  131. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  132. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +40 -25
  133. package/web/.next/standalone/src/presentation/web/app/actions/get-merge-review-data.ts +64 -0
  134. package/web/.next/standalone/src/presentation/web/app/page.tsx +1 -0
  135. package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.stories.tsx +23 -1
  136. package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.tsx +6 -1
  137. package/web/.next/standalone/src/presentation/web/components/common/merge-review/index.ts +7 -0
  138. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +81 -0
  139. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-drawer.tsx +34 -0
  140. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.stories.tsx +240 -0
  141. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +252 -0
  142. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +82 -1
  143. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +15 -0
  144. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +47 -17
  145. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  146. package/web/.next/static/chunks/{9f8e71029fb04681.js → 0da7a9860fa6ae05.js} +2 -2
  147. package/web/.next/static/chunks/22f30ce91a3c79c1.js +1 -0
  148. package/web/.next/static/chunks/66378a6c055c4e67.js +10 -0
  149. package/web/.next/static/chunks/8668962d3e682263.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]__d6d75c22._.js +0 -9
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js.map +0 -1
  154. package/web/.next/server/chunks/ssr/_3ac3601c._.js.map +0 -1
  155. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +0 -9
  156. package/web/.next/static/chunks/779c99975c85389e.js +0 -10
  157. package/web/.next/static/chunks/83ff3b6bbee54bce.js +0 -1
  158. package/web/.next/static/chunks/b7b7abe79e05b229.css +0 -2
  159. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_buildManifest.js +0 -0
  160. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_clientMiddlewareManifest.json +0 -0
  161. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/ui/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;GAEG;AACH,eAAO,MAAM,QAAQ;IACnB;;;;OAIG;6BACa,MAAM,KAAG,IAAI;IAI7B;;;;;;OAMG;2BACW,MAAM,UAAU,KAAK,KAAG,IAAI;IAY1C;;;;OAIG;6BACa,MAAM,KAAG,IAAI;IAI7B;;;;OAIG;0BACU,MAAM,KAAG,IAAI;IAI1B;;;;OAIG;2BACW,MAAM,KAAG,IAAI;IAM3B;;OAEG;4BACU,IAAI;IAIjB;;OAEG;yBACS,MAAM,KAAG,IAAI;CAGjB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/ui/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH;;GAEG;AACH,eAAO,MAAM,QAAQ;IACnB;;;;OAIG;6BACa,MAAM,KAAG,IAAI;IAI7B;;;;;;OAMG;2BACW,MAAM,UAAU,KAAK,KAAG,IAAI;IAO1C;;;;OAIG;6BACa,MAAM,KAAG,IAAI;IAI7B;;;;OAIG;0BACU,MAAM,KAAG,IAAI;IAI1B;;;;OAIG;2BACW,MAAM,KAAG,IAAI;IAM3B;;OAEG;4BACU,IAAI;IAIjB;;OAEG;yBACS,MAAM,KAAG,IAAI;CAGjB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC"}
@@ -32,13 +32,7 @@ export const messages = {
32
32
  error: (text, error) => {
33
33
  console.error(colors.error(`${symbols.error} ${text}`));
34
34
  if (error) {
35
- // Show full stack in debug mode, otherwise just the message
36
- if (process.env.DEBUG) {
37
- console.error(colors.muted(error.stack ?? error.message));
38
- }
39
- else {
40
- console.error(colors.muted(error.message));
41
- }
35
+ console.error(colors.muted(error.stack ?? error.message));
42
36
  }
43
37
  },
44
38
  /**
@@ -0,0 +1,7 @@
1
+ import type { MergeReviewData } from '../../components/common/merge-review/merge-review-config.js';
2
+ type GetMergeReviewDataResult = MergeReviewData | {
3
+ error: string;
4
+ };
5
+ export declare function getMergeReviewData(featureId: string): Promise<GetMergeReviewDataResult>;
6
+ export {};
7
+ //# sourceMappingURL=get-merge-review-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-merge-review-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-merge-review-data.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,eAAe,EAEhB,MAAM,sDAAsD,CAAC;AAE9D,KAAK,wBAAwB,GAAG,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAkD7F"}
@@ -0,0 +1,49 @@
1
+ 'use server';
2
+ import { resolve } from '../../lib/server-container.js';
3
+ export async function getMergeReviewData(featureId) {
4
+ if (!featureId.trim()) {
5
+ return { error: 'Feature id is required' };
6
+ }
7
+ try {
8
+ const featureRepo = resolve('IFeatureRepository');
9
+ const feature = await featureRepo.findById(featureId);
10
+ if (!feature) {
11
+ return { error: 'Feature not found' };
12
+ }
13
+ const pr = feature.pr
14
+ ? {
15
+ url: feature.pr.url,
16
+ number: feature.pr.number,
17
+ status: feature.pr.status,
18
+ commitHash: feature.pr.commitHash,
19
+ ciStatus: feature.pr.ciStatus,
20
+ }
21
+ : undefined;
22
+ const branch = feature.branch ? { source: feature.branch, target: 'main' } : undefined;
23
+ // Load plan phases (best-effort)
24
+ let phases;
25
+ try {
26
+ const planUseCase = resolve('GetPlanArtifactUseCase');
27
+ const plan = await planUseCase.execute(featureId);
28
+ phases = plan.phases.map(({ id, name, description }) => ({ id, name, description }));
29
+ }
30
+ catch {
31
+ // Plan unavailable — not critical
32
+ }
33
+ if (!feature.worktreePath) {
34
+ return { pr, branch, phases, warning: pr ? undefined : 'No PR or diff data available' };
35
+ }
36
+ try {
37
+ const gitPrService = resolve('IGitPrService');
38
+ const diffSummary = await gitPrService.getPrDiffSummary(feature.worktreePath, 'main');
39
+ return { pr, branch, phases, diffSummary };
40
+ }
41
+ catch {
42
+ return { pr, branch, phases, warning: 'Diff statistics unavailable' };
43
+ }
44
+ }
45
+ catch (error) {
46
+ const message = error instanceof Error ? error.message : 'Failed to load merge review data';
47
+ return { error: message };
48
+ }
49
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAwHrC"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAsBvC,wBAA8B,QAAQ,qDAwHrC"}
@@ -21,6 +21,7 @@ const nodeToLifecyclePhase = {
21
21
  research: 'research',
22
22
  plan: 'implementation',
23
23
  implement: 'implementation',
24
+ merge: 'review',
24
25
  };
25
26
  export default async function HomePage() {
26
27
  const listFeatures = resolve('ListFeaturesUseCase');
@@ -1 +1 @@
1
- {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAmDnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CA4KA"}
1
+ {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwDnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CA4KA"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { Handle, Position } from '@xyflow/react';
4
- import { Settings, Plus, FileText, Wrench } from 'lucide-react';
4
+ import { Settings, Plus, FileText, Wrench, GitMerge } from 'lucide-react';
5
5
  import { cn } from '../../../lib/utils.js';
6
6
  import { featureNodeStateConfig, lifecycleDisplayLabels, lifecycleRunningVerbs, } from './feature-node-state-config.js';
7
7
  import { getAgentTypeIcon } from './agent-type-icons.js';
@@ -16,6 +16,8 @@ function getBadgeIcon(data) {
16
16
  return FileText;
17
17
  if (data.lifecycle === 'implementation')
18
18
  return Wrench;
19
+ if (data.lifecycle === 'review')
20
+ return GitMerge;
19
21
  }
20
22
  return config.icon;
21
23
  }
@@ -26,6 +28,9 @@ function getActionRequiredBadgeClasses(data) {
26
28
  if (data.lifecycle === 'implementation') {
27
29
  return { badgeClass: 'text-indigo-700', badgeBgClass: 'bg-indigo-50' };
28
30
  }
31
+ if (data.lifecycle === 'review') {
32
+ return { badgeClass: 'text-emerald-700', badgeBgClass: 'bg-emerald-50' };
33
+ }
29
34
  return null; // requirements stays amber (default)
30
35
  }
31
36
  function getBadgeText(data) {
@@ -44,6 +49,8 @@ function getBadgeText(data) {
44
49
  return 'Review Product Requirements';
45
50
  if (data.lifecycle === 'implementation')
46
51
  return 'Review Technical Planning';
52
+ if (data.lifecycle === 'review')
53
+ return 'Review Merge Request';
47
54
  return config.label;
48
55
  case 'error':
49
56
  return data.errorMessage ?? 'Something went wrong';
@@ -12,6 +12,7 @@ export declare const LongContent: Story;
12
12
  export declare const DoneWithRuntime: Story;
13
13
  export declare const BlockedByFeature: Story;
14
14
  export declare const Creating: Story;
15
+ export declare const MergeReviewActionRequired: Story;
15
16
  export declare const ErrorWithMessage: Story;
16
17
  export declare const Interactive: Story;
17
18
  //# sourceMappingURL=feature-node.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,6BAA6B,CAAC;AAiCrC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,eAAe,CAc/B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AA8EF,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAWF,eAAO,MAAM,aAAa,EAAE,KAqB3B,CAAC;AAsEF,eAAO,MAAM,aAAa,EAAE,KAQ3B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAW7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AA4EF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC"}
1
+ {"version":3,"file":"feature-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAKvD,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,6BAA6B,CAAC;AAiCrC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,eAAe,CAc/B,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvC,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAwFF,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAWF,eAAO,MAAM,aAAa,EAAE,KAqB3B,CAAC;AAsEF,eAAO,MAAM,aAAa,EAAE,KAQ3B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAW7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,KAUvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,KAW9B,CAAC;AA4EF,eAAO,MAAM,WAAW,EAAE,KAOzB,CAAC"}
@@ -69,6 +69,16 @@ const allStatesData = [
69
69
  repositoryPath: '/home/user/my-repo',
70
70
  branch: 'feat/data-pipeline',
71
71
  },
72
+ {
73
+ name: 'Merge Review',
74
+ description: 'PR ready for merge approval',
75
+ featureId: '#bi3',
76
+ lifecycle: 'review',
77
+ state: 'action-required',
78
+ progress: 90,
79
+ repositoryPath: '/home/user/my-repo',
80
+ branch: 'feat/merge-review',
81
+ },
72
82
  {
73
83
  name: 'Payment Gateway',
74
84
  description: 'Stripe integration for subscriptions',
@@ -104,7 +114,7 @@ const allStatesData = [
104
114
  },
105
115
  ];
106
116
  export const AllStates = {
107
- render: () => (_jsx("div", { className: "flex flex-wrap gap-6", children: allStatesData.map((data) => (_jsx(FeatureNodeCanvas, { style: { width: 500, height: 350 }, data: data }, data.state))) })),
117
+ render: () => (_jsx("div", { className: "flex flex-wrap gap-6", children: allStatesData.map((data) => (_jsx(FeatureNodeCanvas, { style: { width: 500, height: 350 }, data: data }, data.featureId))) })),
108
118
  };
109
119
  const allLifecycles = [
110
120
  'requirements',
@@ -245,6 +255,17 @@ export const Creating = {
245
255
  },
246
256
  render: (args) => _jsx(FeatureNodeCanvas, { data: args }),
247
257
  };
258
+ export const MergeReviewActionRequired = {
259
+ args: {
260
+ name: 'Merge Review',
261
+ description: 'PR ready for merge approval',
262
+ featureId: '#bi3',
263
+ lifecycle: 'review',
264
+ state: 'action-required',
265
+ progress: 90,
266
+ },
267
+ render: (args) => _jsx(FeatureNodeCanvas, { data: args }),
268
+ };
248
269
  export const ErrorWithMessage = {
249
270
  args: {
250
271
  name: 'Email Service',
@@ -0,0 +1,4 @@
1
+ export { MergeReview } from './merge-review.js';
2
+ export { MergeReviewDrawer } from './merge-review-drawer.js';
3
+ export type { MergeReviewProps, MergeReviewDrawerProps, MergeReviewData, } from './merge-review-config.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,GAChB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { MergeReview } from './merge-review.js';
2
+ export { MergeReviewDrawer } from './merge-review-drawer.js';
@@ -0,0 +1,75 @@
1
+ import type { PrStatus, CiStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
2
+ /** Diff summary statistics for the PR */
3
+ export interface MergeReviewDiffSummary {
4
+ filesChanged: number;
5
+ additions: number;
6
+ deletions: number;
7
+ commitCount: number;
8
+ }
9
+ /** PR metadata extracted from Feature.pr */
10
+ export interface MergeReviewPr {
11
+ url: string;
12
+ number: number;
13
+ status: PrStatus;
14
+ commitHash?: string;
15
+ ciStatus?: CiStatus;
16
+ }
17
+ /** A phase from the implementation plan */
18
+ export interface MergeReviewPhase {
19
+ id: string;
20
+ name: string;
21
+ description?: string;
22
+ }
23
+ /** Branch merge direction info */
24
+ export interface MergeReviewBranch {
25
+ /** Feature branch name */
26
+ source: string;
27
+ /** Target branch name (e.g. 'main') */
28
+ target: string;
29
+ }
30
+ /** Data returned by the getMergeReviewData server action */
31
+ export interface MergeReviewData {
32
+ /** PR metadata (omitted when the feature has no PR) */
33
+ pr?: MergeReviewPr;
34
+ /** Aggregate diff statistics (omitted when worktree is unavailable) */
35
+ diffSummary?: MergeReviewDiffSummary;
36
+ /** Implementation phases from plan.yaml */
37
+ phases?: MergeReviewPhase[];
38
+ /** Branch merge direction */
39
+ branch?: MergeReviewBranch;
40
+ /** Warning message when diff summary could not be retrieved */
41
+ warning?: string;
42
+ }
43
+ /** Props for the merge review content component */
44
+ export interface MergeReviewProps {
45
+ /** Merge review data from the server action */
46
+ data: MergeReviewData;
47
+ /** Approve merge callback */
48
+ onApprove: () => void;
49
+ /** Send refinement text to AI */
50
+ onRefine: (text: string) => void;
51
+ /** Controls disabled state during approval */
52
+ isProcessing?: boolean;
53
+ }
54
+ /** Props for the merge review drawer (shell wrapper) */
55
+ export interface MergeReviewDrawerProps extends MergeReviewProps {
56
+ /** Whether the drawer is open */
57
+ open: boolean;
58
+ /** Callback when drawer should close */
59
+ onClose: () => void;
60
+ /** Feature name shown in drawer header */
61
+ featureName: string;
62
+ /** Feature ID shown below the name */
63
+ featureId?: string;
64
+ /** Absolute path to the repository on disk */
65
+ repositoryPath?: string;
66
+ /** Git branch name — passed to ReviewDrawerShell for actions */
67
+ branch?: string;
68
+ /** Absolute path to the specs folder on disk */
69
+ specPath?: string;
70
+ /** Callback to delete the feature — shows delete button when provided */
71
+ onDelete?: (featureId: string) => void;
72
+ /** Whether a delete operation is in progress */
73
+ isDeleting?: boolean;
74
+ }
75
+ //# sourceMappingURL=merge-review-config.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,3 @@
1
+ import type { MergeReviewDrawerProps } from './merge-review-config.js';
2
+ export declare function MergeReviewDrawer({ open, onClose, featureName, featureId, repositoryPath, branch, specPath, onDelete, isDeleting, ...reviewProps }: MergeReviewDrawerProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=merge-review-drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-review-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review-drawer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,SAAS,EACT,cAAc,EACd,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,GAAG,WAAW,EACf,EAAE,sBAAsB,2CAgBxB"}
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { ReviewDrawerShell } from '../../common/review-drawer-shell/index.js';
4
+ import { MergeReview } from './merge-review.js';
5
+ export function MergeReviewDrawer({ open, onClose, featureName, featureId, repositoryPath, branch, specPath, onDelete, isDeleting, ...reviewProps }) {
6
+ return (_jsx(ReviewDrawerShell, { open: open, onClose: onClose, featureName: featureName, featureId: featureId, repositoryPath: repositoryPath, branch: branch, specPath: specPath, onDelete: onDelete, isDeleting: isDeleting, children: _jsx(MergeReview, { ...reviewProps }) }));
7
+ }
@@ -0,0 +1,3 @@
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;
3
+ //# sourceMappingURL=merge-review.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,36 @@
1
+ 'use client';
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';
5
+ import { CiStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
6
+ import { Badge } from '../../ui/badge.js';
7
+ import { Button } from '../../ui/button.js';
8
+ import { Input } from '../../ui/input.js';
9
+ function CiStatusBadge({ status }) {
10
+ switch (status) {
11
+ case CiStatus.Success:
12
+ return (_jsxs(Badge, { className: "border-transparent bg-green-50 text-green-700 hover:bg-green-50", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), "Passing"] }));
13
+ case CiStatus.Pending:
14
+ return (_jsxs(Badge, { className: "border-transparent bg-yellow-50 text-yellow-700 hover:bg-yellow-50", children: [_jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" }), "Pending"] }));
15
+ case CiStatus.Failure:
16
+ return (_jsxs(Badge, { className: "border-transparent bg-red-50 text-red-700 hover:bg-red-50", children: [_jsx(XCircle, { className: "mr-1 h-3.5 w-3.5" }), "Failing"] }));
17
+ }
18
+ }
19
+ function PhaseList({ phases }) {
20
+ 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
+ }
22
+ export function MergeReview({ data, onApprove, onRefine, isProcessing = false }) {
23
+ 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
+ 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
+ ? '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"] }) })] })] }));
36
+ }
@@ -0,0 +1,32 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { MergeReview } from './merge-review.js';
3
+ import { MergeReviewDrawer } from './merge-review-drawer.js';
4
+ declare const meta: Meta<typeof MergeReview>;
5
+ export default meta;
6
+ type Story = StoryObj<typeof MergeReview>;
7
+ /** Default — all data present with CI success. */
8
+ export declare const Default: Story;
9
+ /** CI status is Pending — shows yellow badge with spinner. */
10
+ export declare const CIPending: Story;
11
+ /** CI status is Failure — shows red badge. */
12
+ export declare const CIFailure: Story;
13
+ /** Diff summary unavailable — shows warning message. */
14
+ export declare const NoDiffSummary: Story;
15
+ /** CI status undefined — CI section omitted entirely. */
16
+ export declare const NoCIStatus: Story;
17
+ /** Processing state — approve button disabled with spinner. */
18
+ export declare const Processing: Story;
19
+ /** No PR — merge without a pull request, shows branch direction and diff summary. */
20
+ export declare const NoPrWithDiff: Story;
21
+ /** No PR and no diff — bare merge approval with branch info. */
22
+ export declare const NoPrNoDiff: Story;
23
+ /** With implementation phases shown. */
24
+ export declare const WithPhases: Story;
25
+ type DrawerStory = StoryObj<typeof MergeReviewDrawer>;
26
+ /** Merge review drawer with full data. */
27
+ export declare const InDrawer: DrawerStory;
28
+ /** Drawer with delete button visible. */
29
+ export declare const WithDeleteButton: DrawerStory;
30
+ /** Drawer without PR — direct merge with diff summary and branch info. */
31
+ export declare const InDrawerNoPr: DrawerStory;
32
+ //# sourceMappingURL=merge-review.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-review.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/merge-review/merge-review.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAsC1D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,WAAW,CAclC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,WAAW,CAAC,CAAC;AAE1C,kDAAkD;AAClD,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAEF,8CAA8C;AAC9C,eAAO,MAAM,SAAS,EAAE,KAQvB,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,KAS3B,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAQxB,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,UAAU,EAAE,KAMxB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,UAAU,EAAE,KAQxB,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,UAAU,EAAE,KAQxB,CAAC;AAIF,KAAK,WAAW,GAAG,QAAQ,CAAC,OAAO,iBAAiB,CAAC,CAAC;AA8BtD,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,EAAE,WAYtB,CAAC;AAEF,yCAAyC;AACzC,eAAO,MAAM,gBAAgB,EAAE,WAa9B,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,YAAY,EAAE,WAiB1B,CAAC"}
@@ -0,0 +1,165 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { fn } from '@storybook/test';
4
+ import { PrStatus, CiStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
5
+ import { MergeReview } from './merge-review.js';
6
+ import { MergeReviewDrawer } from './merge-review-drawer.js';
7
+ const fullPr = {
8
+ url: 'https://github.com/shep-ai/cli/pull/42',
9
+ number: 42,
10
+ status: PrStatus.Open,
11
+ commitHash: 'a1b2c3d4e5f6789',
12
+ ciStatus: CiStatus.Success,
13
+ };
14
+ const samplePhases = [
15
+ { id: 'phase-1', name: 'Foundation & Config', description: 'Set up types and server action' },
16
+ { id: 'phase-2', name: 'Component Implementation', description: 'Build the merge review UI' },
17
+ { id: 'phase-3', name: 'Integration & Wiring', description: 'Connect to control center' },
18
+ ];
19
+ const sampleBranch = { source: 'feat/add-auth', target: 'main' };
20
+ const fullData = {
21
+ pr: fullPr,
22
+ branch: sampleBranch,
23
+ phases: samplePhases,
24
+ diffSummary: {
25
+ filesChanged: 12,
26
+ additions: 340,
27
+ deletions: 85,
28
+ commitCount: 5,
29
+ },
30
+ };
31
+ const defaultActions = {
32
+ onApprove: fn().mockName('onApprove'),
33
+ onRefine: fn().mockName('onRefine'),
34
+ };
35
+ /* ─── Standalone MergeReview ─── */
36
+ const meta = {
37
+ title: 'Common/MergeReview',
38
+ component: MergeReview,
39
+ tags: ['autodocs'],
40
+ parameters: {
41
+ layout: 'fullscreen',
42
+ },
43
+ decorators: [
44
+ (Story) => (_jsx("div", { style: { height: '600px', width: '400px', border: '1px solid var(--color-border)' }, children: _jsx(Story, {}) })),
45
+ ],
46
+ };
47
+ export default meta;
48
+ /** Default — all data present with CI success. */
49
+ export const Default = {
50
+ args: {
51
+ data: fullData,
52
+ ...defaultActions,
53
+ },
54
+ };
55
+ /** CI status is Pending — shows yellow badge with spinner. */
56
+ export const CIPending = {
57
+ args: {
58
+ data: {
59
+ ...fullData,
60
+ pr: { ...fullPr, ciStatus: CiStatus.Pending },
61
+ },
62
+ ...defaultActions,
63
+ },
64
+ };
65
+ /** CI status is Failure — shows red badge. */
66
+ export const CIFailure = {
67
+ args: {
68
+ data: {
69
+ ...fullData,
70
+ pr: { ...fullPr, ciStatus: CiStatus.Failure },
71
+ },
72
+ ...defaultActions,
73
+ },
74
+ };
75
+ /** Diff summary unavailable — shows warning message. */
76
+ export const NoDiffSummary = {
77
+ args: {
78
+ data: {
79
+ pr: fullPr,
80
+ branch: sampleBranch,
81
+ warning: 'Diff statistics unavailable — worktree may have been removed',
82
+ },
83
+ ...defaultActions,
84
+ },
85
+ };
86
+ /** CI status undefined — CI section omitted entirely. */
87
+ export const NoCIStatus = {
88
+ args: {
89
+ data: {
90
+ ...fullData,
91
+ pr: { ...fullPr, ciStatus: undefined },
92
+ },
93
+ ...defaultActions,
94
+ },
95
+ };
96
+ /** Processing state — approve button disabled with spinner. */
97
+ export const Processing = {
98
+ args: {
99
+ data: fullData,
100
+ ...defaultActions,
101
+ isProcessing: true,
102
+ },
103
+ };
104
+ /** No PR — merge without a pull request, shows branch direction and diff summary. */
105
+ export const NoPrWithDiff = {
106
+ args: {
107
+ data: {
108
+ branch: { source: 'feat/fix-login', target: 'main' },
109
+ phases: samplePhases,
110
+ diffSummary: fullData.diffSummary,
111
+ },
112
+ ...defaultActions,
113
+ },
114
+ };
115
+ /** No PR and no diff — bare merge approval with branch info. */
116
+ export const NoPrNoDiff = {
117
+ args: {
118
+ data: {
119
+ branch: { source: 'feat/fix-login', target: 'main' },
120
+ warning: 'No PR or diff data available',
121
+ },
122
+ ...defaultActions,
123
+ },
124
+ };
125
+ /** With implementation phases shown. */
126
+ export const WithPhases = {
127
+ args: {
128
+ data: {
129
+ ...fullData,
130
+ phases: samplePhases,
131
+ },
132
+ ...defaultActions,
133
+ },
134
+ };
135
+ const drawerMeta = {
136
+ title: 'Common/MergeReviewDrawer',
137
+ component: MergeReviewDrawer,
138
+ tags: ['autodocs'],
139
+ parameters: {
140
+ layout: 'fullscreen',
141
+ },
142
+ };
143
+ function DrawerTemplate(props) {
144
+ const [open, setOpen] = useState(true);
145
+ 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(MergeReviewDrawer, { ...props, open: open, onClose: () => setOpen(false) })] }));
146
+ }
147
+ /** Merge review drawer with full data. */
148
+ export const InDrawer = {
149
+ ...drawerMeta,
150
+ render: () => (_jsx(DrawerTemplate, { featureName: "Add User Authentication", featureId: "FEAT-042", repositoryPath: "/home/user/projects/my-app", branch: "feat/add-auth", data: fullData, ...defaultActions })),
151
+ };
152
+ /** Drawer with delete button visible. */
153
+ export const WithDeleteButton = {
154
+ ...drawerMeta,
155
+ render: () => (_jsx(DrawerTemplate, { featureName: "Add User Authentication", featureId: "FEAT-042", repositoryPath: "/home/user/projects/my-app", branch: "feat/add-auth", data: fullData, ...defaultActions, onDelete: fn().mockName('onDelete') })),
156
+ };
157
+ /** Drawer without PR — direct merge with diff summary and branch info. */
158
+ export const InDrawerNoPr = {
159
+ ...drawerMeta,
160
+ render: () => (_jsx(DrawerTemplate, { featureName: "Fix Login Bug", featureId: "FEAT-099", repositoryPath: "/home/user/projects/my-app", branch: "feat/fix-login", data: {
161
+ branch: { source: 'feat/fix-login', target: 'main' },
162
+ phases: samplePhases,
163
+ diffSummary: fullData.diffSummary,
164
+ }, ...defaultActions, onDelete: fn().mockName('onDelete') })),
165
+ };
@@ -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;AAS1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAS5E,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,2CA2QzF"}
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"}