@shepai/cli 1.47.0 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/apis/json-schema/ApprovalGateDefaults.yaml +26 -0
  2. package/apis/json-schema/Feature.yaml +3 -0
  3. package/apis/json-schema/Repository.yaml +16 -0
  4. package/apis/json-schema/Settings.yaml +5 -0
  5. package/apis/json-schema/WorkflowConfig.yaml +4 -20
  6. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +17 -0
  7. package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +11 -1
  9. package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
  10. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +3 -1
  11. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  12. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +11 -4
  13. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts +19 -0
  14. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.d.ts.map +1 -0
  15. package/dist/packages/core/src/application/use-cases/features/get-plan-artifact.use-case.js +52 -0
  16. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/di/container.js +5 -0
  18. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  19. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +2 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts +2 -0
  21. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.d.ts.map +1 -1
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge.node.js +10 -3
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +15 -7
  25. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +2 -0
  26. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  27. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +41 -0
  28. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +2 -1
  29. package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
  30. package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +29 -4
  31. package/dist/src/presentation/cli/ui/messages.d.ts.map +1 -1
  32. package/dist/src/presentation/cli/ui/messages.js +1 -7
  33. package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts +7 -0
  34. package/dist/src/presentation/web/app/actions/get-merge-review-data.d.ts.map +1 -0
  35. package/dist/src/presentation/web/app/actions/get-merge-review-data.js +49 -0
  36. package/dist/src/presentation/web/app/page.d.ts.map +1 -1
  37. package/dist/src/presentation/web/app/page.js +1 -0
  38. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +8 -1
  40. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
  41. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
  42. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +22 -1
  43. package/dist/src/presentation/web/components/common/merge-review/index.d.ts +4 -0
  44. package/dist/src/presentation/web/components/common/merge-review/index.d.ts.map +1 -0
  45. package/dist/src/presentation/web/components/common/merge-review/index.js +2 -0
  46. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts +75 -0
  47. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.d.ts.map +1 -0
  48. package/dist/src/presentation/web/components/common/merge-review/merge-review-config.js +1 -0
  49. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts +3 -0
  50. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.d.ts.map +1 -0
  51. package/dist/src/presentation/web/components/common/merge-review/merge-review-drawer.js +7 -0
  52. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts +3 -0
  53. package/dist/src/presentation/web/components/common/merge-review/merge-review.d.ts.map +1 -0
  54. package/dist/src/presentation/web/components/common/merge-review/merge-review.js +36 -0
  55. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts +32 -0
  56. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.d.ts.map +1 -0
  57. package/dist/src/presentation/web/components/common/merge-review/merge-review.stories.js +165 -0
  58. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  59. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +55 -1
  60. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  61. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +15 -0
  62. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  63. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +37 -15
  64. package/dist/tsconfig.build.tsbuildinfo +1 -1
  65. package/package.json +1 -1
  66. package/web/.next/BUILD_ID +1 -1
  67. package/web/.next/build-manifest.json +2 -2
  68. package/web/.next/cache/.previewinfo +1 -1
  69. package/web/.next/cache/.rscinfo +1 -1
  70. package/web/.next/cache/.tsbuildinfo +1 -1
  71. package/web/.next/cache/config.json +3 -3
  72. package/web/.next/fallback-build-manifest.json +2 -2
  73. package/web/.next/prerender-manifest.json +3 -3
  74. package/web/.next/required-server-files.js +1 -1
  75. package/web/.next/required-server-files.json +1 -1
  76. package/web/.next/server/app/_global-error.html +2 -2
  77. package/web/.next/server/app/_global-error.rsc +1 -1
  78. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  80. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  81. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  82. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  83. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  84. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  85. package/web/.next/server/app/page/server-reference-manifest.json +39 -24
  86. package/web/.next/server/app/page.js +1 -1
  87. package/web/.next/server/app/page.js.nft.json +1 -1
  88. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  89. package/web/.next/server/app/version/page.js.nft.json +1 -1
  90. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js.map +1 -0
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  96. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/_3ac3601c._.js → server/chunks/ssr/_1fafa9db._.js} +2 -2
  97. package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +1 -0
  98. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  99. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  101. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  102. package/web/.next/server/pages/500.html +2 -2
  103. package/web/.next/server/server-reference-manifest.js +1 -1
  104. package/web/.next/server/server-reference-manifest.json +40 -25
  105. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  106. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  107. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  108. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  109. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  110. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  111. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  112. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  113. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  114. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  116. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  118. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +39 -24
  119. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
  120. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
  121. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  122. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  123. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  124. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +4 -4
  125. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19d52794._.js +9 -0
  126. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  127. package/web/.next/{server/chunks/ssr/_3ac3601c._.js → standalone/src/presentation/web/.next/server/chunks/ssr/_1fafa9db._.js} +2 -2
  128. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  129. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  130. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  131. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  132. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +40 -25
  133. package/web/.next/standalone/src/presentation/web/app/actions/get-merge-review-data.ts +64 -0
  134. package/web/.next/standalone/src/presentation/web/app/page.tsx +1 -0
  135. package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.stories.tsx +23 -1
  136. package/web/.next/standalone/src/presentation/web/components/common/feature-node/feature-node.tsx +6 -1
  137. package/web/.next/standalone/src/presentation/web/components/common/merge-review/index.ts +7 -0
  138. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-config.ts +81 -0
  139. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review-drawer.tsx +34 -0
  140. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.stories.tsx +240 -0
  141. package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +252 -0
  142. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +82 -1
  143. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +15 -0
  144. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +47 -17
  145. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  146. package/web/.next/static/chunks/{9f8e71029fb04681.js → 0da7a9860fa6ae05.js} +2 -2
  147. package/web/.next/static/chunks/22f30ce91a3c79c1.js +1 -0
  148. package/web/.next/static/chunks/66378a6c055c4e67.js +10 -0
  149. package/web/.next/static/chunks/8668962d3e682263.css +2 -0
  150. package/web/.next/trace +1 -1
  151. package/web/.next/trace-build +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +0 -9
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js.map +0 -1
  154. package/web/.next/server/chunks/ssr/_3ac3601c._.js.map +0 -1
  155. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__d6d75c22._.js +0 -9
  156. package/web/.next/static/chunks/779c99975c85389e.js +0 -10
  157. package/web/.next/static/chunks/83ff3b6bbee54bce.js +0 -1
  158. package/web/.next/static/chunks/b7b7abe79e05b229.css +0 -2
  159. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_buildManifest.js +0 -0
  160. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_clientMiddlewareManifest.json +0 -0
  161. /package/web/.next/static/{wQ3vPV9I8JeacVNyp4HFg → 1kZFDMQ0i-Y8dy1KkHlzv}/_ssgManifest.js +0 -0
