@shepai/cli 1.50.0 → 1.51.1

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 (149) hide show
  1. package/apis/json-schema/AgentType.yaml +1 -0
  2. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +11 -0
  3. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
  4. package/dist/packages/core/src/application/use-cases/agents/configure-agent.use-case.d.ts.map +1 -1
  5. package/dist/packages/core/src/application/use-cases/agents/configure-agent.use-case.js +6 -4
  6. package/dist/packages/core/src/domain/generated/output.d.ts +2 -1
  7. package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
  8. package/dist/packages/core/src/domain/generated/output.js +1 -0
  9. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -1
  10. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +10 -1
  11. package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.js +3 -0
  13. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.d.ts +12 -0
  14. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.d.ts.map +1 -0
  15. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.js +128 -0
  16. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/plan.fixture.d.ts +8 -0
  17. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/plan.fixture.d.ts.map +1 -0
  18. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/plan.fixture.js +94 -0
  19. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/research.fixture.d.ts +8 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/research.fixture.d.ts.map +1 -0
  21. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/research.fixture.js +140 -0
  22. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-analyze.fixture.d.ts +8 -0
  23. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-analyze.fixture.d.ts.map +1 -0
  24. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-analyze.fixture.js +81 -0
  25. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-requirements.fixture.d.ts +8 -0
  26. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-requirements.fixture.d.ts.map +1 -0
  27. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/spec-requirements.fixture.js +131 -0
  28. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/tasks.fixture.d.ts +6 -0
  29. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/tasks.fixture.d.ts.map +1 -0
  30. package/dist/packages/core/src/infrastructure/services/agents/common/executors/fixtures/tasks.fixture.js +146 -0
  31. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  32. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +1 -0
  33. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts +5 -0
  34. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
  35. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +16 -4
  36. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts +1 -1
  37. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
  38. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +3 -2
  39. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +1 -0
  40. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  41. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +11 -0
  42. package/dist/src/presentation/cli/commands/settings/agent.command.js +3 -3
  43. package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts +8 -4
  44. package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts.map +1 -1
  45. package/dist/src/presentation/tui/prompts/agent-select.prompt.js +10 -5
  46. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.d.ts +1 -1
  47. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.d.ts.map +1 -1
  48. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.js +6 -0
  49. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.stories.d.ts +1 -0
  50. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.stories.d.ts.map +1 -1
  51. package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.stories.js +7 -0
  52. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +3 -1
  53. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -1
  54. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts +1 -1
  55. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts.map +1 -1
  56. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.js +3 -2
  57. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.d.ts +3 -1
  58. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.d.ts.map +1 -1
  59. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-drawer.d.ts +1 -1
  60. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-drawer.d.ts.map +1 -1
  61. package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-drawer.js +3 -2
  62. package/dist/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.js +1 -1
  63. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-drawer.d.ts +1 -1
  64. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-drawer.d.ts.map +1 -1
  65. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-drawer.js +3 -2
  66. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts +3 -1
  67. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.d.ts.map +1 -1
  68. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +1 -1
  69. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  70. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +23 -11
  71. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  72. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +6 -5
  73. package/dist/tsconfig.build.tsbuildinfo +1 -1
  74. package/package.json +1 -1
  75. package/web/.next/BUILD_ID +1 -1
  76. package/web/.next/build-manifest.json +2 -2
  77. package/web/.next/cache/.previewinfo +1 -1
  78. package/web/.next/cache/.rscinfo +1 -1
  79. package/web/.next/cache/.tsbuildinfo +1 -1
  80. package/web/.next/cache/config.json +3 -3
  81. package/web/.next/fallback-build-manifest.json +2 -2
  82. package/web/.next/prerender-manifest.json +3 -3
  83. package/web/.next/required-server-files.js +1 -1
  84. package/web/.next/required-server-files.json +1 -1
  85. package/web/.next/server/app/_global-error.html +2 -2
  86. package/web/.next/server/app/_global-error.rsc +1 -1
  87. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  88. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  89. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  90. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  91. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  92. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  93. package/web/.next/server/app/page/server-reference-manifest.json +14 -14
  94. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  95. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +2 -2
  100. package/web/.next/server/chunks/ssr/_1fafa9db._.js +1 -1
  101. package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +1 -1
  102. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  103. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  104. package/web/.next/server/pages/500.html +2 -2
  105. package/web/.next/server/server-reference-manifest.js +1 -1
  106. package/web/.next/server/server-reference-manifest.json +15 -15
  107. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  108. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  109. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  110. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  111. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  112. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  113. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  114. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  116. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  118. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  119. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +14 -14
  120. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  121. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  122. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  123. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  124. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +2 -2
  125. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_1fafa9db._.js +1 -1
  126. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  127. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  128. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  129. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +15 -15
  130. package/web/.next/standalone/src/presentation/web/components/common/feature-node/agent-type-icons.stories.tsx +16 -0
  131. package/web/.next/standalone/src/presentation/web/components/common/feature-node/agent-type-icons.tsx +8 -1
  132. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +3 -1
  133. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-drawer.tsx +9 -1
  134. package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-config.ts +3 -1
  135. package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire-drawer.tsx +9 -1
  136. package/web/.next/standalone/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.tsx +1 -1
  137. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-drawer.tsx +9 -1
  138. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review-config.ts +3 -1
  139. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +6 -6
  140. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +51 -35
  141. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +6 -5
  142. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  143. package/web/.next/static/chunks/{86340848468ecffa.js → 0d05698b519cd405.js} +4 -4
  144. package/web/.next/static/chunks/{0da7a9860fa6ae05.js → f9953dad6d0c239c.js} +1 -1
  145. package/web/.next/trace +1 -1
  146. package/web/.next/trace-build +1 -1
  147. /package/web/.next/static/{Hbv-BqJZOvcXHMnbSKEtM → FZG4H6o2TaQM__WR3-u30}/_buildManifest.js +0 -0
  148. /package/web/.next/static/{Hbv-BqJZOvcXHMnbSKEtM → FZG4H6o2TaQM__WR3-u30}/_clientMiddlewareManifest.json +0 -0
  149. /package/web/.next/static/{Hbv-BqJZOvcXHMnbSKEtM → FZG4H6o2TaQM__WR3-u30}/_ssgManifest.js +0 -0
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { Loader2 } from 'lucide-react';
3
4
  import { ReviewDrawerShell } from '@/components/common/review-drawer-shell';
