prjct-cli 0.18.1 → 0.19.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 (245) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/CLAUDE.md +74 -211
  3. package/core/agentic/prompt-builder.ts +3 -7
  4. package/core/command-registry/optional-commands.ts +0 -20
  5. package/core/infrastructure/command-installer/command-installer.ts +8 -1
  6. package/core/infrastructure/command-installer/global-config.ts +31 -1
  7. package/core/infrastructure/command-installer/index.ts +1 -1
  8. package/core/infrastructure/setup.ts +3 -0
  9. package/package.json +3 -17
  10. package/templates/agentic/subagent-generation.md +8 -6
  11. package/templates/commands/done.md +57 -258
  12. package/templates/commands/now.md +72 -277
  13. package/templates/commands/ship.md +55 -261
  14. package/templates/commands/sync.md +7 -7
  15. package/templates/commands/test.md +328 -21
  16. package/templates/global/CLAUDE.md +40 -205
  17. package/templates/global/docs/agents.md +88 -0
  18. package/templates/global/docs/architecture.md +103 -0
  19. package/templates/global/docs/commands.md +98 -0
  20. package/templates/global/docs/validation.md +95 -0
  21. package/templates/mcp-config.json +36 -0
  22. package/bin/dev.js +0 -216
  23. package/bin/serve.js +0 -361
  24. package/packages/web/README.md +0 -36
  25. package/packages/web/app/api/claude/sessions/route.ts +0 -44
  26. package/packages/web/app/api/claude/status/route.ts +0 -34
  27. package/packages/web/app/api/projects/[id]/icon/route.ts +0 -33
  28. package/packages/web/app/api/projects/[id]/momentum/route.ts +0 -257
  29. package/packages/web/app/api/projects/[id]/route.ts +0 -29
  30. package/packages/web/app/api/projects/[id]/stats/route.ts +0 -41
  31. package/packages/web/app/api/projects/[id]/status/route.ts +0 -21
  32. package/packages/web/app/api/projects/route.ts +0 -16
  33. package/packages/web/app/api/sessions/current/route.ts +0 -132
  34. package/packages/web/app/api/sessions/history/route.ts +0 -204
  35. package/packages/web/app/error.tsx +0 -34
  36. package/packages/web/app/favicon.ico +0 -0
  37. package/packages/web/app/globals.css +0 -198
  38. package/packages/web/app/layout.tsx +0 -53
  39. package/packages/web/app/loading.tsx +0 -7
  40. package/packages/web/app/not-found.tsx +0 -25
  41. package/packages/web/app/page.tsx +0 -12
  42. package/packages/web/app/project/[id]/code/layout.tsx +0 -18
  43. package/packages/web/app/project/[id]/code/page.tsx +0 -408
  44. package/packages/web/app/project/[id]/error.tsx +0 -41
  45. package/packages/web/app/project/[id]/loading.tsx +0 -9
  46. package/packages/web/app/project/[id]/not-found.tsx +0 -27
  47. package/packages/web/app/project/[id]/page.tsx +0 -384
  48. package/packages/web/app/project/[id]/reports/page.tsx +0 -59
  49. package/packages/web/app/project/[id]/reports/print/page.tsx +0 -58
  50. package/packages/web/app/sessions/page.tsx +0 -165
  51. package/packages/web/app/settings/page.tsx +0 -151
  52. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +0 -2
  53. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -49
  54. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +0 -8
  55. package/packages/web/components/ActivityTimeline/hooks/index.ts +0 -2
  56. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +0 -9
  57. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +0 -23
  58. package/packages/web/components/ActivityTimeline/index.ts +0 -2
  59. package/packages/web/components/AgentsCard/AgentsCard.tsx +0 -93
  60. package/packages/web/components/AgentsCard/AgentsCard.types.ts +0 -14
  61. package/packages/web/components/AgentsCard/index.ts +0 -2
  62. package/packages/web/components/AppSidebar/AppSidebar.tsx +0 -316
  63. package/packages/web/components/AppSidebar/index.ts +0 -1
  64. package/packages/web/components/BackLink/BackLink.tsx +0 -18
  65. package/packages/web/components/BackLink/BackLink.types.ts +0 -5
  66. package/packages/web/components/BackLink/index.ts +0 -2
  67. package/packages/web/components/BentoCard/BentoCard.constants.ts +0 -16
  68. package/packages/web/components/BentoCard/BentoCard.tsx +0 -48
  69. package/packages/web/components/BentoCard/BentoCard.types.ts +0 -15
  70. package/packages/web/components/BentoCard/index.ts +0 -2
  71. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +0 -9
  72. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +0 -18
  73. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +0 -5
  74. package/packages/web/components/BentoCardSkeleton/index.ts +0 -2
  75. package/packages/web/components/BentoGrid/BentoGrid.tsx +0 -18
  76. package/packages/web/components/BentoGrid/BentoGrid.types.ts +0 -4
  77. package/packages/web/components/BentoGrid/index.ts +0 -2
  78. package/packages/web/components/BlockersCard/BlockersCard.tsx +0 -75
  79. package/packages/web/components/BlockersCard/BlockersCard.types.ts +0 -12
  80. package/packages/web/components/BlockersCard/index.ts +0 -2
  81. package/packages/web/components/CommandBar/CommandBar.tsx +0 -67
  82. package/packages/web/components/CommandBar/index.ts +0 -1
  83. package/packages/web/components/CommandButton/CommandButton.tsx +0 -46
  84. package/packages/web/components/CommandButton/index.ts +0 -1
  85. package/packages/web/components/ConnectionStatus/ConnectionStatus.tsx +0 -29
  86. package/packages/web/components/ConnectionStatus/index.ts +0 -1
  87. package/packages/web/components/DashboardContent/DashboardContent.tsx +0 -284
  88. package/packages/web/components/DashboardContent/index.ts +0 -1
  89. package/packages/web/components/DateGroup/DateGroup.tsx +0 -18
  90. package/packages/web/components/DateGroup/DateGroup.types.ts +0 -6
  91. package/packages/web/components/DateGroup/DateGroup.utils.ts +0 -11
  92. package/packages/web/components/DateGroup/index.ts +0 -2
  93. package/packages/web/components/EmptyState/EmptyState.tsx +0 -76
  94. package/packages/web/components/EmptyState/EmptyState.types.ts +0 -11
  95. package/packages/web/components/EmptyState/index.ts +0 -2
  96. package/packages/web/components/EventRow/EventRow.constants.ts +0 -10
  97. package/packages/web/components/EventRow/EventRow.tsx +0 -49
  98. package/packages/web/components/EventRow/EventRow.types.ts +0 -7
  99. package/packages/web/components/EventRow/EventRow.utils.ts +0 -49
  100. package/packages/web/components/EventRow/index.ts +0 -2
  101. package/packages/web/components/ExpandButton/ExpandButton.tsx +0 -18
  102. package/packages/web/components/ExpandButton/ExpandButton.types.ts +0 -6
  103. package/packages/web/components/ExpandButton/index.ts +0 -2
  104. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +0 -14
  105. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +0 -5
  106. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +0 -13
  107. package/packages/web/components/HealthGradientBackground/index.ts +0 -2
  108. package/packages/web/components/HeroSection/HeroSection.tsx +0 -92
  109. package/packages/web/components/HeroSection/HeroSection.types.ts +0 -14
  110. package/packages/web/components/HeroSection/HeroSection.utils.ts +0 -11
  111. package/packages/web/components/HeroSection/hooks/index.ts +0 -2
  112. package/packages/web/components/HeroSection/hooks/useCountUp.ts +0 -45
  113. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +0 -18
  114. package/packages/web/components/HeroSection/index.ts +0 -2
  115. package/packages/web/components/IdeasCard/IdeasCard.tsx +0 -115
  116. package/packages/web/components/IdeasCard/IdeasCard.types.ts +0 -10
  117. package/packages/web/components/IdeasCard/index.ts +0 -2
  118. package/packages/web/components/InsightMessage/InsightMessage.tsx +0 -9
  119. package/packages/web/components/InsightMessage/InsightMessage.types.ts +0 -3
  120. package/packages/web/components/InsightMessage/index.ts +0 -2
  121. package/packages/web/components/Logo/Logo.tsx +0 -65
  122. package/packages/web/components/Logo/index.ts +0 -1
  123. package/packages/web/components/MarkdownContent/MarkdownContent.tsx +0 -123
  124. package/packages/web/components/MarkdownContent/index.ts +0 -1
  125. package/packages/web/components/MasonryGrid/MasonryGrid.tsx +0 -18
  126. package/packages/web/components/MasonryGrid/index.ts +0 -1
  127. package/packages/web/components/MomentumWidget/MomentumWidget.tsx +0 -119
  128. package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +0 -16
  129. package/packages/web/components/MomentumWidget/index.ts +0 -2
  130. package/packages/web/components/NowCard/NowCard.tsx +0 -118
  131. package/packages/web/components/NowCard/NowCard.types.ts +0 -16
  132. package/packages/web/components/NowCard/index.ts +0 -2
  133. package/packages/web/components/PageHeader/PageHeader.tsx +0 -24
  134. package/packages/web/components/PageHeader/index.ts +0 -1
  135. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +0 -20
  136. package/packages/web/components/ProgressRing/ProgressRing.tsx +0 -51
  137. package/packages/web/components/ProgressRing/ProgressRing.types.ts +0 -11
  138. package/packages/web/components/ProgressRing/index.ts +0 -2
  139. package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +0 -54
  140. package/packages/web/components/ProjectAvatar/index.ts +0 -1
  141. package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +0 -37
  142. package/packages/web/components/ProjectColorDot/index.ts +0 -1
  143. package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +0 -104
  144. package/packages/web/components/ProjectSelectorModal/index.ts +0 -1
  145. package/packages/web/components/Providers/Providers.tsx +0 -48
  146. package/packages/web/components/Providers/index.ts +0 -1
  147. package/packages/web/components/QueueCard/QueueCard.tsx +0 -125
  148. package/packages/web/components/QueueCard/QueueCard.types.ts +0 -12
  149. package/packages/web/components/QueueCard/QueueCard.utils.ts +0 -12
  150. package/packages/web/components/QueueCard/index.ts +0 -2
  151. package/packages/web/components/RecoverCard/RecoverCard.tsx +0 -72
  152. package/packages/web/components/RecoverCard/RecoverCard.types.ts +0 -16
  153. package/packages/web/components/RecoverCard/index.ts +0 -2
  154. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +0 -145
  155. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +0 -16
  156. package/packages/web/components/RoadmapCard/index.ts +0 -2
  157. package/packages/web/components/ShipsCard/ShipsCard.tsx +0 -95
  158. package/packages/web/components/ShipsCard/ShipsCard.types.ts +0 -14
  159. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +0 -4
  160. package/packages/web/components/ShipsCard/index.ts +0 -2
  161. package/packages/web/components/SparklineChart/SparklineChart.tsx +0 -40
  162. package/packages/web/components/SparklineChart/SparklineChart.types.ts +0 -6
  163. package/packages/web/components/SparklineChart/index.ts +0 -2
  164. package/packages/web/components/StatsMasonry/StatsMasonry.tsx +0 -95
  165. package/packages/web/components/StatsMasonry/index.ts +0 -1
  166. package/packages/web/components/StreakCard/StreakCard.constants.ts +0 -2
  167. package/packages/web/components/StreakCard/StreakCard.tsx +0 -55
  168. package/packages/web/components/StreakCard/StreakCard.types.ts +0 -4
  169. package/packages/web/components/StreakCard/index.ts +0 -2
  170. package/packages/web/components/TasksCounter/TasksCounter.tsx +0 -14
  171. package/packages/web/components/TasksCounter/TasksCounter.types.ts +0 -3
  172. package/packages/web/components/TasksCounter/index.ts +0 -2
  173. package/packages/web/components/TechStackBadges/TechStackBadges.tsx +0 -28
  174. package/packages/web/components/TechStackBadges/index.ts +0 -1
  175. package/packages/web/components/TerminalDock/DockToggleTab.tsx +0 -29
  176. package/packages/web/components/TerminalDock/TerminalDock.tsx +0 -386
  177. package/packages/web/components/TerminalDock/TerminalDockTab.tsx +0 -130
  178. package/packages/web/components/TerminalDock/TerminalTabBar.tsx +0 -142
  179. package/packages/web/components/TerminalDock/index.ts +0 -2
  180. package/packages/web/components/TerminalTabs/TerminalTab.tsx +0 -95
  181. package/packages/web/components/TerminalTabs/TerminalTabs.tsx +0 -211
  182. package/packages/web/components/TerminalTabs/index.ts +0 -1
  183. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +0 -32
  184. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +0 -3
  185. package/packages/web/components/VelocityBadge/index.ts +0 -2
  186. package/packages/web/components/VelocityCard/VelocityCard.tsx +0 -73
  187. package/packages/web/components/VelocityCard/VelocityCard.types.ts +0 -7
  188. package/packages/web/components/VelocityCard/index.ts +0 -2
  189. package/packages/web/components/WeeklyReports/PrintableReport.tsx +0 -259
  190. package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +0 -187
  191. package/packages/web/components/WeeklyReports/WeekCalendar.tsx +0 -288
  192. package/packages/web/components/WeeklyReports/WeeklyReports.tsx +0 -149
  193. package/packages/web/components/WeeklyReports/index.ts +0 -4
  194. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +0 -25
  195. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +0 -4
  196. package/packages/web/components/WeeklySparkline/index.ts +0 -2
  197. package/packages/web/components/charts/SessionsChart.tsx +0 -175
  198. package/packages/web/components/ui/alert-dialog.tsx +0 -157
  199. package/packages/web/components/ui/badge.tsx +0 -46
  200. package/packages/web/components/ui/button.tsx +0 -60
  201. package/packages/web/components/ui/card.tsx +0 -92
  202. package/packages/web/components/ui/chart.tsx +0 -385
  203. package/packages/web/components/ui/dialog.tsx +0 -143
  204. package/packages/web/components/ui/drawer.tsx +0 -135
  205. package/packages/web/components/ui/dropdown-menu.tsx +0 -257
  206. package/packages/web/components/ui/input.tsx +0 -21
  207. package/packages/web/components/ui/scroll-area.tsx +0 -58
  208. package/packages/web/components/ui/select.tsx +0 -187
  209. package/packages/web/components/ui/sheet.tsx +0 -139
  210. package/packages/web/components/ui/tabs.tsx +0 -66
  211. package/packages/web/components/ui/tooltip.tsx +0 -61
  212. package/packages/web/components.json +0 -22
  213. package/packages/web/context/GlobalTerminalContext.tsx +0 -538
  214. package/packages/web/context/TerminalContext.tsx +0 -45
  215. package/packages/web/context/TerminalTabsContext.tsx +0 -181
  216. package/packages/web/eslint.config.mjs +0 -18
  217. package/packages/web/hooks/useClaudeTerminal.ts +0 -425
  218. package/packages/web/hooks/useProjectStats.ts +0 -93
  219. package/packages/web/hooks/useProjects.ts +0 -73
  220. package/packages/web/lib/actions/projects.ts +0 -15
  221. package/packages/web/lib/commands.ts +0 -81
  222. package/packages/web/lib/format.ts +0 -23
  223. package/packages/web/lib/generate-week-report.ts +0 -285
  224. package/packages/web/lib/parse-prjct-files.ts +0 -1123
  225. package/packages/web/lib/project-colors.ts +0 -58
  226. package/packages/web/lib/projects.ts +0 -506
  227. package/packages/web/lib/pty.ts +0 -101
  228. package/packages/web/lib/query-config.ts +0 -44
  229. package/packages/web/lib/services/index.ts +0 -9
  230. package/packages/web/lib/services/projects.server.ts +0 -66
  231. package/packages/web/lib/services/stats.server.ts +0 -562
  232. package/packages/web/lib/unified-loader.ts +0 -396
  233. package/packages/web/lib/utils.ts +0 -6
  234. package/packages/web/next-env.d.ts +0 -6
  235. package/packages/web/next.config.ts +0 -7
  236. package/packages/web/package.json +0 -57
  237. package/packages/web/postcss.config.mjs +0 -7
  238. package/packages/web/public/file.svg +0 -1
  239. package/packages/web/public/globe.svg +0 -1
  240. package/packages/web/public/next.svg +0 -1
  241. package/packages/web/public/vercel.svg +0 -1
  242. package/packages/web/public/window.svg +0 -1
  243. package/packages/web/server.ts +0 -312
  244. package/packages/web/tsconfig.json +0 -34
  245. package/templates/commands/serve.md +0 -121