@@ -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
+ }
@@ -8,13 +8,16 @@ import { getFeatureArtifact } from '@/app/actions/get-feature-artifact';
8
8
  import { getResearchArtifact } from '@/app/actions/get-research-artifact';
9
9
  import { getWorkflowDefaults } from '@/app/actions/get-workflow-defaults';
10
10
  import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
11
+ import { getMergeReviewData } from '@/app/actions/get-merge-review-data';
11
12
  import type { TechDecisionsReviewData } from '@/components/common/tech-decisions-review';
13
+ import type { MergeReviewData } from '@/components/common/merge-review';
12
14
  import { FeaturesCanvas } from '@/components/features/features-canvas';
13
15
  import type { CanvasNodeType } from '@/components/features/features-canvas';
14
16
  import { FeatureDrawer, FeatureCreateDrawer } from '@/components/common';
15
17
  import { PrdQuestionnaireDrawer } from '@/components/common/prd-questionnaire';
16
18
  import type { PrdQuestionnaireData } from '@/components/common/prd-questionnaire';
17
19
  import { TechDecisionsDrawer } from '@/components/common/tech-decisions-review';
20
+ import { MergeReviewDrawer } from '@/components/common/merge-review';
18
21
  import { NotificationPermissionBanner } from '@/components/common/notification-permission-banner';
19
22
  import { ControlCenterEmptyState } from './control-center-empty-state';
20
23
  import { useControlCenterState } from './use-control-center-state';
@@ -66,12 +69,19 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
66
69
  const [techDecisionsData, setTechDecisionsData] = useState<TechDecisionsReviewData | null>(null);
67
70
  const [isLoadingTechDecisions, setIsLoadingTechDecisions] = useState(false);
68
71
 
72
+ // Merge review drawer state
73
+ const [mergeReviewData, setMergeReviewData] = useState<MergeReviewData | null>(null);
74
+ const [isLoadingMergeReview, setIsLoadingMergeReview] = useState(false);
75
+
69
76
  const showPrdDrawer =
70
77
  selectedNode?.lifecycle === 'requirements' && selectedNode?.state === 'action-required';
71
78
 
72
79
  const showTechDecisionsDrawer =
73
80
  selectedNode?.lifecycle === 'implementation' && selectedNode?.state === 'action-required';
74
81
 
82
+ const showMergeReviewDrawer =
83
+ selectedNode?.lifecycle === 'review' && selectedNode?.state === 'action-required';
84
+
75
85
  const handlePrdSelect = useCallback((questionId: string, optionId: string) => {
76
86
  setPrdSelections((prev) => ({ ...prev, [questionId]: optionId }));
77
87
  }, []);
@@ -125,6 +135,28 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
125
135
  clearSelection();
126
136
  }, [selectedNode?.featureId, clearSelection]);
127
137
 
