@shepai/cli 1.45.0 → 1.47.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/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-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 +18 -10
- 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/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +15 -1
- package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/layout-with-dagre.js +3 -0
- 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/page/server-reference-manifest.json +37 -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/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]__249c74f6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +9 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js.map +1 -0
- 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 +38 -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/page/server-reference-manifest.json +37 -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/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]__249c74f6._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +9 -0
- 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 +38 -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-workflow-defaults.ts +28 -0
- package/web/.next/standalone/src/presentation/web/app/page.tsx +19 -10
- 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/features/control-center/control-center-inner.tsx +31 -0
- package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +3 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{22f9e39aab128063.js → 779c99975c85389e.js} +4 -4
- 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/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__4e8ca89c._.js +0 -9
- /package/web/.next/static/{z34pr57Jw4sBfoDeMMuGn → wQ3vPV9I8JeacVNyp4HFg}/_buildManifest.js +0 -0
- /package/web/.next/static/{z34pr57Jw4sBfoDeMMuGn → wQ3vPV9I8JeacVNyp4HFg}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{z34pr57Jw4sBfoDeMMuGn → wQ3vPV9I8JeacVNyp4HFg}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { getSettings } from '@shepai/core/infrastructure/services/settings.service';
|
|
4
|
+
|
|
5
|
+
export interface WorkflowDefaults {
|
|
6
|
+
approvalGates: {
|
|
7
|
+
allowPrd: boolean;
|
|
8
|
+
allowPlan: boolean;
|
|
9
|
+
allowMerge: boolean;
|
|
10
|
+
};
|
|
11
|
+
push: boolean;
|
|
12
|
+
openPr: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function getWorkflowDefaults(): Promise<WorkflowDefaults> {
|
|
16
|
+
const settings = getSettings();
|
|
17
|
+
const { workflow } = settings;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
approvalGates: {
|
|
21
|
+
allowPrd: workflow.approvalGateDefaults.allowPrd,
|
|
22
|
+
allowPlan: workflow.approvalGateDefaults.allowPlan,
|
|
23
|
+
allowMerge: workflow.approvalGateDefaults.allowMerge,
|
|
24
|
+
},
|
|
25
|
+
push: workflow.approvalGateDefaults.pushOnImplementationComplete,
|
|
26
|
+
openPr: workflow.openPrOnImplementationComplete,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -119,19 +119,28 @@ export default async function HomePage() {
|
|
|
119
119
|
nodesep: 15,
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
// Position "+ Add Repository"
|
|
123
|
-
//
|
|
122
|
+
// Position "+ Add Repository" below the last repo node (no-features case) or
|
|
123
|
+
// vertically centered with a bottom feature node (features case).
|
|
124
124
|
const repoNodes = laid.nodes.filter((n) => n.type === 'repositoryNode');
|
|
125
125
|
const featureNodes = laid.nodes.filter((n) => n.type === 'featureNode');
|
|
126
|
-
const sortedFeatures = [...featureNodes].sort((a, b) => a.position.y - b.position.y);
|
|
127
|
-
// Pick the feature node just below center (one past the midpoint index)
|
|
128
|
-
const centerIdx = Math.floor(sortedFeatures.length / 2);
|
|
129
|
-
const targetFeature = sortedFeatures[centerIdx + 1] ?? sortedFeatures[sortedFeatures.length - 1];
|
|
130
126
|
const repoX = repoNodes[0]?.position.x ?? 0;
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
127
|
+
|
|
128
|
+
let addRepoPosition: { x: number; y: number };
|
|
129
|
+
if (featureNodes.length > 0) {
|
|
130
|
+
// Mirror how dagre centers repo nodes with their connected features
|
|
131
|
+
const sortedFeatures = [...featureNodes].sort((a, b) => a.position.y - b.position.y);
|
|
132
|
+
const centerIdx = Math.floor(sortedFeatures.length / 2);
|
|
133
|
+
const targetFeature =
|
|
134
|
+
sortedFeatures[centerIdx + 1] ?? sortedFeatures[sortedFeatures.length - 1];
|
|
135
|
+
// Center the add-repo node (h=50) with the target feature node (h=140)
|
|
136
|
+
addRepoPosition = { x: repoX, y: targetFeature.position.y + 70 - 25 };
|
|
137
|
+
} else {
|
|
138
|
+
// No features — place below the bottom-most repo node with a gap
|
|
139
|
+
const lastRepoY = repoNodes.length > 0 ? Math.max(...repoNodes.map((n) => n.position.y)) : 0;
|
|
140
|
+
const repoHeight = 50;
|
|
141
|
+
const gap = 200;
|
|
142
|
+
addRepoPosition = { x: repoX, y: lastRepoY + repoHeight + gap };
|
|
143
|
+
}
|
|
135
144
|
|
|
136
145
|
laid.nodes.push({
|
|
137
146
|
id: 'add-repository',
|
|
@@ -3,6 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
3
3
|
import { within, userEvent, fn } from '@storybook/test';
|
|
4
4
|
import { FeatureCreateDrawer } from './feature-create-drawer';
|
|
5
5
|
import type { FeatureCreatePayload } from './feature-create-drawer';
|
|
6
|
+
import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
|
|
6
7
|
import { Button } from '@/components/ui/button';
|
|
7
8
|
|
|
8
9
|
/* ---------------------------------------------------------------------------
|
|
@@ -81,7 +82,13 @@ const logClose = fn().mockName('onClose');
|
|
|
81
82
|
* ------------------------------------------------------------------------- */
|
|
82
83
|
|
|
83
84
|
/** Starts closed — click button to open. Actions are logged. */
|
|
84
|
-
function CreateDrawerTrigger({
|
|
85
|
+
function CreateDrawerTrigger({
|
|
86
|
+
label = 'Open Create Feature',
|
|
87
|
+
workflowDefaults,
|
|
88
|
+
}: {
|
|
89
|
+
label?: string;
|
|
90
|
+
workflowDefaults?: WorkflowDefaults;
|
|
91
|
+
}) {
|
|
85
92
|
const [open, setOpen] = useState(false);
|
|
86
93
|
|
|
87
94
|
return (
|
|
@@ -100,6 +107,7 @@ function CreateDrawerTrigger({ label = 'Open Create Feature' }: { label?: string
|
|
|
100
107
|
setOpen(false);
|
|
101
108
|
}}
|
|
102
109
|
repositoryPath="/Users/dev/my-repo"
|
|
110
|
+
workflowDefaults={workflowDefaults}
|
|
103
111
|
/>
|
|
104
112
|
</div>
|
|
105
113
|
);
|
|
@@ -222,6 +230,71 @@ export const MergeOnly: Story = {
|
|
|
222
230
|
},
|
|
223
231
|
};
|
|
224
232
|
|
|
233
|
+
/* ---------------------------------------------------------------------------
|
|
234
|
+
* Git checkbox stories
|
|
235
|
+
* ------------------------------------------------------------------------- */
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Push checkbox checked — the "Push" option is enabled so the branch will be
|
|
239
|
+
* pushed to remote after implementation. "Create PR" remains unchecked.
|
|
240
|
+
*/
|
|
241
|
+
export const PushOnly: Story = {
|
|
242
|
+
render: () => <CreateDrawerTrigger label="Open (Push Only)" />,
|
|
243
|
+
play: async ({ canvasElement }) => {
|
|
244
|
+
const canvas = within(canvasElement);
|
|
245
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Open (Push Only)' }));
|
|
246
|
+
|
|
247
|
+
const body = within(canvasElement.ownerDocument.body);
|
|
248
|
+
const pushCheckbox = await body.findByLabelText('Push');
|
|
249
|
+
await userEvent.click(pushCheckbox);
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create PR checked — checking "Create PR" auto-checks and disables "Push"
|
|
255
|
+
* because a PR cannot be created without pushing. Both checkboxes appear
|
|
256
|
+
* checked, but "Push" is non-interactive (disabled).
|
|
257
|
+
*/
|
|
258
|
+
export const PrChecked: Story = {
|
|
259
|
+
render: () => <CreateDrawerTrigger label="Open (PR Checked)" />,
|
|
260
|
+
play: async ({ canvasElement }) => {
|
|
261
|
+
const canvas = within(canvasElement);
|
|
262
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Open (PR Checked)' }));
|
|
263
|
+
|
|
264
|
+
const body = within(canvasElement.ownerDocument.body);
|
|
265
|
+
const prCheckbox = await body.findByLabelText('Create PR');
|
|
266
|
+
await userEvent.click(prCheckbox);
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/* ---------------------------------------------------------------------------
|
|
271
|
+
* Workflow defaults stories
|
|
272
|
+
* ------------------------------------------------------------------------- */
|
|
273
|
+
|
|
274
|
+
const SAMPLE_WORKFLOW_DEFAULTS: WorkflowDefaults = {
|
|
275
|
+
approvalGates: { allowPrd: true, allowPlan: true, allowMerge: false },
|
|
276
|
+
push: true,
|
|
277
|
+
openPr: true,
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Drawer pre-populated from workflow settings — PRD and Plan approval gates
|
|
282
|
+
* are checked, Push and Create PR are enabled. These values come from
|
|
283
|
+
* `shep settings workflow` and are read at mount time via `getWorkflowDefaults()`.
|
|
284
|
+
*/
|
|
285
|
+
export const WithWorkflowDefaults: Story = {
|
|
286
|
+
render: () => (
|
|
287
|
+
<CreateDrawerTrigger
|
|
288
|
+
label="Open (Workflow Defaults)"
|
|
289
|
+
workflowDefaults={SAMPLE_WORKFLOW_DEFAULTS}
|
|
290
|
+
/>
|
|
291
|
+
),
|
|
292
|
+
play: async ({ canvasElement }) => {
|
|
293
|
+
const canvas = within(canvasElement);
|
|
294
|
+
await userEvent.click(canvas.getByRole('button', { name: 'Open (Workflow Defaults)' }));
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
225
298
|
/* ---------------------------------------------------------------------------
|
|
226
299
|
* Interactive story — full paths shown in submitted data panel
|
|
227
300
|
* ------------------------------------------------------------------------- */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState, useCallback } from 'react';
|
|
3
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import type { LucideIcon } from 'lucide-react';
|
|
5
5
|
import {
|
|
6
6
|
XIcon,
|
|
@@ -25,9 +25,11 @@ import { Input } from '@/components/ui/input';
|
|
|
25
25
|
import { Textarea } from '@/components/ui/textarea';
|
|
26
26
|
import { Label } from '@/components/ui/label';
|
|
27
27
|
import { CheckboxGroup } from '@/components/ui/checkbox-group';
|
|
28
|
+
import { CheckboxGroupItem } from '@/components/ui/checkbox-group-item';
|
|
28
29
|
import { Separator } from '@/components/ui/separator';
|
|
29
30
|
import { Badge } from '@/components/ui/badge';
|
|
30
31
|
import type { FileAttachment } from '@shepai/core/infrastructure/services/file-dialog.service';
|
|
32
|
+
import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
|
|
31
33
|
import { pickFiles } from './pick-files';
|
|
32
34
|
|
|
33
35
|
export type { FileAttachment } from '@shepai/core/infrastructure/services/file-dialog.service';
|
|
@@ -42,6 +44,8 @@ export interface FeatureCreatePayload {
|
|
|
42
44
|
allowPlan: boolean;
|
|
43
45
|
allowMerge: boolean;
|
|
44
46
|
};
|
|
47
|
+
push: boolean;
|
|
48
|
+
openPr: boolean;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
const AUTO_APPROVE_OPTIONS = [
|
|
@@ -62,6 +66,7 @@ export interface FeatureCreateDrawerProps {
|
|
|
62
66
|
onSubmit: (data: FeatureCreatePayload) => void;
|
|
63
67
|
repositoryPath: string;
|
|
64
68
|
isSubmitting?: boolean;
|
|
69
|
+
workflowDefaults?: WorkflowDefaults;
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
export function FeatureCreateDrawer({
|
|
@@ -70,18 +75,36 @@ export function FeatureCreateDrawer({
|
|
|
70
75
|
onSubmit,
|
|
71
76
|
repositoryPath,
|
|
72
77
|
isSubmitting = false,
|
|
78
|
+
workflowDefaults,
|
|
73
79
|
}: FeatureCreateDrawerProps) {
|
|
80
|
+
const defaultGates = workflowDefaults?.approvalGates ?? EMPTY_GATES;
|
|
81
|
+
const defaultPush = workflowDefaults?.push ?? false;
|
|
82
|
+
const defaultOpenPr = workflowDefaults?.openPr ?? false;
|
|
83
|
+
|
|
74
84
|
const [name, setName] = useState('');
|
|
75
85
|
const [description, setDescription] = useState('');
|
|
76
86
|
const [attachments, setAttachments] = useState<FileAttachment[]>([]);
|
|
77
|
-
const [approvalGates, setApprovalGates] = useState<Record<string, boolean>>({ ...
|
|
87
|
+
const [approvalGates, setApprovalGates] = useState<Record<string, boolean>>({ ...defaultGates });
|
|
88
|
+
const [push, setPush] = useState(defaultPush);
|
|
89
|
+
const [openPr, setOpenPr] = useState(defaultOpenPr);
|
|
90
|
+
|
|
91
|
+
// Sync state when workflowDefaults load asynchronously
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
if (workflowDefaults) {
|
|
94
|
+
setApprovalGates({ ...workflowDefaults.approvalGates });
|
|
95
|
+
setPush(workflowDefaults.push);
|
|
96
|
+
setOpenPr(workflowDefaults.openPr);
|
|
97
|
+
}
|
|
98
|
+
}, [workflowDefaults]);
|
|
78
99
|
|
|
79
100
|
const resetForm = useCallback(() => {
|
|
80
101
|
setName('');
|
|
81
102
|
setDescription('');
|
|
82
103
|
setAttachments([]);
|
|
83
|
-
setApprovalGates({ ...
|
|
84
|
-
|
|
104
|
+
setApprovalGates({ ...defaultGates });
|
|
105
|
+
setPush(defaultPush);
|
|
106
|
+
setOpenPr(defaultOpenPr);
|
|
107
|
+
}, [defaultGates, defaultPush, defaultOpenPr]);
|
|
85
108
|
|
|
86
109
|
const handleOpenChange = useCallback(
|
|
87
110
|
(nextOpen: boolean) => {
|
|
@@ -108,9 +131,11 @@ export function FeatureCreateDrawer({
|
|
|
108
131
|
allowPlan: approvalGates.allowPlan ?? false,
|
|
109
132
|
allowMerge: approvalGates.allowMerge ?? false,
|
|
110
133
|
},
|
|
134
|
+
push: push || openPr,
|
|
135
|
+
openPr,
|
|
111
136
|
});
|
|
112
137
|
},
|
|
113
|
-
[name, description, attachments, approvalGates, repositoryPath, onSubmit]
|
|
138
|
+
[name, description, attachments, approvalGates, repositoryPath, onSubmit, push, openPr]
|
|
114
139
|
);
|
|
115
140
|
|
|
116
141
|
const handleAddFiles = useCallback(async () => {
|
|
@@ -211,6 +236,31 @@ export function FeatureCreateDrawer({
|
|
|
211
236
|
/>
|
|
212
237
|
</div>
|
|
213
238
|
|
|
239
|
+
{/* Git options */}
|
|
240
|
+
<div className="flex flex-col gap-1.5">
|
|
241
|
+
<Label className="text-muted-foreground text-xs font-semibold tracking-wider">
|
|
242
|
+
GIT
|
|
243
|
+
</Label>
|
|
244
|
+
<div className="flex flex-col gap-2">
|
|
245
|
+
<CheckboxGroupItem
|
|
246
|
+
id="push"
|
|
247
|
+
label="Push"
|
|
248
|
+
description="Push branch to remote after implementation."
|
|
249
|
+
checked={push || openPr}
|
|
250
|
+
onCheckedChange={setPush}
|
|
251
|
+
disabled={openPr || isSubmitting}
|
|
252
|
+
/>
|
|
253
|
+
<CheckboxGroupItem
|
|
254
|
+
id="open-pr"
|
|
255
|
+
label="Create PR"
|
|
256
|
+
description="Open a pull request after pushing."
|
|
257
|
+
checked={openPr}
|
|
258
|
+
onCheckedChange={setOpenPr}
|
|
259
|
+
disabled={isSubmitting}
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
|
|
214
264
|
{/* Attachments */}
|
|
215
265
|
<div className="flex flex-col gap-2">
|
|
216
266
|
<div className="flex items-center justify-between">
|
|
@@ -6,6 +6,8 @@ import { toast } from 'sonner';
|
|
|
6
6
|
import { approveFeature } from '@/app/actions/approve-feature';
|
|
7
7
|
import { getFeatureArtifact } from '@/app/actions/get-feature-artifact';
|
|
8
8
|
import { getResearchArtifact } from '@/app/actions/get-research-artifact';
|
|
9
|
+
import { getWorkflowDefaults } from '@/app/actions/get-workflow-defaults';
|
|
10
|
+
import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
|
|
9
11
|
import type { TechDecisionsReviewData } from '@/components/common/tech-decisions-review';
|
|
10
12
|
import { FeaturesCanvas } from '@/components/features/features-canvas';
|
|
11
13
|
import type { CanvasNodeType } from '@/components/features/features-canvas';
|
|
@@ -44,6 +46,16 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
|
|
|
44
46
|
closeCreateDrawer,
|
|
45
47
|
} = useControlCenterState(initialNodes, initialEdges);
|
|
46
48
|
|
|
49
|
+
// Workflow defaults for the create-feature drawer
|
|
50
|
+
const [workflowDefaults, setWorkflowDefaults] = useState<WorkflowDefaults | undefined>();
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
getWorkflowDefaults()
|
|
53
|
+
.then(setWorkflowDefaults)
|
|
54
|
+
.catch(() => {
|
|
55
|
+
// Settings unavailable — drawer falls back to all-false defaults
|
|
56
|
+
});
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
47
59
|
// PRD questionnaire drawer state
|
|
48
60
|
const [prdSelections, setPrdSelections] = useState<Record<string, string>>({});
|
|
49
61
|
const [isPrdProcessing, setIsPrdProcessing] = useState(false);
|
|
@@ -185,6 +197,8 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
|
|
|
185
197
|
};
|
|
186
198
|
}, [techDecisionsFeatureId]);
|
|
187
199
|
|
|
200
|
+
const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
|
|
201
|
+
|
|
188
202
|
// Listen for global "open create drawer" events from the sidebar
|
|
189
203
|
useEffect(() => {
|
|
190
204
|
const handler = () => handleAddFeature();
|
|
@@ -192,6 +206,22 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
|
|
|
192
206
|
return () => window.removeEventListener('shep:open-create-drawer', handler);
|
|
193
207
|
}, [handleAddFeature]);
|
|
194
208
|
|
|
209
|
+
if (!hasRepositories) {
|
|
210
|
+
return (
|
|
211
|
+
<>
|
|
212
|
+
<NotificationPermissionBanner />
|
|
213
|
+
<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />
|
|
214
|
+
<FeatureCreateDrawer
|
|
215
|
+
open={isCreateDrawerOpen}
|
|
216
|
+
onClose={closeCreateDrawer}
|
|
217
|
+
onSubmit={handleCreateFeatureSubmit}
|
|
218
|
+
repositoryPath={pendingRepositoryPath}
|
|
219
|
+
workflowDefaults={workflowDefaults}
|
|
220
|
+
/>
|
|
221
|
+
</>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
195
225
|
return (
|
|
196
226
|
<>
|
|
197
227
|
<NotificationPermissionBanner />
|
|
@@ -257,6 +287,7 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
|
|
|
257
287
|
onClose={closeCreateDrawer}
|
|
258
288
|
onSubmit={handleCreateFeatureSubmit}
|
|
259
289
|
repositoryPath={pendingRepositoryPath}
|
|
290
|
+
workflowDefaults={workflowDefaults}
|
|
260
291
|
/>
|
|
261
292
|
</>
|
|
262
293
|
);
|
|
@@ -124,6 +124,9 @@ export function layoutWithDagre<N extends Node>(
|
|
|
124
124
|
minX = Math.min(minX, n.position.x);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// When no graph nodes exist (all disconnected), default to origin
|
|
128
|
+
if (minX === Infinity) minX = 0;
|
|
129
|
+
|
|
127
130
|
for (let i = 0; i < disconnectedNodes.length; i++) {
|
|
128
131
|
const node = disconnectedNodes[i];
|
|
129
132
|
const size = getNodeSize(node, nodeSize);
|
|
@@ -15,7 +15,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
|
|
|
15
15
|
const hostname = process.env.HOSTNAME || '0.0.0.0'
|
|
16
16
|
|
|
17
17
|
let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
|
|
18
|
-
const nextConfig = {"env":{"NEXT_PUBLIC_SHEP_VERSION":"1.
|
|
18
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_SHEP_VERSION":"1.46.0","NEXT_PUBLIC_SHEP_PACKAGE_NAME":"@shepai/cli","NEXT_PUBLIC_SHEP_DESCRIPTION":"Autonomous AI Native SDLC Platform - Automate the development cycle from idea to deploy"},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":true,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/cli/cli","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"dynamicOnHover":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":false,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":false,"lockDistDir":true,"isolatedDevBuild":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":false,"optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","turbopack":{"root":"/home/runner/work/cli/cli"},"serverExternalPackages":["tsyringe","reflect-metadata","better-sqlite3"],"distDirRoot":".next"}
|
|
19
19
|
|
|
20
20
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
21
21
|
|