prjct-cli 0.18.2 → 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 (243) hide show
  1. package/CHANGELOG.md +40 -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/commands/done.md +57 -258
  11. package/templates/commands/now.md +72 -277
  12. package/templates/commands/ship.md +55 -261
  13. package/templates/commands/test.md +328 -21
  14. package/templates/global/CLAUDE.md +40 -205
  15. package/templates/global/docs/agents.md +88 -0
  16. package/templates/global/docs/architecture.md +103 -0
  17. package/templates/global/docs/commands.md +98 -0
  18. package/templates/global/docs/validation.md +95 -0
  19. package/templates/mcp-config.json +36 -0
  20. package/bin/dev.js +0 -216
  21. package/bin/serve.js +0 -361
  22. package/packages/web/README.md +0 -36
  23. package/packages/web/app/api/claude/sessions/route.ts +0 -44
  24. package/packages/web/app/api/claude/status/route.ts +0 -34
  25. package/packages/web/app/api/projects/[id]/icon/route.ts +0 -33
  26. package/packages/web/app/api/projects/[id]/momentum/route.ts +0 -257
  27. package/packages/web/app/api/projects/[id]/route.ts +0 -29
  28. package/packages/web/app/api/projects/[id]/stats/route.ts +0 -41
  29. package/packages/web/app/api/projects/[id]/status/route.ts +0 -21
  30. package/packages/web/app/api/projects/route.ts +0 -16
  31. package/packages/web/app/api/sessions/current/route.ts +0 -132
  32. package/packages/web/app/api/sessions/history/route.ts +0 -204
  33. package/packages/web/app/error.tsx +0 -34
  34. package/packages/web/app/favicon.ico +0 -0
  35. package/packages/web/app/globals.css +0 -198
  36. package/packages/web/app/layout.tsx +0 -53
  37. package/packages/web/app/loading.tsx +0 -7
  38. package/packages/web/app/not-found.tsx +0 -25
  39. package/packages/web/app/page.tsx +0 -12
  40. package/packages/web/app/project/[id]/code/layout.tsx +0 -18
  41. package/packages/web/app/project/[id]/code/page.tsx +0 -408
  42. package/packages/web/app/project/[id]/error.tsx +0 -41
  43. package/packages/web/app/project/[id]/loading.tsx +0 -9
  44. package/packages/web/app/project/[id]/not-found.tsx +0 -27
  45. package/packages/web/app/project/[id]/page.tsx +0 -384
  46. package/packages/web/app/project/[id]/reports/page.tsx +0 -59
  47. package/packages/web/app/project/[id]/reports/print/page.tsx +0 -58
  48. package/packages/web/app/sessions/page.tsx +0 -165
  49. package/packages/web/app/settings/page.tsx +0 -151
  50. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +0 -2
  51. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -49
  52. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +0 -8
  53. package/packages/web/components/ActivityTimeline/hooks/index.ts +0 -2
  54. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +0 -9
  55. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +0 -23
  56. package/packages/web/components/ActivityTimeline/index.ts +0 -2
  57. package/packages/web/components/AgentsCard/AgentsCard.tsx +0 -93
  58. package/packages/web/components/AgentsCard/AgentsCard.types.ts +0 -14
  59. package/packages/web/components/AgentsCard/index.ts +0 -2
  60. package/packages/web/components/AppSidebar/AppSidebar.tsx +0 -316
  61. package/packages/web/components/AppSidebar/index.ts +0 -1
  62. package/packages/web/components/BackLink/BackLink.tsx +0 -18
  63. package/packages/web/components/BackLink/BackLink.types.ts +0 -5
  64. package/packages/web/components/BackLink/index.ts +0 -2
  65. package/packages/web/components/BentoCard/BentoCard.constants.ts +0 -16
  66. package/packages/web/components/BentoCard/BentoCard.tsx +0 -48
  67. package/packages/web/components/BentoCard/BentoCard.types.ts +0 -15
  68. package/packages/web/components/BentoCard/index.ts +0 -2
  69. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +0 -9
  70. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +0 -18
  71. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +0 -5
  72. package/packages/web/components/BentoCardSkeleton/index.ts +0 -2
  73. package/packages/web/components/BentoGrid/BentoGrid.tsx +0 -18
  74. package/packages/web/components/BentoGrid/BentoGrid.types.ts +0 -4
  75. package/packages/web/components/BentoGrid/index.ts +0 -2
  76. package/packages/web/components/BlockersCard/BlockersCard.tsx +0 -75
  77. package/packages/web/components/BlockersCard/BlockersCard.types.ts +0 -12
  78. package/packages/web/components/BlockersCard/index.ts +0 -2
  79. package/packages/web/components/CommandBar/CommandBar.tsx +0 -67
  80. package/packages/web/components/CommandBar/index.ts +0 -1
  81. package/packages/web/components/CommandButton/CommandButton.tsx +0 -46
  82. package/packages/web/components/CommandButton/index.ts +0 -1
  83. package/packages/web/components/ConnectionStatus/ConnectionStatus.tsx +0 -29
  84. package/packages/web/components/ConnectionStatus/index.ts +0 -1
  85. package/packages/web/components/DashboardContent/DashboardContent.tsx +0 -284
  86. package/packages/web/components/DashboardContent/index.ts +0 -1
  87. package/packages/web/components/DateGroup/DateGroup.tsx +0 -18
  88. package/packages/web/components/DateGroup/DateGroup.types.ts +0 -6
  89. package/packages/web/components/DateGroup/DateGroup.utils.ts +0 -11
  90. package/packages/web/components/DateGroup/index.ts +0 -2
  91. package/packages/web/components/EmptyState/EmptyState.tsx +0 -76
  92. package/packages/web/components/EmptyState/EmptyState.types.ts +0 -11
  93. package/packages/web/components/EmptyState/index.ts +0 -2
  94. package/packages/web/components/EventRow/EventRow.constants.ts +0 -10
  95. package/packages/web/components/EventRow/EventRow.tsx +0 -49
  96. package/packages/web/components/EventRow/EventRow.types.ts +0 -7
  97. package/packages/web/components/EventRow/EventRow.utils.ts +0 -49
  98. package/packages/web/components/EventRow/index.ts +0 -2
  99. package/packages/web/components/ExpandButton/ExpandButton.tsx +0 -18
  100. package/packages/web/components/ExpandButton/ExpandButton.types.ts +0 -6
  101. package/packages/web/components/ExpandButton/index.ts +0 -2
  102. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +0 -14
  103. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +0 -5
  104. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +0 -13
  105. package/packages/web/components/HealthGradientBackground/index.ts +0 -2
  106. package/packages/web/components/HeroSection/HeroSection.tsx +0 -92
  107. package/packages/web/components/HeroSection/HeroSection.types.ts +0 -14
  108. package/packages/web/components/HeroSection/HeroSection.utils.ts +0 -11
  109. package/packages/web/components/HeroSection/hooks/index.ts +0 -2
  110. package/packages/web/components/HeroSection/hooks/useCountUp.ts +0 -45
  111. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +0 -18
  112. package/packages/web/components/HeroSection/index.ts +0 -2
  113. package/packages/web/components/IdeasCard/IdeasCard.tsx +0 -115
  114. package/packages/web/components/IdeasCard/IdeasCard.types.ts +0 -10
  115. package/packages/web/components/IdeasCard/index.ts +0 -2
  116. package/packages/web/components/InsightMessage/InsightMessage.tsx +0 -9
  117. package/packages/web/components/InsightMessage/InsightMessage.types.ts +0 -3
  118. package/packages/web/components/InsightMessage/index.ts +0 -2
  119. package/packages/web/components/Logo/Logo.tsx +0 -65
  120. package/packages/web/components/Logo/index.ts +0 -1
  121. package/packages/web/components/MarkdownContent/MarkdownContent.tsx +0 -123
  122. package/packages/web/components/MarkdownContent/index.ts +0 -1
  123. package/packages/web/components/MasonryGrid/MasonryGrid.tsx +0 -18
  124. package/packages/web/components/MasonryGrid/index.ts +0 -1
  125. package/packages/web/components/MomentumWidget/MomentumWidget.tsx +0 -119
  126. package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +0 -16
  127. package/packages/web/components/MomentumWidget/index.ts +0 -2
  128. package/packages/web/components/NowCard/NowCard.tsx +0 -118
  129. package/packages/web/components/NowCard/NowCard.types.ts +0 -16
  130. package/packages/web/components/NowCard/index.ts +0 -2
  131. package/packages/web/components/PageHeader/PageHeader.tsx +0 -24
  132. package/packages/web/components/PageHeader/index.ts +0 -1
  133. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +0 -20
  134. package/packages/web/components/ProgressRing/ProgressRing.tsx +0 -51
  135. package/packages/web/components/ProgressRing/ProgressRing.types.ts +0 -11
  136. package/packages/web/components/ProgressRing/index.ts +0 -2
  137. package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +0 -54
  138. package/packages/web/components/ProjectAvatar/index.ts +0 -1
  139. package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +0 -37
  140. package/packages/web/components/ProjectColorDot/index.ts +0 -1
  141. package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +0 -104
  142. package/packages/web/components/ProjectSelectorModal/index.ts +0 -1
  143. package/packages/web/components/Providers/Providers.tsx +0 -48
  144. package/packages/web/components/Providers/index.ts +0 -1
  145. package/packages/web/components/QueueCard/QueueCard.tsx +0 -125
  146. package/packages/web/components/QueueCard/QueueCard.types.ts +0 -12
  147. package/packages/web/components/QueueCard/QueueCard.utils.ts +0 -12
  148. package/packages/web/components/QueueCard/index.ts +0 -2
  149. package/packages/web/components/RecoverCard/RecoverCard.tsx +0 -72
  150. package/packages/web/components/RecoverCard/RecoverCard.types.ts +0 -16
  151. package/packages/web/components/RecoverCard/index.ts +0 -2
  152. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +0 -145
  153. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +0 -16
  154. package/packages/web/components/RoadmapCard/index.ts +0 -2
  155. package/packages/web/components/ShipsCard/ShipsCard.tsx +0 -95
  156. package/packages/web/components/ShipsCard/ShipsCard.types.ts +0 -14
  157. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +0 -4
  158. package/packages/web/components/ShipsCard/index.ts +0 -2
  159. package/packages/web/components/SparklineChart/SparklineChart.tsx +0 -40
  160. package/packages/web/components/SparklineChart/SparklineChart.types.ts +0 -6
  161. package/packages/web/components/SparklineChart/index.ts +0 -2
  162. package/packages/web/components/StatsMasonry/StatsMasonry.tsx +0 -95
  163. package/packages/web/components/StatsMasonry/index.ts +0 -1
  164. package/packages/web/components/StreakCard/StreakCard.constants.ts +0 -2
  165. package/packages/web/components/StreakCard/StreakCard.tsx +0 -55
  166. package/packages/web/components/StreakCard/StreakCard.types.ts +0 -4
  167. package/packages/web/components/StreakCard/index.ts +0 -2
  168. package/packages/web/components/TasksCounter/TasksCounter.tsx +0 -14
  169. package/packages/web/components/TasksCounter/TasksCounter.types.ts +0 -3
  170. package/packages/web/components/TasksCounter/index.ts +0 -2
  171. package/packages/web/components/TechStackBadges/TechStackBadges.tsx +0 -28
  172. package/packages/web/components/TechStackBadges/index.ts +0 -1
  173. package/packages/web/components/TerminalDock/DockToggleTab.tsx +0 -29
  174. package/packages/web/components/TerminalDock/TerminalDock.tsx +0 -386
  175. package/packages/web/components/TerminalDock/TerminalDockTab.tsx +0 -130
  176. package/packages/web/components/TerminalDock/TerminalTabBar.tsx +0 -142
  177. package/packages/web/components/TerminalDock/index.ts +0 -2
  178. package/packages/web/components/TerminalTabs/TerminalTab.tsx +0 -95
  179. package/packages/web/components/TerminalTabs/TerminalTabs.tsx +0 -211
  180. package/packages/web/components/TerminalTabs/index.ts +0 -1
  181. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +0 -32
  182. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +0 -3
  183. package/packages/web/components/VelocityBadge/index.ts +0 -2
  184. package/packages/web/components/VelocityCard/VelocityCard.tsx +0 -73
  185. package/packages/web/components/VelocityCard/VelocityCard.types.ts +0 -7
  186. package/packages/web/components/VelocityCard/index.ts +0 -2
  187. package/packages/web/components/WeeklyReports/PrintableReport.tsx +0 -259
  188. package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +0 -187
  189. package/packages/web/components/WeeklyReports/WeekCalendar.tsx +0 -288
  190. package/packages/web/components/WeeklyReports/WeeklyReports.tsx +0 -149
  191. package/packages/web/components/WeeklyReports/index.ts +0 -4
  192. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +0 -25
  193. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +0 -4
  194. package/packages/web/components/WeeklySparkline/index.ts +0 -2
  195. package/packages/web/components/charts/SessionsChart.tsx +0 -175
  196. package/packages/web/components/ui/alert-dialog.tsx +0 -157
  197. package/packages/web/components/ui/badge.tsx +0 -46
  198. package/packages/web/components/ui/button.tsx +0 -60
  199. package/packages/web/components/ui/card.tsx +0 -92
  200. package/packages/web/components/ui/chart.tsx +0 -385
  201. package/packages/web/components/ui/dialog.tsx +0 -143
  202. package/packages/web/components/ui/drawer.tsx +0 -135
  203. package/packages/web/components/ui/dropdown-menu.tsx +0 -257
  204. package/packages/web/components/ui/input.tsx +0 -21
  205. package/packages/web/components/ui/scroll-area.tsx +0 -58
  206. package/packages/web/components/ui/select.tsx +0 -187
  207. package/packages/web/components/ui/sheet.tsx +0 -139
  208. package/packages/web/components/ui/tabs.tsx +0 -66
  209. package/packages/web/components/ui/tooltip.tsx +0 -61
  210. package/packages/web/components.json +0 -22
  211. package/packages/web/context/GlobalTerminalContext.tsx +0 -538
  212. package/packages/web/context/TerminalContext.tsx +0 -45
  213. package/packages/web/context/TerminalTabsContext.tsx +0 -181
  214. package/packages/web/eslint.config.mjs +0 -18
  215. package/packages/web/hooks/useClaudeTerminal.ts +0 -425
  216. package/packages/web/hooks/useProjectStats.ts +0 -93
  217. package/packages/web/hooks/useProjects.ts +0 -73
  218. package/packages/web/lib/actions/projects.ts +0 -15
  219. package/packages/web/lib/commands.ts +0 -81
  220. package/packages/web/lib/format.ts +0 -23
  221. package/packages/web/lib/generate-week-report.ts +0 -285
  222. package/packages/web/lib/parse-prjct-files.ts +0 -1123
  223. package/packages/web/lib/project-colors.ts +0 -58
  224. package/packages/web/lib/projects.ts +0 -506
  225. package/packages/web/lib/pty.ts +0 -101
  226. package/packages/web/lib/query-config.ts +0 -44
  227. package/packages/web/lib/services/index.ts +0 -9
  228. package/packages/web/lib/services/projects.server.ts +0 -66
  229. package/packages/web/lib/services/stats.server.ts +0 -562
  230. package/packages/web/lib/unified-loader.ts +0 -396
  231. package/packages/web/lib/utils.ts +0 -6
  232. package/packages/web/next-env.d.ts +0 -6
  233. package/packages/web/next.config.ts +0 -7
  234. package/packages/web/package.json +0 -57
  235. package/packages/web/postcss.config.mjs +0 -7
  236. package/packages/web/public/file.svg +0 -1
  237. package/packages/web/public/globe.svg +0 -1
  238. package/packages/web/public/next.svg +0 -1
  239. package/packages/web/public/vercel.svg +0 -1
  240. package/packages/web/public/window.svg +0 -1
  241. package/packages/web/server.ts +0 -312
  242. package/packages/web/tsconfig.json +0 -34
  243. 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
- }