138
+ const handleMergeApprove = useCallback(async () => {
139
+ const featureId = selectedNode?.featureId;
140
+ if (!featureId) return;
141
+
142
+ const result = await approveFeature(featureId);
143
+
144
+ if (!result.approved) {
145
+ toast.error(result.error ?? 'Failed to approve merge');
146
+ return;
147
+ }
148
+
149
+ toast.success('Merge approved — agent resuming');
150
+ clearSelection();
151
+ }, [selectedNode?.featureId, clearSelection]);
152
+
153
+ const handleMergeRefine = useCallback(async (_text: string) => {
154
+ setIsLoadingMergeReview(true);
155
+ // TODO: Call API to refine merge
156
+ await new Promise((resolve) => setTimeout(resolve, 1500));
157
+ setIsLoadingMergeReview(false);
158
+ }, []);
159
+
128
160
  // Fetch questionnaire data and reset selections when a different feature is selected
129
161
  const prdFeatureId = showPrdDrawer ? selectedNode?.featureId : null;
130
162
  useEffect(() => {
@@ -197,6 +229,36 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
197
229
  };
198
230
  }, [techDecisionsFeatureId]);
199
231
 
232
+ // Fetch merge review data when a feature is in review + action-required
233
+ const mergeFeatureId = showMergeReviewDrawer ? selectedNode?.featureId : null;
234
+ useEffect(() => {
235
+ setMergeReviewData(null);
236
+
237
+ if (!mergeFeatureId) return;
238
+
239
+ let cancelled = false;
240
+ setIsLoadingMergeReview(true);
241
+ getMergeReviewData(mergeFeatureId)
242
+ .then((result) => {
243
+ if (cancelled) return;
244
+ if ('error' in result) {
245
+ toast.error(result.error);
246
+ return;
247
+ }
248
+ setMergeReviewData(result);
249
+ })
250
+ .catch(() => {
251
+ if (!cancelled) toast.error('Failed to load merge review data');
252
+ })
253
+ .finally(() => {
254
+ if (!cancelled) setIsLoadingMergeReview(false);
255
+ });
256
+
257
+ return () => {
258
+ cancelled = true;
259
+ };
260
+ }, [mergeFeatureId]);
261
+
200
262
  const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
201
263
 
202
264
  // Listen for global "open create drawer" events from the sidebar
@@ -240,7 +302,9 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
240
302
  emptyState={<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />}
241
303
  />
242
304
  <FeatureDrawer
243
- selectedNode={showPrdDrawer || showTechDecisionsDrawer ? null : selectedNode}
305
+ selectedNode={
306
+ showPrdDrawer || showTechDecisionsDrawer || showMergeReviewDrawer ? null : selectedNode
307
+ }
244
308
  onClose={clearSelection}
245
309
  onDelete={handleDeleteFeature}
246
310
  isDeleting={isDeleting}
@@ -282,6 +346,23 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
282
346
  isProcessing={isLoadingTechDecisions}
283
347
  />
284
348
  ) : null}
349
+ {mergeReviewData ? (
350
+ <MergeReviewDrawer
351
+ open={showMergeReviewDrawer}
352
+ onClose={clearSelection}
353
+ featureName={selectedNode?.name ?? ''}
354
+ featureId={selectedNode?.featureId}
355
+ repositoryPath={selectedNode?.repositoryPath}
356
+ branch={selectedNode?.branch}
357
+ specPath={selectedNode?.specPath}
358
+ data={mergeReviewData}
359
+ onApprove={handleMergeApprove}
360
+ onRefine={handleMergeRefine}
361
+ onDelete={handleDeleteFeature}
362
+ isDeleting={isDeleting}
363
+ isProcessing={isLoadingMergeReview}
364
+ />
365
+ ) : null}
285
366
  <FeatureCreateDrawer
286
367
  open={isCreateDrawerOpen}
287
368
  onClose={closeCreateDrawer}
@@ -75,6 +75,21 @@ const featureNodes: FeatureNodeType[] = [
75
75
  branch: 'feat/api-gateway',
76
76
  },
77
77
  },
78
+ {
79
+ id: 'feat-4',
80
+ type: 'featureNode',
81
+ position: { x: 800, y: 345 },
82
+ data: {
83
+ name: 'Merge Review',
84
+ description: 'PR ready for merge approval',
85
+ featureId: '#f4',
86
+ lifecycle: 'review',
87
+ state: 'action-required',
88
+ progress: 90,
89
+ repositoryPath: '/home/user/my-repo',
90
+ branch: 'feat/merge-review',
91
+ },
92
+ },
78
93
  ];
79
94
 