@@ -1,408 +0,0 @@
1
- 'use client'
2
-
3
- import { useState, use, useEffect, useRef, useCallback } from 'react'
4
- import { useRouter, useSearchParams } from 'next/navigation'
5
- import { useProject, useDeleteProject } from '@/hooks/useProjects'
6
- import { useGlobalTerminal } from '@/context/GlobalTerminalContext'
7
- import { TerminalDockTab } from '@/components/TerminalDock/TerminalDockTab'
8
- import { TerminalTabBar } from '@/components/TerminalDock/TerminalTabBar'
9
- import { CommandBar } from '@/components/CommandBar'
10
- import { Button } from '@/components/ui/button'
11
- import { Badge } from '@/components/ui/badge'
12
- import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'
13
- import {
14
- AlertDialog,
15
- AlertDialogAction,
16
- AlertDialogCancel,
17
- AlertDialogContent,
18
- AlertDialogDescription,
19
- AlertDialogFooter,
20
- AlertDialogHeader,
21
- AlertDialogTitle,
22
- } from '@/components/ui/alert-dialog'
23
- import { ProjectAvatar } from '@/components/ProjectAvatar'
24
- import { TechStackBadges } from '@/components/TechStackBadges'
25
- import { MomentumWidget } from '@/components/MomentumWidget'
26
- import { formatPath } from '@/lib/format'
27
- import {
28
- Panel,
29
- PanelGroup,
30
- PanelResizeHandle,
31
- } from 'react-resizable-panels'
32
- import {
33
- Loader2,
34
- AlertTriangle,
35
- Trash2,
36
- ArrowLeft,
37
- FolderGit2,
38
- Plus,
39
- Terminal,
40
- SplitSquareHorizontal,
41
- Minus,
42
- } from 'lucide-react'
43
- import { cn } from '@/lib/utils'
44
-
45
- // Inner component that uses the terminal context
46
- function ProjectPageContent({ projectId, project }: { projectId: string; project: NonNullable<ReturnType<typeof useProject>['data']> }) {
47
- const router = useRouter()
48
- const searchParams = useSearchParams()
49
- const commandExecutedRef = useRef(false)
50
-
51
- // Global terminal context
52
- const {
53
- activeSessionId,
54
- secondActiveSessionId,
55
- isSplitEnabled,
56
- setSplitEnabled,
57
- createSessionForProject,
58
- getProjectSessions,
59
- switchSession,
60
- closeSession,
61
- sendCommandToActive,
62
- getActiveSession,
63
- setFullScreen,
64
- getAllSessions,
65
- getLeftPanelSessions,
66
- getRightPanelSessions,
67
- updateSession,
68
- } = useGlobalTerminal()
69
-
70
- const sessions = getProjectSessions(projectId)
71
- const allSessions = getAllSessions()
72
- const activeSession = getActiveSession()
73
- const hasActiveSessions = sessions.length > 0
74
- const isActiveConnected = activeSession?.isConnected ?? false
75
-
76
- const projectPath = project.repoPath || project.path || '/tmp'
77
- const projectName = project.name || projectId
78
-
79
- // Set full-screen mode when entering code page
80
- useEffect(() => {
81
- setFullScreen(true)
82
- return () => setFullScreen(false)
83
- }, [setFullScreen])
84
-
85
- // Handle new terminal - creates session directly in the specified panel
86
- const handleNewTerminal = useCallback((panel: 'left' | 'right' = 'left') => {
87
- createSessionForProject(projectId, projectName, projectPath, panel)
88
- }, [projectId, projectName, projectPath, createSessionForProject])
89
-
90
- // Handle close session
91
- const handleCloseSession = useCallback((sessionId: string) => {
92
- const disconnectKey = `terminal_disconnect_${sessionId}`
93
- const disconnectFn = (window as unknown as Record<string, () => void>)[disconnectKey]
94
- if (disconnectFn) {
95
- disconnectFn()
96
- }
97
- closeSession(sessionId)
98
- }, [closeSession])
99
-
100
- // Handle rename session
101
- const handleRenameSession = useCallback((sessionId: string, newLabel: string) => {
102
- updateSession(sessionId, { label: newLabel })
103
- }, [updateSession])
104
-
105
- // Auto-execute command from URL param (e.g., ?cmd=p.%20done)
106
- useEffect(() => {
107
- const cmd = searchParams.get('cmd')
108
- if (cmd && isActiveConnected && !commandExecutedRef.current) {
109
- commandExecutedRef.current = true
110
- const decoded = decodeURIComponent(cmd)
111
- setTimeout(() => {
112
- sendCommandToActive(decoded)
113
- router.replace(`/project/${projectId}/code`)
114
- }, 500)
115
- }
116
- }, [searchParams, isActiveConnected, sendCommandToActive, router, projectId])
117
-
118
- // Terminal content with split support
119
- const TerminalContent = (
120
- <div className="flex-1 relative overflow-hidden">
121
- {allSessions.length === 0 ? (
122
- <div className="flex flex-col items-center justify-center h-full text-muted-foreground gap-4">
123
- <Terminal className="w-12 h-12 opacity-50" />
124
- <div className="text-center">
125
- <p className="text-lg font-medium">No terminal sessions</p>
126
- <p className="text-sm">Open a terminal to get started</p>
127
- </div>
128
- <button
129
- onClick={() => handleNewTerminal('left')}
130
- className="flex items-center gap-2 px-4 py-2 rounded-lg bg-orange-500 hover:bg-orange-600 text-white transition-colors"
131
- >
132
- <Plus className="w-4 h-4" />
133
- Open Terminal
134
- </button>
135
- </div>
136
- ) : isSplitEnabled ? (
137
- <PanelGroup direction="horizontal">
138
- <Panel defaultSize={50} minSize={20}>
139
- <div className="h-full flex flex-col">
140
- <div className="border-b border-border bg-muted/30">
141
- <TerminalTabBar
142
- sessions={getLeftPanelSessions()}
143
- activeSessionId={activeSessionId}
144
- onSwitchSession={(id) => switchSession(id, 'left')}
145
- onCloseSession={handleCloseSession}
146
- onNewTerminal={() => handleNewTerminal('left')}
147
- onRenameSession={handleRenameSession}
148
- />
149
- </div>
150
- <div className="flex-1 relative">
151
- {getLeftPanelSessions().length > 0 ? (
152
- getLeftPanelSessions().map((session) => (
153
- <TerminalDockTab
154
- key={session.id}
155
- session={session}
156
- isActive={session.id === activeSessionId}
157
- />
158
- ))
159
- ) : (
160
- <div className="absolute inset-0 flex items-center justify-center bg-card/95 text-muted-foreground text-sm">
161
- <button
162
- onClick={() => handleNewTerminal('left')}
163
- className="text-orange-500 hover:text-orange-400 underline"
164
- >
165
- Open terminal in left panel
166
- </button>
167
- </div>
168
- )}
169
- </div>
170
- </div>
171
- </Panel>
172
-
173
- <PanelResizeHandle className="w-1 bg-border hover:bg-orange-500/50 transition-colors" />
174
-
175
- <Panel defaultSize={50} minSize={20}>
176
- <div className="h-full flex flex-col">
177
- <div className="border-b border-border bg-muted/30">
178
- <TerminalTabBar
179
- sessions={getRightPanelSessions()}
180
- activeSessionId={secondActiveSessionId}
181
- onSwitchSession={(id) => switchSession(id, 'right')}
182
- onCloseSession={handleCloseSession}
183
- onNewTerminal={() => handleNewTerminal('right')}
184
- onRenameSession={handleRenameSession}
185
- />
186
- </div>
187
- <div className="flex-1 relative">
188
- {getRightPanelSessions().length > 0 ? (
189
- getRightPanelSessions().map((session) => (
190
- <TerminalDockTab
191
- key={`right-${session.id}`}
192
- session={session}
193
- isActive={session.id === secondActiveSessionId}
194
- />
195
- ))
196
- ) : (
197
- <div className="absolute inset-0 flex items-center justify-center bg-card/95 text-muted-foreground text-sm">
198
- <button
199
- onClick={() => handleNewTerminal('right')}
200
- className="text-orange-500 hover:text-orange-400 underline"
201
- >
202
- Open terminal in right panel
203
- </button>
204
- </div>
205
- )}
206
- </div>
207
- </div>
208
- </Panel>
209
- </PanelGroup>
210
- ) : (
211
- <div className="h-full flex flex-col">
212
- <div className="border-b border-border bg-muted/30">
213
- <TerminalTabBar
214
- sessions={allSessions}
215
- activeSessionId={activeSessionId}
216
- onSwitchSession={(id) => switchSession(id)}
217
- onCloseSession={handleCloseSession}
218
- onNewTerminal={() => handleNewTerminal('left')}
219
- onRenameSession={handleRenameSession}
220
- />
221
- </div>
222
- <div className="flex-1 relative">
223
- {allSessions.map((session) => (
224
- <TerminalDockTab
225
- key={session.id}
226
- session={session}
227
- isActive={session.id === activeSessionId}
228
- />
229
- ))}
230
- </div>
231
- </div>
232
- )}
233
- </div>
234
- )
235
-
236
- return (
237
- <div className="h-full">
238
- <TooltipProvider>
239
- <div className="flex flex-col h-full">
240
- {/* Header - Responsive */}
241
- <header className="h-auto md:h-14 flex flex-col md:flex-row md:items-center justify-between px-3 md:px-4 py-2 md:py-0 border-b border-border bg-card gap-2">
242
- {/* Left: Project info */}
243
- <div className="flex items-center gap-3">
244
- <ProjectAvatar
245
- projectId={projectId}
246
- name={project.name || projectId}
247
- iconPath={project.iconPath}
248
- size="sm"
249
- />
250
- <div className="flex flex-col min-w-0">
251
- <div className="flex items-center gap-2">
252
- <span className="font-bold leading-tight truncate">{project.name || projectId}</span>
253
- {project.version && (
254
- <Badge variant="outline" className="text-[10px] px-1.5 py-0 font-mono shrink-0">
255
- v{project.version}
256
- </Badge>
257
- )}
258
- </div>
259
- {project.repoPath && (
260
- <span className="text-xs text-muted-foreground leading-tight flex items-center gap-1 truncate">
261
- <FolderGit2 className="w-3 h-3 shrink-0" />
262
- <span className="truncate">{formatPath(project.repoPath)}</span>
263
- </span>
264
- )}
265
- </div>
266
- {hasActiveSessions && (
267
- <Badge variant="outline" className="text-green-500 border-green-500/50 shrink-0">
268
- {sessions.filter(s => s.isConnected).length} active
269
- </Badge>
270
- )}
271
- </div>
272
-
273
- {/* Center: Momentum widget - desktop only */}
274
- <div className="hidden md:flex items-center justify-center flex-1">
275
- <MomentumWidget projectId={projectId} />
276
- </div>
277
-
278
- {/* Right: metadata and tech stack - desktop only */}
279
- <div className="hidden md:flex items-center gap-4">
280
- <div className="flex items-center gap-3 text-xs text-muted-foreground">
281
- {project.filesCount && (
282
- <span><span className="font-medium text-foreground">{project.filesCount}</span> files</span>
283
- )}
284
- {project.commitsCount && (
285
- <span><span className="font-medium text-foreground">{project.commitsCount}</span> commits</span>
286
- )}
287
- </div>
288
- <TechStackBadges techStack={project.techStack || []} />
289
- </div>
290
- </header>
291
-
292
- {/* Command bar + actions - SAME AS DOCK */}
293
- <div className="flex items-center justify-between border-b border-border bg-card/95 shrink-0">
294
- <CommandBar isConnected={isActiveConnected} onCommand={sendCommandToActive} />
295
-
296
- {/* Header actions: split toggle, back button */}
297
- <div className="flex items-center gap-1 px-2">
298
- <Tooltip>
299
- <TooltipTrigger asChild>
300
- <button
301
- onClick={() => setSplitEnabled(!isSplitEnabled)}
302
- className={cn(
303
- 'p-1.5 rounded transition-colors',
304
- isSplitEnabled
305
- ? 'bg-accent text-accent-foreground'
306
- : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
307
- )}
308
- >
309
- <SplitSquareHorizontal className="w-4 h-4" />
310
- </button>
311
- </TooltipTrigger>
312
- <TooltipContent>{isSplitEnabled ? 'Single view' : 'Split view'}</TooltipContent>
313
- </Tooltip>
314
-
315
- <Tooltip>
316
- <TooltipTrigger asChild>
317
- <button
318
- onClick={() => router.push(`/project/${projectId}`)}
319
- className="p-1.5 rounded text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
320
- >
321
- <Minus className="w-4 h-4" />
322
- </button>
323
- </TooltipTrigger>
324
- <TooltipContent>Back to project</TooltipContent>
325
- </Tooltip>
326
- </div>
327
- </div>
328
-
329
- {/* Terminal content area */}
330
- {TerminalContent}
331
- </div>
332
- </TooltipProvider>
333
- </div>
334
- )
335
- }
336
-
337
- export default function ProjectPage({ params }: { params: Promise<{ id: string }> }) {
338
- const { id: projectId } = use(params)
339
- const router = useRouter()
340
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
341
-
342
- const { data: project, isLoading: projectLoading } = useProject(projectId)
343
- const deleteMutation = useDeleteProject()
344
-
345
- if (projectLoading) {
346
- return (
347
- <div className="flex items-center justify-center h-full">
348
- <Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
349
- </div>
350
- )
351
- }
352
-
353
- if (!project) {
354
- return (
355
- <div className="flex items-center justify-center h-full p-4">
356
- <div className="text-center space-y-4 max-w-sm">
357
- <div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mx-auto">
358
- <AlertTriangle className="w-8 h-8 text-muted-foreground" />
359
- </div>
360
- <div>
361
- <h2 className="text-lg font-medium">Project not found</h2>
362
- <p className="text-sm text-muted-foreground mt-1 break-all">ID: {projectId}</p>
363
- </div>
364
- <div className="flex flex-col sm:flex-row gap-2 justify-center">
365
- <Button variant="outline" onClick={() => router.push('/')}>
366
- <ArrowLeft className="w-4 h-4 mr-2" />
367
- Back to Dashboard
368
- </Button>
369
- <Button variant="destructive" onClick={() => setShowDeleteConfirm(true)}>
370
- <Trash2 className="w-4 h-4 mr-2" />
371
- Delete from Storage
372
- </Button>
373
- </div>
374
-
375
- <AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
376
- <AlertDialogContent className="max-w-[calc(100vw-2rem)] sm:max-w-lg">
377
- <AlertDialogHeader>
378
- <AlertDialogTitle className="flex items-center gap-2">
379
- <AlertTriangle className="w-5 h-5 text-destructive" />
380
- Delete Project Data?
381
- </AlertDialogTitle>
382
- <AlertDialogDescription>
383
- This will move the project storage to trash.
384
- <br />
385
- <span className="text-muted-foreground text-sm break-all">ID: {projectId}</span>
386
- </AlertDialogDescription>
387
- </AlertDialogHeader>
388
- <AlertDialogFooter className="flex-col sm:flex-row gap-2">
389
- <AlertDialogCancel disabled={deleteMutation.isPending} className="w-full sm:w-auto">
390
- Cancel
391
- </AlertDialogCancel>
392
- <AlertDialogAction
393
- onClick={() => deleteMutation.mutate(projectId, { onSuccess: () => router.push('/') })}
394
- disabled={deleteMutation.isPending}
395
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90 w-full sm:w-auto"
396
- >
397
- {deleteMutation.isPending ? 'Deleting...' : 'Delete'}
398
- </AlertDialogAction>
399
- </AlertDialogFooter>
400
- </AlertDialogContent>
401
- </AlertDialog>
402
- </div>
403
- </div>
404
- )
405
- }
406
-
407
- return <ProjectPageContent projectId={projectId} project={project} />
408
- }
@@ -1,41 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect } from 'react'
4
- import { useRouter } from 'next/navigation'
5
- import { Button } from '@/components/ui/button'
6
- import { AlertTriangle, ArrowLeft } from 'lucide-react'
7
-
8
- export default function ProjectError({
9
- error,
10
- reset,
11
- }: {
12
- error: Error & { digest?: string }
13
- reset: () => void
14
- }) {
15
- const router = useRouter()
16
-
17
- useEffect(() => {
18
- console.error(error)
19
- }, [error])
20
-
21
- return (
22
- <div className="flex items-center justify-center h-full">
23
- <div className="text-center space-y-4">
24
- <div className="w-16 h-16 rounded-full bg-destructive/10 flex items-center justify-center mx-auto">
25
- <AlertTriangle className="w-8 h-8 text-destructive" />
26
- </div>
27
- <div>
28
- <h2 className="text-lg font-medium">Failed to load project</h2>
29
- <p className="text-sm text-muted-foreground mt-1">{error.message}</p>
30
- </div>
31
- <div className="flex gap-2 justify-center">
32
- <Button onClick={() => router.push('/')} variant="outline">
33
- <ArrowLeft className="w-4 h-4 mr-2" />
34
- Dashboard
35
- </Button>
36
- <Button onClick={reset}>Try again</Button>
37
- </div>
38
- </div>
39
- </div>
40
- )
41
- }
@@ -1,9 +0,0 @@
1
- import { Loader2 } from 'lucide-react'
2
-
3
- export default function ProjectLoading() {
4
- return (
5
- <div className="flex items-center justify-center h-full">
6
- <Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
7
- </div>
8
- )
9
- }
@@ -1,27 +0,0 @@
1
- import Link from 'next/link'
2
- import { Button } from '@/components/ui/button'
3
- import { FolderX, ArrowLeft } from 'lucide-react'
4
-
5
- export default function ProjectNotFound() {
6
- return (
7
- <div className="flex items-center justify-center h-full">
8
- <div className="text-center space-y-4">
9
- <div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mx-auto">
10
- <FolderX className="w-8 h-8 text-muted-foreground" />
11
- </div>
12
- <div>
13
- <h2 className="text-lg font-medium">Project not found</h2>
14
- <p className="text-sm text-muted-foreground mt-1">
15
- This project may have been deleted or moved.
16
- </p>
17
- </div>
18
- <Button asChild variant="outline">
19
- <Link href="/">
20
- <ArrowLeft className="w-4 h-4 mr-2" />
21
- Back to Dashboard
22
- </Link>
23
- </Button>
24
- </div>
25
- </div>
26
- )
27
- }