@shepai/cli 1.61.0 → 1.63.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 (201) hide show
  1. package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js +1 -1
  2. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.d.ts +17 -0
  3. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.d.ts.map +1 -0
  4. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.js +23 -0
  5. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.d.ts +22 -0
  6. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.d.ts.map +1 -0
  7. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.js +56 -0
  8. package/dist/src/presentation/web/components/common/base-drawer/index.d.ts +2 -0
  9. package/dist/src/presentation/web/components/common/base-drawer/index.d.ts.map +1 -0
  10. package/dist/src/presentation/web/components/common/base-drawer/index.js +1 -0
  11. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  12. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +11 -16
  13. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts +1 -1
  14. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.js +1 -1
  15. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
  16. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +14 -14
  17. package/dist/src/presentation/web/components/common/repository-node/index.d.ts +1 -0
  18. package/dist/src/presentation/web/components/common/repository-node/index.d.ts.map +1 -1
  19. package/dist/src/presentation/web/components/common/repository-node/index.js +1 -0
  20. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.d.ts +7 -0
  21. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.d.ts.map +1 -0
  22. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.js +12 -0
  23. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.stories.d.ts +9 -0
  24. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.stories.d.ts.map +1 -0
  25. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.stories.js +34 -0
  26. package/dist/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.d.ts.map +1 -1
  27. package/dist/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.js +4 -6
  28. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  29. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +20 -2
  30. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts +3 -1
  31. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  32. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +4 -2
  33. package/dist/src/presentation/web/components/features/skills/skill-detail-drawer.d.ts.map +1 -1
  34. package/dist/src/presentation/web/components/features/skills/skill-detail-drawer.js +3 -6
  35. package/dist/tsconfig.build.tsbuildinfo +1 -1
  36. package/package.json +1 -1
  37. package/web/.next/BUILD_ID +1 -1
  38. package/web/.next/build-manifest.json +2 -2
  39. package/web/.next/cache/.previewinfo +1 -1
  40. package/web/.next/cache/.rscinfo +1 -1
  41. package/web/.next/cache/.tsbuildinfo +1 -1
  42. package/web/.next/cache/config.json +3 -3
  43. package/web/.next/fallback-build-manifest.json +2 -2
  44. package/web/.next/prerender-manifest.json +3 -3
  45. package/web/.next/required-server-files.js +1 -1
  46. package/web/.next/required-server-files.json +1 -1
  47. package/web/.next/server/app/_global-error.html +2 -2
  48. package/web/.next/server/app/_global-error.rsc +1 -1
  49. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  50. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  51. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  52. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  53. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  54. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  55. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  56. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/web/.next/server/app/page/server-reference-manifest.json +14 -14
  58. package/web/.next/server/app/page.js.nft.json +1 -1
  59. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/app/skills/page/server-reference-manifest.json +1 -1
  61. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  62. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  63. package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  64. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  65. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  67. package/web/.next/server/app/version/page.js.nft.json +1 -1
  68. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  69. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  70. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
  71. package/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js +3 -0
  72. package/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js.map +1 -0
  73. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  74. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  75. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  76. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  77. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
  78. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
  79. package/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js +3 -0
  80. package/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js.map +1 -0
  81. package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +2 -2
  82. package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js.map +1 -1
  83. package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +1 -1
  84. package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js.map +1 -1
  85. package/web/.next/server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js +3 -0
  86. package/web/.next/server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js.map +1 -0
  87. package/web/.next/server/chunks/ssr/[root-of-the-server]__fbc89707._.js +1 -1
  88. package/web/.next/server/chunks/ssr/_73d14b70._.js +3 -0
  89. package/web/.next/server/chunks/ssr/_73d14b70._.js.map +1 -0
  90. package/web/.next/server/chunks/ssr/_7f386377._.js +3 -0
  91. package/web/.next/server/chunks/ssr/_7f386377._.js.map +1 -0
  92. package/web/.next/server/chunks/ssr/_d3711354._.js +2 -2
  93. package/web/.next/server/chunks/ssr/_d3711354._.js.map +1 -1
  94. package/web/.next/server/chunks/ssr/{_a64b7b24._.js → _d81184e2._.js} +2 -2
  95. package/web/.next/server/chunks/ssr/_d81184e2._.js.map +1 -0
  96. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/node_modules__pnpm_fe355030._.js → server/chunks/ssr/node_modules__pnpm_87f920e7._.js} +2 -2
  97. package/web/.next/server/chunks/ssr/{node_modules__pnpm_fe355030._.js.map → node_modules__pnpm_87f920e7._.js.map} +1 -1
  98. package/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js +3 -0
  99. package/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js.map +1 -0
  100. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +3 -0
  101. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -0
  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 +15 -15
  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/server-reference-manifest.json +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +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.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/skills/page/server-reference-manifest.json +1 -1
  123. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  124. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  125. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  126. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  127. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  128. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  129. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  130. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  131. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  132. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js +3 -0
  133. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  134. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  135. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
  136. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js +3 -0
  137. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +2 -2
  138. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +1 -1
  139. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js +3 -0
  140. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__fbc89707._.js +1 -1
  141. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_73d14b70._.js +3 -0
  142. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_7f386377._.js +3 -0
  143. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_d3711354._.js +2 -2
  144. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_a64b7b24._.js → _d81184e2._.js} +2 -2
  145. package/web/.next/{server/chunks/ssr/node_modules__pnpm_fe355030._.js → standalone/src/presentation/web/.next/server/chunks/ssr/node_modules__pnpm_87f920e7._.js} +2 -2
  146. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js +3 -0
  147. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +3 -0
  148. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  149. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  150. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +15 -15
  151. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.stories.tsx +207 -0
  152. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.tsx +90 -0
  153. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/index.ts +1 -0
  154. package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.tsx +1 -1
  155. package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx +145 -172
  156. package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/feature-drawer.tsx +119 -133
  157. package/web/.next/standalone/src/presentation/web/components/common/repository-node/index.ts +1 -0
  158. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-drawer.stories.tsx +58 -0
  159. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-drawer.tsx +82 -0
  160. package/web/.next/standalone/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.tsx +79 -96
  161. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +30 -2
  162. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +7 -0
  163. package/web/.next/standalone/src/presentation/web/components/features/skills/skill-detail-drawer.tsx +71 -77
  164. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  165. package/web/.next/static/chunks/0c6654ec27f11c7e.js +1 -0
  166. package/web/.next/static/chunks/12c70bfd5951cf9b.js +1 -0
  167. package/web/.next/static/chunks/21541b346dd4dd28.js +1 -0
  168. package/web/.next/static/chunks/{cb1b27e4a21415d3.js → 3b941e59ac013e12.js} +2 -2
  169. package/web/.next/static/chunks/426292e5fb0b2a61.js +1 -0
  170. package/web/.next/static/chunks/{09d898be63c54f20.js → 78919481e7c5ad4f.js} +1 -1
  171. package/web/.next/static/chunks/a5b6a22de303e877.css +2 -0
  172. package/web/.next/static/chunks/af7a5bcb7c49e46e.js +1 -0
  173. package/web/.next/static/chunks/be784143669bb992.js +1 -0
  174. package/web/.next/static/chunks/ea57f9afe9055c7a.js +10 -0
  175. package/web/.next/trace +1 -1
  176. package/web/.next/trace-build +1 -1
  177. package/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js +0 -3
  178. package/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js.map +0 -1
  179. package/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js +0 -3
  180. package/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js.map +0 -1
  181. package/web/.next/server/chunks/ssr/[root-of-the-server]__ee7cffe1._.js +0 -3
  182. package/web/.next/server/chunks/ssr/[root-of-the-server]__ee7cffe1._.js.map +0 -1
  183. package/web/.next/server/chunks/ssr/_9915d2a7._.js +0 -3
  184. package/web/.next/server/chunks/ssr/_9915d2a7._.js.map +0 -1
  185. package/web/.next/server/chunks/ssr/_a64b7b24._.js.map +0 -1
  186. package/web/.next/server/chunks/ssr/_e7a4b0e4._.js +0 -3
  187. package/web/.next/server/chunks/ssr/_e7a4b0e4._.js.map +0 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2395adc6._.js +0 -3
  189. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__87fda958._.js +0 -3
  190. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__ee7cffe1._.js +0 -3
  191. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9915d2a7._.js +0 -3
  192. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_e7a4b0e4._.js +0 -3
  193. package/web/.next/static/chunks/13664c029245afc8.js +0 -1
  194. package/web/.next/static/chunks/25f42652257ff43d.js +0 -1
  195. package/web/.next/static/chunks/2934854f0378f815.js +0 -1
  196. package/web/.next/static/chunks/2960a70537e4fd12.js +0 -10
  197. package/web/.next/static/chunks/45f510f84c7c417d.css +0 -2
  198. package/web/.next/static/chunks/79718b1f5713fdc0.js +0 -1
  199. /package/web/.next/static/{_DBWexyU1QkK02q15qod2 → 23Y-ea-5g4_fUHZyGpCb0}/_buildManifest.js +0 -0
  200. /package/web/.next/static/{_DBWexyU1QkK02q15qod2 → 23Y-ea-5g4_fUHZyGpCb0}/_clientMiddlewareManifest.json +0 -0
  201. /package/web/.next/static/{_DBWexyU1QkK02q15qod2 → 23Y-ea-5g4_fUHZyGpCb0}/_ssgManifest.js +0 -0