4
5
  import { PrdQuestionnaire } from './prd-questionnaire';
5
6
  import type { PrdQuestionnaireDrawerProps } from './prd-questionnaire-config';
@@ -15,6 +16,7 @@ export function PrdQuestionnaireDrawer({
15
16
  specPath,
16
17
  onDelete,
17
18
  isDeleting,
19
+ data,
18
20
  ...questionnaireProps
19
21
  }: PrdQuestionnaireDrawerProps) {
20
22
  return (
@@ -30,7 +32,13 @@ export function PrdQuestionnaireDrawer({
30
32
  onDelete={onDelete}
31
33
  isDeleting={isDeleting}
32
34
  >
33
- <PrdQuestionnaire {...questionnaireProps} />
35
+ {data ? (
36
+ <PrdQuestionnaire data={data} {...questionnaireProps} />
37
+ ) : (
38
+ <div className="flex items-center justify-center p-8">
39
+ <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
40
+ </div>
41
+ )}
34
42
  </ReviewDrawerShell>
35
43
  );
36
44
  }
@@ -63,7 +63,7 @@ export function ReviewDrawerShell({
63
63
  </button>
64
64
 
65
65
  {/* Header */}
66
- <DrawerHeader>
66
+ <DrawerHeader data-testid="feature-drawer-header">
67
67
  <DrawerTitle>{featureName}</DrawerTitle>
68
68
  {featureDescription ? (
69
69
  <DrawerDescription>{featureDescription}</DrawerDescription>
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { Loader2 } from 'lucide-react';
3
4
  import { ReviewDrawerShell } from '@/components/common/review-drawer-shell';
4
5
  import { TechDecisionsReview } from './tech-decisions-review';
5
6
  import type { TechDecisionsDrawerProps } from './tech-decisions-review-config';
@@ -14,6 +15,7 @@ export function TechDecisionsDrawer({
14
15
  specPath,
15
16
  onDelete,
16
17
  isDeleting,
18
+ data,
17
19
  ...reviewProps
18
20
  }: TechDecisionsDrawerProps) {
19
21
  return (
@@ -28,7 +30,13 @@ export function TechDecisionsDrawer({
28
30
  onDelete={onDelete}
29
31
  isDeleting={isDeleting}
30
32
  >
31
- <TechDecisionsReview {...reviewProps} />
33
+ {data ? (
34
+ <TechDecisionsReview data={data} {...reviewProps} />
35
+ ) : (
36
+ <div className="flex items-center justify-center p-8">
37
+ <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
38
+ </div>
39
+ )}
32
40
  </ReviewDrawerShell>
33
41
  );
34
42
  }
@@ -22,7 +22,9 @@ export interface TechDecisionsReviewProps {
22
22
  isRejecting?: boolean;
23
23
  }
24
24
 
25
- export interface TechDecisionsDrawerProps extends TechDecisionsReviewProps {
25
+ export interface TechDecisionsDrawerProps extends Omit<TechDecisionsReviewProps, 'data'> {
26
+ /** Tech decisions data — null while loading */
27
+ data: TechDecisionsReviewData | null;
26
28
  /** Whether the drawer is open */
27
29
  open: boolean;
28
30
  /** Callback when drawer should close */
@@ -351,9 +351,9 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
351
351
  onDelete={handleDeleteFeature}
352
352
  isDeleting={isDeleting}
353
353
  />
354
- {questionnaireData ? (
354
+ {showPrdDrawer ? (
355
355
  <PrdQuestionnaireDrawer
356
- open={showPrdDrawer}
356
+ open
357
357
  onClose={clearSelection}
358
358
  featureName={selectedNode?.name ?? ''}
359
359
  featureDescription={selectedNode?.description}
@@ -372,9 +372,9 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
372
372
  isProcessing={isLoadingQuestionnaire}
373
373
  />
374
374
  ) : null}
375
- {techDecisionsData ? (
375
+ {showTechDecisionsDrawer ? (
376
376
  <TechDecisionsDrawer
377
- open={showTechDecisionsDrawer}
377
+ open
378
378
  onClose={clearSelection}
379
379
  featureName={selectedNode?.name ?? ''}
380
380
  featureId={selectedNode?.featureId}
@@ -390,9 +390,9 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
390
390
  isProcessing={isLoadingTechDecisions}
391
391
  />
392
392
  ) : null}
393
- {mergeReviewData ? (
393
+ {showMergeReviewDrawer ? (
394
394
  <MergeReviewDrawer
395
- open={showMergeReviewDrawer}
395
+ open
396
396
  onClose={clearSelection}
397
397
  featureName={selectedNode?.name ?? ''}
398
398
  featureId={selectedNode?.featureId}
@@ -49,7 +49,19 @@ export function useControlCenterState(
49
49
  ): ControlCenterState {
50
50
  const router = useRouter();
51
51
  const [nodes, setNodes] = useState<CanvasNodeType[]>(initialNodes);
52
- const [edges, setEdges] = useState<Edge[]>(initialEdges);
52
+ // eslint-disable-next-line react/hook-use-state -- raw setter renamed; public setEdges wrapper keeps edgesRef in sync
53
+ const [edges, setEdgesRaw] = useState<Edge[]>(initialEdges);
54
+ const edgesRef = useRef<Edge[]>(initialEdges);
55
+
56
+ // Wrapper that keeps edgesRef in sync with edges state, allowing
57
+ // createFeatureNode to read current edges without a closure dependency.
58
+ const setEdges = useCallback((update: Edge[] | ((prev: Edge[]) => Edge[])) => {
59
+ setEdgesRaw((prev) => {
60
+ const next = typeof update === 'function' ? update(prev) : update;
61
+ edgesRef.current = next;
62
+ return next;
63
+ });
64
+ }, []);
53
65
  const [selectedNode, setSelectedNode] = useState<FeatureNodeData | null>(null);
54
66
  const [isCreateDrawerOpen, setIsCreateDrawerOpen] = useState(false);
55
67
  const [isDeleting, setIsDeleting] = useState(false);
@@ -103,7 +115,7 @@ export function useControlCenterState(
103
115
 
104
116
  useEffect(() => {
105
117
  setEdges(initialEdges);
106
- }, [initialEdgeKey, initialEdges]);
118
+ }, [initialEdgeKey, initialEdges, setEdges]);
107
119
 
108
120
  // Refresh server data when SSE agent events arrive (status changes)
109
121
  const { lastEvent } = useAgentEventsContext();
@@ -145,35 +157,38 @@ export function useControlCenterState(
145
157
  return () => document.removeEventListener('keydown', handleKeyDown);
146
158
  }, [clearSelection]);
147
159
 
148
- const handleConnect = useCallback((connection: Connection) => {
149
- if (!connection.source || !connection.target) return;
160
+ const handleConnect = useCallback(
161
+ (connection: Connection) => {
162
+ if (!connection.source || !connection.target) return;
150
163
 
151
- setNodes((currentNodes) => {
152
- const sourceNode = currentNodes.find((n) => n.id === connection.source);
153
- if (sourceNode?.type !== 'repositoryNode') return currentNodes;
154
-
155
- // Block if target feature already has a repo source
156
- setEdges((currentEdges) => {
157
- const targetAlreadyHasRepo = currentEdges.some((e) => {
158
- const edgeSource = currentNodes.find((n) => n.id === e.source);
159
- return edgeSource?.type === 'repositoryNode' && e.target === connection.target;
164
+ setNodes((currentNodes) => {
165
+ const sourceNode = currentNodes.find((n) => n.id === connection.source);
166
+ if (sourceNode?.type !== 'repositoryNode') return currentNodes;
167
+
168
+ // Block if target feature already has a repo source
169
+ setEdges((currentEdges) => {
170
+ const targetAlreadyHasRepo = currentEdges.some((e) => {
171
+ const edgeSource = currentNodes.find((n) => n.id === e.source);
172
+ return edgeSource?.type === 'repositoryNode' && e.target === connection.target;
173
+ });
174
+ if (targetAlreadyHasRepo) return currentEdges;
175
+
176
+ return [
177
+ ...currentEdges,
178
+ {
179
+ id: `edge-${connection.source}-${connection.target}`,
180
+ source: connection.source,
181
+ target: connection.target,
182
+ style: { strokeDasharray: '5 5' },
183
+ },
184
+ ];
160
185
  });
161
- if (targetAlreadyHasRepo) return currentEdges;
162
186
 
163
- return [
164
- ...currentEdges,
165
- {
166
- id: `edge-${connection.source}-${connection.target}`,
167
- source: connection.source,
168
- target: connection.target,
169
- style: { strokeDasharray: '5 5' },
170
- },
171
- ];
187
+ return currentNodes;
172
188
  });
173
-
174
- return currentNodes;
175
- });
176
- }, []);
189
+ },
190
+ [setEdges]
191
+ );
177
192
 
178
193
  const createFeatureNode = useCallback(
179
194
  (sourceNodeId: string | null, dataOverride?: Partial<FeatureNodeData>): string => {
@@ -190,9 +205,10 @@ export function useControlCenterState(
190
205
  };
191
206
 
192
207
  setNodes((currentNodes) => {
193
- // Find siblings connected to the same parent
208
+ // Read edges from ref to avoid closure dependency on `edges` state.
209
+ // edgesRef is kept in sync by the setEdges wrapper.
194
210
  const siblingIds = sourceNodeId
195
- ? new Set(edges.filter((e) => e.source === sourceNodeId).map((e) => e.target))
211
+ ? new Set(edgesRef.current.filter((e) => e.source === sourceNodeId).map((e) => e.target))
196
212
  : new Set<string>();
197
213
  const siblings = currentNodes.filter((n) => siblingIds.has(n.id));
198
214
 
@@ -290,7 +306,7 @@ export function useControlCenterState(
290
306
 
291
307
  return id;
292
308
  },
293
- [edges]
309
+ [setEdges]
294
310
  );
295
311
 
296
312
  const handleAddFeature = useCallback(() => {
@@ -332,7 +348,7 @@ export function useControlCenterState(
332
348
  toast.error('Failed to create feature');
333
349
  });
334
350
  },
335
- [router, createFeatureNode, pendingRepoNodeId]
351
+ [router, createFeatureNode, pendingRepoNodeId, setEdges]
336
352
  );
337
353
 
338
354
  const closeCreateDrawer = useCallback(() => {
@@ -372,7 +388,7 @@ export function useControlCenterState(
372
388
  setIsDeleting(false);
373
389
  }
374
390
  },
375
- [router, edges]
391
+ [router, edges, setEdges]
376
392
  );
377
393
 
378
394
  const handleDeleteRepository = useCallback(
@@ -399,7 +415,7 @@ export function useControlCenterState(
399
415
  router.refresh();
400
416
  }
401
417
  },
402
- [router]
418
+ [router, setEdges]
403
419
  );
404
420
 
405
421
  const handleAddFeatureToRepo = useCallback((repoNodeId: string) => {
@@ -428,7 +444,7 @@ export function useControlCenterState(
428
444
  return result.nodes;
429
445
  });
430
446
  },
431
- [edges]
447
+ [edges, setEdges]
432
448
  );
433
449
 
434
450
  const handleAddRepository = useCallback(
@@ -535,7 +551,7 @@ export function useControlCenterState(
535
551
  toast.error('Failed to add repository');
536
552
  });
537
553
  },
538
- [router]
554
+ [router, setEdges]
539
555
  );
540
556
 
541
557
  const pendingNode = pendingRepoNodeId ? nodes.find((n) => n.id === pendingRepoNodeId) : null;
@@ -80,11 +80,12 @@ export function FeaturesCanvas({
80
80
  data: {
81
81
  ...node.data,
82
82
  showHandles: edges.length > 0,
83
- ...(node.type === 'featureNode' &&
84
- (node.data as FeatureNodeData).state !== 'creating' && {
85
- onAction: onNodeAction ? () => onNodeAction(node.id) : undefined,
86
- onSettings: onNodeSettings ? () => onNodeSettings(node.id) : undefined,
87
- }),
83
+ ...(node.type === 'featureNode' && (node.data as FeatureNodeData).state !== 'creating'
84
+ ? {
85
+ onAction: onNodeAction ? () => onNodeAction(node.id) : undefined,
86
+ onSettings: onNodeSettings ? () => onNodeSettings(node.id) : undefined,
87
+ }
88
+ : {}),
88
89
  ...(node.type === 'repositoryNode' && {
89
90
  onAdd: onRepositoryAdd ? () => onRepositoryAdd(node.id) : undefined,
90
91
  onDelete: onRepositoryDelete,
@@ -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.49.1","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"}
18
+ const nextConfig = {"env":{"NEXT_PUBLIC_SHEP_VERSION":"1.51.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