@shepai/cli 1.46.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.
- package/apis/json-schema/ApprovalGateDefaults.yaml +26 -0
- package/apis/json-schema/Feature.yaml +3 -0
- package/apis/json-schema/Repository.yaml +16 -0
- package/apis/json-schema/Settings.yaml +5 -0
- package/apis/json-schema/WorkflowConfig.yaml +4 -20
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +17 -0
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +11 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +3 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +11 -4
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts +19 -0
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.js +52 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +5 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +10 -3
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +15 -7
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +41 -0
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +2 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +29 -4
- package/dist/src/presentation/cli/ui/messages.d.ts.map +1 -1
- package/dist/src/presentation/cli/ui/messages.js +1 -7
- package/dist/src/presentation/web/app/actions/create-feature.d.ts +2 -0
- package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/create-feature.js +3 -1
- package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts +7 -0
- package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-merge-review-data.js +49 -0
- package/dist/src/presentation/web/app/actions/get-workflow-defaults.d.ts +11 -0
- package/dist/src/presentation/web/app/actions/get-workflow-defaults.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-workflow-defaults.js +15 -0
- package/dist/src/presentation/web/app/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/page.js +1 -0
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +5 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +25 -7
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts +17 -0
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.js +54 -2
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +8 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +22 -1
- package/dist/src/presentation/web/components/common/merge-review/index.d.ts +4 -0
- package/dist/src/presentation/web/components/common/merge-review/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/index.js +2 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +75 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-config.js +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts +3 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.js +7 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts +3 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.js +36 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts +32 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.js +165 -0
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +66 -2
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +15 -0
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +37 -15
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +52 -22
- package/web/.next/server/app/page.js +1 -1
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/_3ac3601c._.js → server/chunks/ssr/_1fafa9db._.js} +2 -2
- package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +53 -23
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +52 -22
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/{server/chunks/ssr/_3ac3601c._.js → standalone/src/presentation/web/.next/server/chunks/ssr/_1fafa9db._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +53 -23
- package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +5 -1
- package/web/.next/standalone/src/presentation/web/app/actions/get-merge-review-data.ts +64 -0
- package/web/.next/standalone/src/presentation/web/app/actions/get-workflow-defaults.ts +28 -0
- package/web/.next/standalone/src/presentation/web/app/page.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.tsx +74 -1
- package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx +55 -5
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.stories.tsx +23 -1
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.tsx +6 -1
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/index.ts +7 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +81 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-drawer.tsx +34 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.stories.tsx +240 -0
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +252 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +96 -1
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +15 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +47 -17
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{9f8e71029fb04681.js → 0da7a9860fa6ae05.js} +2 -2
- package/web/.next/static/chunks/22f30ce91a3c79c1.js +1 -0
- package/web/.next/static/chunks/66378a6c055c4e67.js +10 -0
- package/web/.next/static/chunks/8668962d3e682263.css +2 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js +0 -9
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_3ac3601c._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js +0 -9
- package/web/.next/static/chunks/83ff3b6bbee54bce.js +0 -1
- package/web/.next/static/chunks/b7b7abe79e05b229.css +0 -2
- package/web/.next/static/chunks/ecf44fa8a155c854.js +0 -10
- /package/web/.next/static/{nM-uXIiW9k_0Z_GM_4bI4 → 1kZFDMQ0i-Y8dy1KkHlzv}/_buildManifest.js +0 -0
- /package/web/.next/static/{nM-uXIiW9k_0Z_GM_4bI4 → 1kZFDMQ0i-Y8dy1KkHlzv}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{nM-uXIiW9k_0Z_GM_4bI4 → 1kZFDMQ0i-Y8dy1KkHlzv}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { PrStatus, CiStatus } from '@shepai/core/domain/generated/output';
|
|
2
|
+
|
|
3
|
+
/** Diff summary statistics for the PR */
|
|
4
|
+
export interface MergeReviewDiffSummary {
|
|
5
|
+
filesChanged: number;
|
|
6
|
+
additions: number;
|
|
7
|
+
deletions: number;
|
|
8
|
+
commitCount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** PR metadata extracted from Feature.pr */
|
|
12
|
+
export interface MergeReviewPr {
|
|
13
|
+
url: string;
|
|
14
|
+
number: number;
|
|
15
|
+
status: PrStatus;
|
|
16
|
+
commitHash?: string;
|
|
17
|
+
ciStatus?: CiStatus;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A phase from the implementation plan */
|
|
21
|
+
export interface MergeReviewPhase {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Branch merge direction info */
|
|
28
|
+
export interface MergeReviewBranch {
|
|
29
|
+
/** Feature branch name */
|
|
30
|
+
source: string;
|
|
31
|
+
/** Target branch name (e.g. 'main') */
|
|
32
|
+
target: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Data returned by the getMergeReviewData server action */
|
|
36
|
+
export interface MergeReviewData {
|
|
37
|
+
/** PR metadata (omitted when the feature has no PR) */
|
|
38
|
+
pr?: MergeReviewPr;
|
|
39
|
+
/** Aggregate diff statistics (omitted when worktree is unavailable) */
|
|
40
|
+
diffSummary?: MergeReviewDiffSummary;
|
|
41
|
+
/** Implementation phases from plan.yaml */
|
|
42
|
+
phases?: MergeReviewPhase[];
|
|
43
|
+
/** Branch merge direction */
|
|
44
|
+
branch?: MergeReviewBranch;
|
|
45
|
+
/** Warning message when diff summary could not be retrieved */
|
|
46
|
+
warning?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Props for the merge review content component */
|
|
50
|
+
export interface MergeReviewProps {
|
|
51
|
+
/** Merge review data from the server action */
|
|
52
|
+
data: MergeReviewData;
|
|
53
|
+
/** Approve merge callback */
|
|
54
|
+
onApprove: () => void;
|
|
55
|
+
/** Send refinement text to AI */
|
|
56
|
+
onRefine: (text: string) => void;
|
|
57
|
+
/** Controls disabled state during approval */
|
|
58
|
+
isProcessing?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Props for the merge review drawer (shell wrapper) */
|
|
62
|
+
export interface MergeReviewDrawerProps extends MergeReviewProps {
|
|
63
|
+
/** Whether the drawer is open */
|
|
64
|
+
open: boolean;
|
|
65
|
+
/** Callback when drawer should close */
|
|
66
|
+
onClose: () => void;
|
|
67
|
+
/** Feature name shown in drawer header */
|
|
68
|
+
featureName: string;
|
|
69
|
+
/** Feature ID shown below the name */
|
|
70
|
+
featureId?: string;
|
|
71
|
+
/** Absolute path to the repository on disk */
|
|
72
|
+
repositoryPath?: string;
|
|
73
|
+
/** Git branch name — passed to ReviewDrawerShell for actions */
|
|
74
|
+
branch?: string;
|
|
75
|
+
/** Absolute path to the specs folder on disk */
|
|
76
|
+
specPath?: string;
|
|
77
|
+
/** Callback to delete the feature — shows delete button when provided */
|
|
78
|
+
onDelete?: (featureId: string) => void;
|
|
79
|
+
/** Whether a delete operation is in progress */
|
|
80
|
+
isDeleting?: boolean;
|
|
81
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReviewDrawerShell } from '@/components/common/review-drawer-shell';
|
|
4
|
+
import { MergeReview } from './merge-review';
|
|
5
|
+
import type { MergeReviewDrawerProps } from './merge-review-config';
|
|
6
|
+
|
|
7
|
+
export function MergeReviewDrawer({
|
|
8
|
+
open,
|
|
9
|
+
onClose,
|
|
10
|
+
featureName,
|
|
11
|
+
featureId,
|
|
12
|
+
repositoryPath,
|
|
13
|
+
branch,
|
|
14
|
+
specPath,
|
|
15
|
+
onDelete,
|
|
16
|
+
isDeleting,
|
|
17
|
+
...reviewProps
|
|
18
|
+
}: MergeReviewDrawerProps) {
|
|
19
|
+
return (
|
|
20
|
+
<ReviewDrawerShell
|
|
21
|
+
open={open}
|
|
22
|
+
onClose={onClose}
|
|
23
|
+
featureName={featureName}
|
|
24
|
+
featureId={featureId}
|
|
25
|
+
repositoryPath={repositoryPath}
|
|
26
|
+
branch={branch}
|
|
27
|
+
specPath={specPath}
|
|
28
|
+
onDelete={onDelete}
|
|
29
|
+
isDeleting={isDeleting}
|
|
30
|
+
>
|
|
31
|
+
<MergeReview {...reviewProps} />
|
|
32
|
+
</ReviewDrawerShell>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { fn } from '@storybook/test';
|
|
4
|
+
import { PrStatus, CiStatus } from '@shepai/core/domain/generated/output';
|
|
5
|
+
import { MergeReview } from './merge-review';
|
|
6
|
+
import { MergeReviewDrawer } from './merge-review-drawer';
|
|
7
|
+
import type { MergeReviewData } from './merge-review-config';
|
|
8
|
+
|
|
9
|
+
const fullPr = {
|
|
10
|
+
url: 'https://github.com/shep-ai/cli/pull/42',
|
|
11
|
+
number: 42,
|
|
12
|
+
status: PrStatus.Open,
|
|
13
|
+
commitHash: 'a1b2c3d4e5f6789',
|
|
14
|
+
ciStatus: CiStatus.Success,
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
const samplePhases = [
|
|
18
|
+
{ id: 'phase-1', name: 'Foundation & Config', description: 'Set up types and server action' },
|
|
19
|
+
{ id: 'phase-2', name: 'Component Implementation', description: 'Build the merge review UI' },
|
|
20
|
+
{ id: 'phase-3', name: 'Integration & Wiring', description: 'Connect to control center' },
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const sampleBranch = { source: 'feat/add-auth', target: 'main' };
|
|
24
|
+
|
|
25
|
+
const fullData: MergeReviewData = {
|
|
26
|
+
pr: fullPr,
|
|
27
|
+
branch: sampleBranch,
|
|
28
|
+
phases: samplePhases,
|
|
29
|
+
diffSummary: {
|
|
30
|
+
filesChanged: 12,
|
|
31
|
+
additions: 340,
|
|
32
|
+
deletions: 85,
|
|
33
|
+
commitCount: 5,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const defaultActions = {
|
|
38
|
+
onApprove: fn().mockName('onApprove'),
|
|
39
|
+
onRefine: fn().mockName('onRefine'),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/* ─── Standalone MergeReview ─── */
|
|
43
|
+
|
|
44
|
+
const meta: Meta<typeof MergeReview> = {
|
|
45
|
+
title: 'Common/MergeReview',
|
|
46
|
+
component: MergeReview,
|
|
47
|
+
tags: ['autodocs'],
|
|
48
|
+
parameters: {
|
|
49
|
+
layout: 'fullscreen',
|
|
50
|
+
},
|
|
51
|
+
decorators: [
|
|
52
|
+
(Story) => (
|
|
53
|
+
<div style={{ height: '600px', width: '400px', border: '1px solid var(--color-border)' }}>
|
|
54
|
+
<Story />
|
|
55
|
+
</div>
|
|
56
|
+
),
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default meta;
|
|
61
|
+
type Story = StoryObj<typeof MergeReview>;
|
|
62
|
+
|
|
63
|
+
/** Default — all data present with CI success. */
|
|
64
|
+
export const Default: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
data: fullData,
|
|
67
|
+
...defaultActions,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/** CI status is Pending — shows yellow badge with spinner. */
|
|
72
|
+
export const CIPending: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
data: {
|
|
75
|
+
...fullData,
|
|
76
|
+
pr: { ...fullPr, ciStatus: CiStatus.Pending },
|
|
77
|
+
},
|
|
78
|
+
...defaultActions,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** CI status is Failure — shows red badge. */
|
|
83
|
+
export const CIFailure: Story = {
|
|
84
|
+
args: {
|
|
85
|
+
data: {
|
|
86
|
+
...fullData,
|
|
87
|
+
pr: { ...fullPr, ciStatus: CiStatus.Failure },
|
|
88
|
+
},
|
|
89
|
+
...defaultActions,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/** Diff summary unavailable — shows warning message. */
|
|
94
|
+
export const NoDiffSummary: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
data: {
|
|
97
|
+
pr: fullPr,
|
|
98
|
+
branch: sampleBranch,
|
|
99
|
+
warning: 'Diff statistics unavailable — worktree may have been removed',
|
|
100
|
+
},
|
|
101
|
+
...defaultActions,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** CI status undefined — CI section omitted entirely. */
|
|
106
|
+
export const NoCIStatus: Story = {
|
|
107
|
+
args: {
|
|
108
|
+
data: {
|
|
109
|
+
...fullData,
|
|
110
|
+
pr: { ...fullPr, ciStatus: undefined },
|
|
111
|
+
},
|
|
112
|
+
...defaultActions,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/** Processing state — approve button disabled with spinner. */
|
|
117
|
+
export const Processing: Story = {
|
|
118
|
+
args: {
|
|
119
|
+
data: fullData,
|
|
120
|
+
...defaultActions,
|
|
121
|
+
isProcessing: true,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/** No PR — merge without a pull request, shows branch direction and diff summary. */
|
|
126
|
+
export const NoPrWithDiff: Story = {
|
|
127
|
+
args: {
|
|
128
|
+
data: {
|
|
129
|
+
branch: { source: 'feat/fix-login', target: 'main' },
|
|
130
|
+
phases: samplePhases,
|
|
131
|
+
diffSummary: fullData.diffSummary,
|
|
132
|
+
},
|
|
133
|
+
...defaultActions,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/** No PR and no diff — bare merge approval with branch info. */
|
|
138
|
+
export const NoPrNoDiff: Story = {
|
|
139
|
+
args: {
|
|
140
|
+
data: {
|
|
141
|
+
branch: { source: 'feat/fix-login', target: 'main' },
|
|
142
|
+
warning: 'No PR or diff data available',
|
|
143
|
+
},
|
|
144
|
+
...defaultActions,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/** With implementation phases shown. */
|
|
149
|
+
export const WithPhases: Story = {
|
|
150
|
+
args: {
|
|
151
|
+
data: {
|
|
152
|
+
...fullData,
|
|
153
|
+
phases: samplePhases,
|
|
154
|
+
},
|
|
155
|
+
...defaultActions,
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/* ─── Drawer Variant ─── */
|
|
160
|
+
|
|
161
|
+
type DrawerStory = StoryObj<typeof MergeReviewDrawer>;
|
|
162
|
+
|
|
163
|
+
const drawerMeta = {
|
|
164
|
+
title: 'Common/MergeReviewDrawer',
|
|
165
|
+
component: MergeReviewDrawer,
|
|
166
|
+
tags: ['autodocs'],
|
|
167
|
+
parameters: {
|
|
168
|
+
layout: 'fullscreen',
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
function DrawerTemplate(
|
|
173
|
+
props: Omit<React.ComponentProps<typeof MergeReviewDrawer>, 'open' | 'onClose'>
|
|
174
|
+
) {
|
|
175
|
+
const [open, setOpen] = useState(true);
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<div style={{ height: '100vh', background: '#f8fafc', padding: '2rem' }}>
|
|
179
|
+
<button
|
|
180
|
+
type="button"
|
|
181
|
+
onClick={() => setOpen(true)}
|
|
182
|
+
style={{ padding: '8px 16px', border: '1px solid #ccc', borderRadius: '6px' }}
|
|
183
|
+
>
|
|
184
|
+
Open Drawer
|
|
185
|
+
</button>
|
|
186
|
+
<MergeReviewDrawer {...props} open={open} onClose={() => setOpen(false)} />
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Merge review drawer with full data. */
|
|
192
|
+
export const InDrawer: DrawerStory = {
|
|
193
|
+
...drawerMeta,
|
|
194
|
+
render: () => (
|
|
195
|
+
<DrawerTemplate
|
|
196
|
+
featureName="Add User Authentication"
|
|
197
|
+
featureId="FEAT-042"
|
|
198
|
+
repositoryPath="/home/user/projects/my-app"
|
|
199
|
+
branch="feat/add-auth"
|
|
200
|
+
data={fullData}
|
|
201
|
+
{...defaultActions}
|
|
202
|
+
/>
|
|
203
|
+
),
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/** Drawer with delete button visible. */
|
|
207
|
+
export const WithDeleteButton: DrawerStory = {
|
|
208
|
+
...drawerMeta,
|
|
209
|
+
render: () => (
|
|
210
|
+
<DrawerTemplate
|
|
211
|
+
featureName="Add User Authentication"
|
|
212
|
+
featureId="FEAT-042"
|
|
213
|
+
repositoryPath="/home/user/projects/my-app"
|
|
214
|
+
branch="feat/add-auth"
|
|
215
|
+
data={fullData}
|
|
216
|
+
{...defaultActions}
|
|
217
|
+
onDelete={fn().mockName('onDelete')}
|
|
218
|
+
/>
|
|
219
|
+
),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/** Drawer without PR — direct merge with diff summary and branch info. */
|
|
223
|
+
export const InDrawerNoPr: DrawerStory = {
|
|
224
|
+
...drawerMeta,
|
|
225
|
+
render: () => (
|
|
226
|
+
<DrawerTemplate
|
|
227
|
+
featureName="Fix Login Bug"
|
|
228
|
+
featureId="FEAT-099"
|
|
229
|
+
repositoryPath="/home/user/projects/my-app"
|
|
230
|
+
branch="feat/fix-login"
|
|
231
|
+
data={{
|
|
232
|
+
branch: { source: 'feat/fix-login', target: 'main' },
|
|
233
|
+
phases: samplePhases,
|
|
234
|
+
diffSummary: fullData.diffSummary,
|
|
235
|
+
}}
|
|
236
|
+
{...defaultActions}
|
|
237
|
+
onDelete={fn().mockName('onDelete')}
|
|
238
|
+
/>
|
|
239
|
+
),
|
|
240
|
+
};
|
package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import {
|
|
5
|
+
CheckCircle2,
|
|
6
|
+
ExternalLink,
|
|
7
|
+
GitMerge,
|
|
8
|
+
Loader2,
|
|
9
|
+
XCircle,
|
|
10
|
+
AlertTriangle,
|
|
11
|
+
FileDiff,
|
|
12
|
+
GitCommitHorizontal,
|
|
13
|
+
GitBranch,
|
|
14
|
+
ArrowRight,
|
|
15
|
+
Layers,
|
|
16
|
+
Send,
|
|
17
|
+
} from 'lucide-react';
|
|
18
|
+
import { CiStatus } from '@shepai/core/domain/generated/output';
|
|
19
|
+
import { Badge } from '@/components/ui/badge';
|
|
20
|
+
import { Button } from '@/components/ui/button';
|
|
21
|
+
import { Input } from '@/components/ui/input';
|
|
22
|
+
import type { MergeReviewProps, MergeReviewPhase } from './merge-review-config';
|
|
23
|
+
|
|
24
|
+
function CiStatusBadge({ status }: { status: CiStatus }) {
|
|
25
|
+
switch (status) {
|
|
26
|
+
case CiStatus.Success:
|
|
27
|
+
return (
|
|
28
|
+
<Badge className="border-transparent bg-green-50 text-green-700 hover:bg-green-50">
|
|
29
|
+
<CheckCircle2 className="mr-1 h-3.5 w-3.5" />
|
|
30
|
+
Passing
|
|
31
|
+
</Badge>
|
|
32
|
+
);
|
|
33
|
+
case CiStatus.Pending:
|
|
34
|
+
return (
|
|
35
|
+
<Badge className="border-transparent bg-yellow-50 text-yellow-700 hover:bg-yellow-50">
|
|
36
|
+
<Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
|
|
37
|
+
Pending
|
|
38
|
+
</Badge>
|
|
39
|
+
);
|
|
40
|
+
case CiStatus.Failure:
|
|
41
|
+
return (
|
|
42
|
+
<Badge className="border-transparent bg-red-50 text-red-700 hover:bg-red-50">
|
|
43
|
+
<XCircle className="mr-1 h-3.5 w-3.5" />
|
|
44
|
+
Failing
|
|
45
|
+
</Badge>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function PhaseList({ phases }: { phases: MergeReviewPhase[] }) {
|
|
51
|
+
return (
|
|
52
|
+
<div className="border-border rounded-lg border">
|
|
53
|
+
<div className="px-4 py-3">
|
|
54
|
+
<div className="mb-3 flex items-center gap-2">
|
|
55
|
+
<Layers className="text-muted-foreground h-4 w-4" />
|
|
56
|
+
<span className="text-foreground text-xs font-semibold">Implementation Phases</span>
|
|
57
|
+
</div>
|
|
58
|
+
<ol className="space-y-2">
|
|
59
|
+
{phases.map((phase, i) => (
|
|
60
|
+
<li key={phase.id} className="flex items-start gap-2.5">
|
|
61
|
+
<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">
|
|
62
|
+
{i + 1}
|
|
63
|
+
</span>
|
|
64
|
+
<div className="min-w-0">
|
|
65
|
+
<span className="text-foreground text-xs font-medium">{phase.name}</span>
|
|
66
|
+
{phase.description ? (
|
|
67
|
+
<p className="text-muted-foreground mt-0.5 text-[11px] leading-relaxed">
|
|
68
|
+
{phase.description}
|
|
69
|
+
</p>
|
|
70
|
+
) : null}
|
|
71
|
+
</div>
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ol>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function MergeReview({ data, onApprove, onRefine, isProcessing = false }: MergeReviewProps) {
|
|
81
|
+
const { pr, diffSummary, phases, branch, warning } = data;
|
|
82
|
+
const [chatInput, setChatInput] = useState('');
|
|
83
|
+
|
|
84
|
+
function handleSubmit(e: { preventDefault: () => void }) {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
const text = chatInput.trim();
|
|
87
|
+
if (!text) return;
|
|
88
|
+
onRefine(text);
|
|
89
|
+
setChatInput('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div className="flex h-full flex-col">
|
|
94
|
+
<div className="flex-1 space-y-4 overflow-y-auto p-4">
|
|
95
|
+
{/* Header */}
|
|
96
|
+
<div className="flex items-start gap-3">
|
|
97
|
+
<div className="mt-1.5 h-2.5 w-2.5 shrink-0 rounded-full bg-emerald-500" />
|
|
98
|
+
<div className="flex-1">
|
|
99
|
+
<h2 className="text-foreground text-sm font-bold">Merge Review</h2>
|
|
100
|
+
<p className="text-muted-foreground mt-1 text-xs leading-relaxed">
|
|
101
|
+
{pr
|
|
102
|
+
? 'Review the pull request details and approve to merge.'
|
|
103
|
+
: 'Review the changes and approve to merge.'}
|
|
104
|
+
</p>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{/* Branch merge direction (GitHub-like) */}
|
|
109
|
+
{branch ? (
|
|
110
|
+
<div className="border-border rounded-lg border">
|
|
111
|
+
<div className="flex items-center gap-2 px-4 py-3">
|
|
112
|
+
<GitBranch className="text-muted-foreground h-4 w-4 shrink-0" />
|
|
113
|
+
<Badge variant="secondary" className="font-mono text-[11px]">
|
|
114
|
+
{branch.source}
|
|
115
|
+
</Badge>
|
|
116
|
+
<ArrowRight className="text-muted-foreground h-3.5 w-3.5 shrink-0" />
|
|
117
|
+
<Badge variant="outline" className="font-mono text-[11px]">
|
|
118
|
+
{branch.target}
|
|
119
|
+
</Badge>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
) : null}
|
|
123
|
+
|
|
124
|
+
{/* PR metadata card */}
|
|
125
|
+
{pr ? (
|
|
126
|
+
<div className="border-border rounded-lg border">
|
|
127
|
+
<div className="space-y-3 px-4 py-3">
|
|
128
|
+
{/* PR number + link */}
|
|
129
|
+
<div className="flex items-center justify-between">
|
|
130
|
+
<a
|
|
131
|
+
href={pr.url}
|
|
132
|
+
target="_blank"
|
|
133
|
+
rel="noopener noreferrer"
|
|
134
|
+
className="text-primary flex items-center gap-1.5 text-sm font-semibold underline underline-offset-2"
|
|
135
|
+
>
|
|
136
|
+
PR #{pr.number}
|
|
137
|
+
<ExternalLink className="h-3.5 w-3.5" />
|
|
138
|
+
</a>
|
|
139
|
+
<Badge variant="outline" className="text-xs">
|
|
140
|
+
{pr.status}
|
|
141
|
+
</Badge>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
{/* CI status */}
|
|
145
|
+
{pr.ciStatus ? (
|
|
146
|
+
<div className="flex items-center justify-between">
|
|
147
|
+
<span className="text-muted-foreground text-xs font-medium">CI Status</span>
|
|
148
|
+
<CiStatusBadge status={pr.ciStatus} />
|
|
149
|
+
</div>
|
|
150
|
+
) : null}
|
|
151
|
+
|
|
152
|
+
{/* Commit hash */}
|
|
153
|
+
{pr.commitHash ? (
|
|
154
|
+
<div className="flex items-center justify-between">
|
|
155
|
+
<span className="text-muted-foreground text-xs font-medium">Commit</span>
|
|
156
|
+
<div className="flex items-center gap-1.5">
|
|
157
|
+
<GitCommitHorizontal className="text-muted-foreground h-3.5 w-3.5" />
|
|
158
|
+
<code className="bg-muted text-foreground rounded-md px-1.5 py-0.5 font-mono text-[11px]">
|
|
159
|
+
{pr.commitHash.slice(0, 7)}
|
|
160
|
+
</code>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
) : null}
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
) : null}
|
|
167
|
+
|
|
168
|
+
{/* Diff summary */}
|
|
169
|
+
{diffSummary ? (
|
|
170
|
+
<div className="border-border rounded-lg border">
|
|
171
|
+
<div className="px-4 py-3">
|
|
172
|
+
<div className="mb-3 flex items-center gap-2">
|
|
173
|
+
<FileDiff className="text-muted-foreground h-4 w-4" />
|
|
174
|
+
<span className="text-foreground text-xs font-semibold">Changes</span>
|
|
175
|
+
</div>
|
|
176
|
+
<div className="grid grid-cols-4 gap-3">
|
|
177
|
+
<div className="text-center">
|
|
178
|
+
<div className="text-foreground text-sm font-bold">
|
|
179
|
+
{diffSummary.filesChanged}
|
|
180
|
+
</div>
|
|
181
|
+
<div className="text-muted-foreground text-[10px]">files</div>
|
|
182
|
+
</div>
|
|
183
|
+
<div className="text-center">
|
|
184
|
+
<div className="text-sm font-bold text-green-600">+{diffSummary.additions}</div>
|
|
185
|
+
<div className="text-muted-foreground text-[10px]">additions</div>
|
|
186
|
+
</div>
|
|
187
|
+
<div className="text-center">
|
|
188
|
+
<div className="text-sm font-bold text-red-600">-{diffSummary.deletions}</div>
|
|
189
|
+
<div className="text-muted-foreground text-[10px]">deletions</div>
|
|
190
|
+
</div>
|
|
191
|
+
<div className="text-center">
|
|
192
|
+
<div className="text-foreground text-sm font-bold">{diffSummary.commitCount}</div>
|
|
193
|
+
<div className="text-muted-foreground text-[10px]">commits</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
) : warning ? (
|
|
199
|
+
<div className="border-border rounded-lg border">
|
|
200
|
+
<div className="flex items-center gap-2 px-4 py-3">
|
|
201
|
+
<AlertTriangle className="text-muted-foreground h-4 w-4 shrink-0" />
|
|
202
|
+
<span className="text-muted-foreground text-xs">{warning}</span>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
) : null}
|
|
206
|
+
|
|
207
|
+
{/* Implementation phases */}
|
|
208
|
+
{phases && phases.length > 0 ? <PhaseList phases={phases} /> : null}
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
{/* Action bar: chat + approve */}
|
|
212
|
+
<div className="border-border shrink-0 border-t">
|
|
213
|
+
<form onSubmit={handleSubmit} className="flex items-center gap-2 p-4 pb-2">
|
|
214
|
+
<Input
|
|
215
|
+
type="text"
|
|
216
|
+
placeholder="Ask AI to revise before merging..."
|
|
217
|
+
aria-label="Ask AI to revise before merging"
|
|
218
|
+
disabled={isProcessing}
|
|
219
|
+
value={chatInput}
|
|
220
|
+
onChange={(e) => setChatInput(e.target.value)}
|
|
221
|
+
className="flex-1"
|
|
222
|
+
/>
|
|
223
|
+
<Button
|
|
224
|
+
type="submit"
|
|
225
|
+
variant="secondary"
|
|
226
|
+
size="icon"
|
|
227
|
+
aria-label="Send"
|
|
228
|
+
disabled={isProcessing}
|
|
229
|
+
>
|
|
230
|
+
<Send />
|
|
231
|
+
</Button>
|
|
232
|
+
</form>
|
|
233
|
+
<div className="px-4 pt-2 pb-4">
|
|
234
|
+
<Button
|
|
235
|
+
type="button"
|
|
236
|
+
className="w-full"
|
|
237
|
+
disabled={isProcessing}
|
|
238
|
+
onClick={onApprove}
|
|
239
|
+
aria-label="Approve Merge"
|
|
240
|
+
>
|
|
241
|
+
{isProcessing ? (
|
|
242
|
+
<Loader2 className="mr-1.5 h-4 w-4 animate-spin" />
|
|
243
|
+
) : (
|
|
244
|
+
<GitMerge className="mr-1.5 h-4 w-4" />
|
|
245
|
+
)}
|
|
246
|
+
Approve Merge
|
|
247
|
+
</Button>
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
}
|