80
95
  const repoNode: RepositoryNodeType = {
@@ -351,8 +351,19 @@ export function useControlCenterState(
351
351
  }
352
352
 
353
353
  setSelectedNode(null);
354
- setNodes((prev) => prev.filter((n) => n.id !== featureId));
355
- setEdges((prev) => prev.filter((e) => e.source !== featureId && e.target !== featureId));
354
+ setNodes((currentNodes) => {
355
+ const remainingNodes = currentNodes.filter((n) => n.id !== featureId);
356
+ const remainingEdges = edges.filter(
357
+ (e) => e.source !== featureId && e.target !== featureId
358
+ );
359
+ const result = layoutWithDagre(remainingNodes, remainingEdges, {
360
+ direction: 'LR',
361
+ ranksep: 200,
362
+ nodesep: 60,
363
+ });
364
+ setEdges(result.edges);
365
+ return result.nodes;
366
+ });
356
367
  toast.success('Feature deleted successfully');
357
368
  router.refresh();
358
369
  } catch {
@@ -361,7 +372,7 @@ export function useControlCenterState(
361
372
  setIsDeleting(false);
362
373
  }
363
374
  },
364
- [router]
375
+ [router, edges]
365
376
  );
366
377
 
367
378
  const handleDeleteRepository = useCallback(
@@ -430,23 +441,23 @@ export function useControlCenterState(
430
441
  .pop() ?? path;
431
442
 
432
443
  // Optimistic UI: add node immediately
444
+ let savedAddRepoY = 0;
433
445
  setNodes((currentNodes) => {
434
446
  const repoNodes = currentNodes.filter((n) => n.type === 'repositoryNode');
435
447
  const addRepoNode = currentNodes.find((n) => n.type === 'addRepositoryNode');
436
448
 
437
- // Place in the repo column, below the last existing repo node
449
+ // Save addRepoNode's original Y for rollback on error
450
+ if (addRepoNode) savedAddRepoY = addRepoNode.position.y;
451
+
452
+ // Place in the repo column, at the addRepoNode's current position
438
453
  const repoX = repoNodes[0]?.position.x ?? addRepoNode?.position.x ?? 50;
439
454
  const repoHeight = 50; // repositoryNode height
440
455
  const gap = 15; // match dagre nodesep
441
456
 
442
- const lastRepoBottomY =
443
- repoNodes.length > 0
444
- ? Math.max(...repoNodes.map((n) => n.position.y)) + repoHeight
445
- : addRepoNode
446
- ? addRepoNode.position.y
447
- : 0;
448
-
449
- const position = { x: repoX, y: lastRepoBottomY + gap };
457
+ const position = {
458
+ x: repoX,
459
+ y: addRepoNode ? addRepoNode.position.y : 0,
460
+ };
450
461
 
451
462
  const newNode = {
452
463
  id: tempId,
@@ -455,8 +466,10 @@ export function useControlCenterState(
455
466
  data: { name: repoName, repositoryPath: path, id: tempId },
456
467
  } as CanvasNodeType;
457
468
 
458
- // Move addRepo button below the new node
459
- const addRepoY = position.y + repoHeight + gap;
469
+ // Shift addRepo button down by exactly one slot
470
+ const addRepoY = addRepoNode
471
+ ? addRepoNode.position.y + repoHeight + gap
472
+ : position.y + repoHeight + gap;
460
473
 
461
474
  return currentNodes
462
475
  .map((n) =>
@@ -469,8 +482,16 @@ export function useControlCenterState(
469
482
  addRepository({ path, name: repoName })
470
483
  .then((result) => {
471
484
  if (result.error) {
472
- // Rollback optimistic node
473
- setNodes((prev) => prev.filter((n) => n.id !== tempId));
485
+ // Rollback optimistic node and restore addRepoNode position
486
+ setNodes((prev) =>
487
+ prev
488
+ .filter((n) => n.id !== tempId)
489
+ .map((n) =>
490
+ n.type === 'addRepositoryNode'
491
+ ? { ...n, position: { ...n.position, y: savedAddRepoY } }
492
+ : n
493
+ )
494
+ );
474
495
  toast.error(result.error);
475
496
  return;
476
497
  }
@@ -501,7 +522,16 @@ export function useControlCenterState(
501
522
  router.refresh();
502
523
  })
503
524
  .catch(() => {
504
- setNodes((prev) => prev.filter((n) => n.id !== tempId));
525
+ // Rollback optimistic node and restore addRepoNode position
526
+ setNodes((prev) =>
527
+ prev
528
+ .filter((n) => n.id !== tempId)
529
+ .map((n) =>
530
+ n.type === 'addRepositoryNode'
531
+ ? { ...n, position: { ...n.position, y: savedAddRepoY } }
532
+ : n
533
+ )
534
+ );
505
535
  toast.error('Failed to add repository');
506
536
  });
507
537
  },
@@ -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.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"}
18
+ const nextConfig = {"env":{"NEXT_PUBLIC_SHEP_VERSION":"1.47.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