@@ -1,2 +1,3 @@
1
1
  export { RepositoryNode } from './repository-node';
2
+ export { RepositoryDrawer, type RepositoryDrawerProps } from './repository-drawer';
2
3
  export type { RepositoryNodeData, RepositoryNodeType } from './repository-node-config';
@@ -0,0 +1,58 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { Button } from '@/components/ui/button';
4
+ import { RepositoryDrawer } from './repository-drawer';
5
+ import type { RepositoryNodeData } from './repository-node-config';
6
+
7
+ const meta: Meta<typeof RepositoryDrawer> = {
8
+ title: 'Composed/RepositoryDrawer',
9
+ component: RepositoryDrawer,
10
+ tags: ['autodocs'],
11
+ parameters: {
12
+ layout: 'fullscreen',
13
+ },
14
+ };
15
+
16
+ export default meta;
17
+ type Story = StoryObj<typeof RepositoryDrawer>;
18
+
19
+ const repoData: RepositoryNodeData = {
20
+ id: 'repo-1',
21
+ name: 'shep-ai/cli',
22
+ repositoryPath: '/home/user/shep-ai/cli',
23
+ };
24
+
25
+ function DrawerTrigger({ data, label }: { data: RepositoryNodeData; label: string }) {
26
+ const [selected, setSelected] = useState<RepositoryNodeData | null>(null);
27
+
28
+ return (
29
+ <div className="flex h-screen items-start p-4">
30
+ <Button variant="outline" onClick={() => setSelected(data)}>
31
+ {label}
32
+ </Button>
33
+ <RepositoryDrawer data={selected} onClose={() => setSelected(null)} />
34
+ </div>
35
+ );
36
+ }
37
+
38
+ export const Default: Story = {
39
+ render: () => <DrawerTrigger data={repoData} label="Open Repository" />,
40
+ };
41
+
42
+ export const LongPath: Story = {
43
+ render: () => (
44
+ <DrawerTrigger
45
+ data={{
46
+ ...repoData,
47
+ repositoryPath: '/home/user/projects/company/some-very-long-path/shep-ai/cli',
48
+ }}
49
+ label="Open Long Path"
50
+ />
51
+ ),
52
+ };
53
+
54
+ export const WithoutPath: Story = {
55
+ render: () => (
56
+ <DrawerTrigger data={{ ...repoData, repositoryPath: undefined }} label="Open Without Path" />
57
+ ),
58
+ };
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+
3
+ import { Code2, Terminal, FolderOpen } from 'lucide-react';
4
+ import { BaseDrawer } from '@/components/common/base-drawer';
5
+ import { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';
6
+ import { Separator } from '@/components/ui/separator';
7
+ import { ActionButton } from '@/components/common/action-button';
8
+ import type { RepositoryNodeData } from './repository-node-config';
9
+ import { useRepositoryActions } from './use-repository-actions';
10
+
11
+ export interface RepositoryDrawerProps {
12
+ data: RepositoryNodeData | null;
13
+ onClose: () => void;
14
+ }
15
+
16
+ export function RepositoryDrawer({ data, onClose }: RepositoryDrawerProps) {
17
+ const actions = useRepositoryActions(
18
+ data?.repositoryPath ? { repositoryPath: data.repositoryPath } : null
19
+ );
20
+
21
+ return (
22
+ <BaseDrawer
23
+ open={data !== null}
24
+ onClose={onClose}
25
+ size="sm"
26
+ modal={false}
27
+ data-testid="repository-drawer"
28
+ header={
29
+ data ? (
30
+ <div data-testid="repository-drawer-header">
31
+ <DrawerTitle>{data.name}</DrawerTitle>
32
+ {data.repositoryPath ? (
33
+ <DrawerDescription className="truncate font-mono text-xs">
34
+ {data.repositoryPath}
35
+ </DrawerDescription>
36
+ ) : null}
37
+ </div>
38
+ ) : undefined
39
+ }
40
+ >
41
+ {data?.repositoryPath ? (
42
+ <>
43
+ <Separator />
44
+ <div className="flex flex-col gap-3 p-4">
45
+ <div className="text-muted-foreground text-xs font-semibold tracking-wider">
46
+ OPEN WITH
47
+ </div>
48
+ <div className="flex flex-col gap-2">
49
+ <ActionButton
50
+ label="Open in IDE"
51
+ onClick={actions.openInIde}
52
+ loading={actions.ideLoading}
53
+ error={!!actions.ideError}
54
+ icon={Code2}
55
+ variant="outline"
56
+ size="sm"
57
+ />
58
+ <ActionButton
59
+ label="Open in Shell"
60
+ onClick={actions.openInShell}
61
+ loading={actions.shellLoading}
62
+ error={!!actions.shellError}
63
+ icon={Terminal}
64
+ variant="outline"
65
+ size="sm"
66
+ />
67
+ <ActionButton
68
+ label="Open Folder"
69
+ onClick={actions.openFolder}
70
+ loading={actions.folderLoading}
71
+ error={!!actions.folderError}
72
+ icon={FolderOpen}
73
+ variant="outline"
74
+ size="sm"
75
+ />
76
+ </div>
77
+ </div>
78
+ </>
79
+ ) : null}
80
+ </BaseDrawer>
81
+ );
82
+ }
@@ -1,13 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { Loader2, Trash2, XIcon } from 'lucide-react';
4
- import {
5
- Drawer,
6
- DrawerContent,
7
- DrawerHeader,
8
- DrawerTitle,
9
- DrawerDescription,
10
- } from '@/components/ui/drawer';
3
+ import { Loader2, Trash2 } from 'lucide-react';
4
+ import { BaseDrawer } from '@/components/common/base-drawer';
5
+ import { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';
11
6
  import { Button } from '@/components/ui/button';
12
7
  import { Separator } from '@/components/ui/separator';
13
8
  import {
@@ -42,101 +37,89 @@ export function ReviewDrawerShell({
42
37
  const actions = useFeatureActions(actionsInput);
43
38
 
44
39
  return (
45
- <Drawer
46
- direction="right"
47
- modal={false}
48
- handleOnly
40
+ <BaseDrawer
49
41
  open={open}
50
- onOpenChange={(isOpen) => {
51
- if (!isOpen) onClose();
52
- }}
53
- >
54
- <DrawerContent direction="right" className="w-xl" showCloseButton={false}>
55
- {/* Close button */}
56
- <button
57
- type="button"
58
- aria-label="Close"
59
- onClick={onClose}
60
- className="ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden"
61
- >
62
- <XIcon className="size-4" />
63
- </button>
64
-
65
- {/* Header */}
66
- <DrawerHeader data-testid="feature-drawer-header">
67
- <DrawerTitle>{featureName}</DrawerTitle>
68
- {featureDescription ? (
69
- <DrawerDescription>{featureDescription}</DrawerDescription>
70
- ) : featureId ? (
71
- <DrawerDescription className="sr-only">{featureId}</DrawerDescription>
72
- ) : null}
73
- </DrawerHeader>
42
+ onClose={onClose}
43
+ size="md"
44
+ modal={false}
45
+ data-testid="review-drawer"
46
+ header={
47
+ <>
48
+ <div data-testid="feature-drawer-header">
49
+ <DrawerTitle>{featureName}</DrawerTitle>
50
+ {featureDescription ? (
51
+ <DrawerDescription>{featureDescription}</DrawerDescription>
52
+ ) : featureId ? (
53
+ <DrawerDescription className="sr-only">{featureId}</DrawerDescription>
54
+ ) : null}
55
+ </div>
74
56
 
75
- {/* Action menu + inline delete */}
76
- {actionsInput ? (
77
- <div className="flex items-center gap-2 px-4 pb-3">
78
- <OpenActionMenu
79
- actions={actions}
80
- repositoryPath={actionsInput.repositoryPath}
81
- showSpecs={!!specPath}
82
- />
83
- {onDelete && featureId ? (
84
- <>
85
- <div className="bg-border mx-1 h-4 w-px" />
86
- <AlertDialog>
87
- <AlertDialogTrigger asChild>
88
- <Button
89
- variant="ghost"
90
- size="icon-sm"
91
- aria-label="Delete feature"
92
- disabled={isDeleting}
93
- className="text-muted-foreground hover:text-destructive"
94
- data-testid="review-drawer-delete"
95
- >
96
- {isDeleting ? (
97
- <Loader2 className="size-4 animate-spin" />
98
- ) : (
99
- <Trash2 className="size-4" />
100
- )}
101
- </Button>
102
- </AlertDialogTrigger>
103
- <AlertDialogContent>
104
- <AlertDialogHeader>
105
- <AlertDialogTitle>Delete feature?</AlertDialogTitle>
106
- <AlertDialogDescription>
107
- This will permanently delete <strong>{featureName}</strong> ({featureId}).
108
- This action cannot be undone.
109
- </AlertDialogDescription>
110
- </AlertDialogHeader>
111
- <AlertDialogFooter>
112
- <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
113
- <AlertDialogAction
114
- variant="destructive"
57
+ {/* Action menu + inline delete */}
58
+ {actionsInput ? (
59
+ <div className="flex items-center gap-2 pt-2">
60
+ <OpenActionMenu
61
+ actions={actions}
62
+ repositoryPath={actionsInput.repositoryPath}
63
+ showSpecs={!!specPath}
64
+ />
65
+ {onDelete && featureId ? (
66
+ <>
67
+ <div className="bg-border mx-1 h-4 w-px" />
68
+ <AlertDialog>
69
+ <AlertDialogTrigger asChild>
70
+ <Button
71
+ variant="ghost"
72
+ size="icon-sm"
73
+ aria-label="Delete feature"
115
74
  disabled={isDeleting}
116
- onClick={() => onDelete(featureId)}
75
+ className="text-muted-foreground hover:text-destructive"
76
+ data-testid="review-drawer-delete"
117
77
  >
118
78
  {isDeleting ? (
119
- <>
120
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
121
- Deleting…
122
- </>
79
+ <Loader2 className="size-4 animate-spin" />
123
80
  ) : (
124
- 'Delete'
81
+ <Trash2 className="size-4" />
125
82
  )}
126
- </AlertDialogAction>
127
- </AlertDialogFooter>
128
- </AlertDialogContent>
129
- </AlertDialog>
130
- </>
131
- ) : null}
132
- </div>
133
- ) : null}
134
-
135
- <Separator />
83
+ </Button>
84
+ </AlertDialogTrigger>
85
+ <AlertDialogContent>
86
+ <AlertDialogHeader>
87
+ <AlertDialogTitle>Delete feature?</AlertDialogTitle>
88
+ <AlertDialogDescription>
89
+ This will permanently delete <strong>{featureName}</strong> ({featureId}).
90
+ This action cannot be undone.
91
+ </AlertDialogDescription>
92
+ </AlertDialogHeader>
93
+ <AlertDialogFooter>
94
+ <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
95
+ <AlertDialogAction
96
+ variant="destructive"
97
+ disabled={isDeleting}
98
+ onClick={() => onDelete(featureId)}
99
+ >
100
+ {isDeleting ? (
101
+ <>
102
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
103
+ Deleting…
104
+ </>
105
+ ) : (
106
+ 'Delete'
107
+ )}
108
+ </AlertDialogAction>
109
+ </AlertDialogFooter>
110
+ </AlertDialogContent>
111
+ </AlertDialog>
112
+ </>
113
+ ) : null}
114
+ </div>
115
+ ) : null}
116
+ </>
117
+ }
118
+ >
119
+ <Separator />
136
120
 
137
- {/* Content slot */}
138
- <div className="flex min-h-0 flex-1 flex-col">{children}</div>
139
- </DrawerContent>
140
- </Drawer>
121
+ {/* Content slot */}
122
+ <div className="flex min-h-0 flex-1 flex-col">{children}</div>
123
+ </BaseDrawer>
141
124
  );
142
125
  }
@@ -20,6 +20,8 @@ import { FeaturesCanvas } from '@/components/features/features-canvas';
20
20
  import type { CanvasNodeType } from '@/components/features/features-canvas';
21
21
  import type { FeatureNodeData } from '@/components/common/feature-node';
22
22
  import { FeatureDrawer, FeatureCreateDrawer } from '@/components/common';
23
+ import { RepositoryDrawer } from '@/components/common/repository-node';
24
+ import type { RepositoryNodeData } from '@/components/common/repository-node';
23
25
  import { PrdQuestionnaireDrawer } from '@/components/common/prd-questionnaire';
24
26
  import type { PrdQuestionnaireData } from '@/components/common/prd-questionnaire';
25
27
  import { TechDecisionsDrawer } from '@/components/common/tech-decisions-review';
@@ -98,6 +100,28 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
98
100
  const [mergeReviewData, setMergeReviewData] = useState<MergeReviewData | null>(null);
99
101
  const [isLoadingMergeReview, setIsLoadingMergeReview] = useState(false);
100
102
 
103
+ // Repository drawer state
104
+ const [selectedRepoNode, setSelectedRepoNode] = useState<RepositoryNodeData | null>(null);
105
+
106
+ // Clear all drawers — used for pane click and canvas drag
107
+ const handleClearDrawers = useCallback(() => {
108
+ clearSelection();
109
+ setSelectedRepoNode(null);
110
+ closeCreateDrawer();
111
+ }, [clearSelection, closeCreateDrawer]);
112
+
113
+ // Open repository drawer when a repo node is clicked
114
+ const handleRepositoryClick = useCallback(
115
+ (nodeId: string) => {
116
+ const node = nodes.find((n) => n.id === nodeId);
117
+ if (node?.type === 'repositoryNode') {
118
+ clearSelection();
119
+ setSelectedRepoNode(node.data as RepositoryNodeData);
120
+ }
121
+ },
122
+ [nodes, clearSelection]
123
+ );
124
+
101
125
  const showPrdDrawer =
102
126
  selectedNode?.lifecycle === 'requirements' && selectedNode?.state === 'action-required';
103
127
 
@@ -105,7 +129,8 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
105
129
  selectedNode?.lifecycle === 'implementation' && selectedNode?.state === 'action-required';
106
130
 
107
131
  const showMergeReviewDrawer =
108
- selectedNode?.lifecycle === 'review' && selectedNode?.state === 'action-required';
132
+ selectedNode?.lifecycle === 'review' &&
133
+ (selectedNode?.state === 'action-required' || selectedNode?.state === 'error');
109
134
 
110
135
  const handlePrdSelect = useCallback((questionId: string, optionId: string) => {
111
136
  setPrdSelections((prev) => ({ ...prev, [questionId]: optionId }));
@@ -378,10 +403,12 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
378
403
  onAddFeature={handleAddFeature}
379
404
  onNodeAction={handleAddFeatureToFeature}
380
405
  onNodeClick={handleNodeClick}
381
- onPaneClick={clearSelection}
406
+ onPaneClick={handleClearDrawers}
382
407
  onRepositoryAdd={handleAddFeatureToRepo}
408
+ onRepositoryClick={handleRepositoryClick}
383
409
  onRepositoryDelete={handleDeleteRepository}
384
410
  onRepositorySelect={handleAddRepository}
411
+ onCanvasDrag={handleClearDrawers}
385
412
  emptyState={<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />}
386
413
  />
387
414
  <FeatureDrawer
@@ -458,6 +485,7 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
458
485
  features={featureOptions}
459
486
  initialParentId={pendingParentFeatureId}
460
487
  />
488
+ <RepositoryDrawer data={selectedRepoNode} onClose={() => setSelectedRepoNode(null)} />
461
489
  </>
462
490
  );
463
491
  }
@@ -26,9 +26,11 @@ export interface FeaturesCanvasProps {
26
26
  onNodeClick?: (event: React.MouseEvent, node: CanvasNodeType) => void;
27
27
  onPaneClick?: (event: React.MouseEvent) => void;
28
28
  onRepositoryAdd?: (repoNodeId: string) => void;
29
+ onRepositoryClick?: (nodeId: string) => void;
29
30
  onRepositoryDelete?: (repositoryId: string) => void;
30
31
  onConnect?: (connection: Connection) => void;
31
32
  onRepositorySelect?: (path: string) => void;
33
+ onCanvasDrag?: () => void;
32
34
  toolbar?: React.ReactNode;
33
35
  emptyState?: React.ReactNode;
34
36
  }
@@ -44,8 +46,10 @@ export function FeaturesCanvas({
44
46
  onNodeClick,
45
47
  onPaneClick,
46
48
  onRepositoryAdd,
49
+ onRepositoryClick,
47
50
  onRepositoryDelete,
48
51
  onRepositorySelect,
52
+ onCanvasDrag,
49
53
  toolbar,
50
54
  emptyState,
51
55
  }: FeaturesCanvasProps) {
@@ -96,6 +100,7 @@ export function FeaturesCanvas({
96
100
  : {}),
97
101
  ...(node.type === 'repositoryNode' && {
98
102
  onAdd: onRepositoryAdd ? () => onRepositoryAdd(node.id) : undefined,
103
+ onClick: onRepositoryClick ? () => onRepositoryClick(node.id) : undefined,
99
104
  onDelete: onRepositoryDelete,
100
105
  }),
101
106
  ...(node.type === 'addRepositoryNode' && {
@@ -109,6 +114,7 @@ export function FeaturesCanvas({
109
114
  onNodeAction,
110
115
  onNodeSettings,
111
116
  onRepositoryAdd,
117
+ onRepositoryClick,
112
118
  onRepositoryDelete,
113
119
  onRepositorySelect,
114
120
  ]
@@ -151,6 +157,7 @@ export function FeaturesCanvas({
151
157
  onNodesChange={onNodesChange}
152
158
  onNodeClick={onNodeClick}
153
159
  onPaneClick={onPaneClick}
160
+ onMoveStart={onCanvasDrag}
154
161
  defaultViewport={{ x: 30, y: 30, zoom: 0.85 }}
155
162
  nodesDraggable={false}
156
163
  nodesConnectable={false}
@@ -1,14 +1,8 @@
1
1
  'use client';
2
2
 
3
- import {
4
- Sheet,
5
- SheetContent,
6
- SheetHeader,
7
- SheetTitle,
8
- SheetDescription,
9
- } from '@/components/ui/sheet';
3
+ import { BaseDrawer } from '@/components/common/base-drawer';
4
+ import { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';
10
5
  import { Badge } from '@/components/ui/badge';
11
- import { ScrollArea } from '@/components/ui/scroll-area';
12
6
  import { Separator } from '@/components/ui/separator';
13
7
  import { FolderOpen } from 'lucide-react';
14
8
  import type { SkillData } from '@/lib/skills';
@@ -20,81 +14,81 @@ export interface SkillDetailDrawerProps {
20
14
 
21
15
  export function SkillDetailDrawer({ skill, onClose }: SkillDetailDrawerProps) {
22
16
  return (
23
- <Sheet
17
+ <BaseDrawer
24
18
  open={skill !== null}
25
- onOpenChange={(open) => {
26
- if (!open) onClose();
27
- }}
28
- >
29
- <SheetContent side="right" className="w-full sm:max-w-lg">
30
- {skill ? (
19
+ onClose={onClose}
20
+ size="sm"
21
+ modal
22
+ data-testid="skill-detail-drawer"
23
+ header={
24
+ skill ? (
31
25
  <>
32
- <SheetHeader>
33
- <SheetTitle>{skill.displayName}</SheetTitle>
34
- <SheetDescription>{skill.name}</SheetDescription>
35
- </SheetHeader>
26
+ <DrawerTitle>{skill.displayName}</DrawerTitle>
27
+ <DrawerDescription>{skill.name}</DrawerDescription>
28
+ </>
29
+ ) : undefined
30
+ }
31
+ >
32
+ {skill ? (
33
+ <div className="px-4 pb-4">
34
+ {/* Description */}
35
+ <p className="text-muted-foreground text-sm">{skill.description}</p>
36
36
 
37
- <ScrollArea className="flex-1 px-4 pb-4">
38
- {/* Description */}
39
- <p className="text-muted-foreground text-sm">{skill.description}</p>
37
+ {/* Badges */}
38
+ <div className="mt-4 flex flex-wrap items-center gap-1.5">
39
+ <Badge variant={skill.source === 'project' ? 'secondary' : 'outline'}>
40
+ {skill.source === 'project' ? 'Project' : 'Global'}
41
+ </Badge>
42
+ <Badge variant="outline">{skill.category}</Badge>
43
+ {skill.context ? <Badge variant="outline">{skill.context}</Badge> : null}
44
+ </div>
40
45
 
41
- {/* Badges */}
42
- <div className="mt-4 flex flex-wrap items-center gap-1.5">
43
- <Badge variant={skill.source === 'project' ? 'secondary' : 'outline'}>
44
- {skill.source === 'project' ? 'Project' : 'Global'}
45
- </Badge>
46
- <Badge variant="outline">{skill.category}</Badge>
47
- {skill.context ? <Badge variant="outline">{skill.context}</Badge> : null}
46
+ {/* Allowed Tools */}
47
+ {skill.allowedTools ? (
48
+ <>
49
+ <Separator className="my-4" />
50
+ <div>
51
+ <h3 className="text-sm font-semibold">Allowed Tools</h3>
52
+ <p className="text-muted-foreground mt-1 text-sm">{skill.allowedTools}</p>
48
53
  </div>
54
+ </>
55
+ ) : null}
49
56
 
50
- {/* Allowed Tools */}
51
- {skill.allowedTools ? (
52
- <>
53
- <Separator className="my-4" />
54
- <div>
55
- <h3 className="text-sm font-semibold">Allowed Tools</h3>
56
- <p className="text-muted-foreground mt-1 text-sm">{skill.allowedTools}</p>
57
- </div>
58
- </>
59
- ) : null}
60
-
61
- {/* Resources */}
62
- {skill.resources.length > 0 ? (
63
- <>
64
- <Separator className="my-4" />
65
- <div>
66
- <h3 className="text-sm font-semibold">Resources</h3>
67
- <ul className="mt-2 space-y-1.5">
68
- {skill.resources.map((resource) => (
69
- <li
70
- key={resource.name}
71
- className="text-muted-foreground flex items-center gap-2 text-sm"
72
- >
73
- <FolderOpen className="size-3.5 shrink-0" />
74
- <span>
75
- {resource.name}/ — {resource.fileCount}{' '}
76
- {resource.fileCount === 1 ? 'file' : 'files'}
77
- </span>
78
- </li>
79
- ))}
80
- </ul>
81
- </div>
82
- </>
83
- ) : null}
57
+ {/* Resources */}
58
+ {skill.resources.length > 0 ? (
59
+ <>
60
+ <Separator className="my-4" />
61
+ <div>
62
+ <h3 className="text-sm font-semibold">Resources</h3>
63
+ <ul className="mt-2 space-y-1.5">
64
+ {skill.resources.map((resource) => (
65
+ <li
66
+ key={resource.name}
67
+ className="text-muted-foreground flex items-center gap-2 text-sm"
68
+ >
69
+ <FolderOpen className="size-3.5 shrink-0" />
70
+ <span>
71
+ {resource.name}/ {resource.fileCount}{' '}
72
+ {resource.fileCount === 1 ? 'file' : 'files'}
73
+ </span>
74
+ </li>
75
+ ))}
76
+ </ul>
77
+ </div>
78
+ </>
79
+ ) : null}
84
80
 
85
- {/* Body */}
86
- {skill.body ? (
87
- <>
88
- <Separator className="my-4" />
89
- <pre className="text-muted-foreground text-sm leading-relaxed whitespace-pre-wrap">
90
- {skill.body}
91
- </pre>
92
- </>
93
- ) : null}
94
- </ScrollArea>
95
- </>
96
- ) : null}
97
- </SheetContent>
98
- </Sheet>
81
+ {/* Body */}
82
+ {skill.body ? (
83
+ <>
84
+ <Separator className="my-4" />
85
+ <pre className="text-muted-foreground text-sm leading-relaxed whitespace-pre-wrap">
86
+ {skill.body}
87
+ </pre>
88
+ </>
89
+ ) : null}
90
+ </div>
91
+ ) : null}
92
+ </BaseDrawer>
99
93
  );
100
94
  }