prjct-cli 0.18.2 → 0.20.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 (246) hide show
  1. package/CHANGELOG.md +82 -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/agents/uxui.md +210 -0
  11. package/templates/commands/bug.md +219 -41
  12. package/templates/commands/done.md +57 -258
  13. package/templates/commands/feature.md +368 -80
  14. package/templates/commands/now.md +72 -277
  15. package/templates/commands/ship.md +167 -246
  16. package/templates/commands/sync.md +62 -3
  17. package/templates/commands/test.md +160 -20
  18. package/templates/global/CLAUDE.md +40 -205
  19. package/templates/global/docs/agents.md +88 -0
  20. package/templates/global/docs/architecture.md +103 -0
  21. package/templates/global/docs/commands.md +98 -0
  22. package/templates/global/docs/validation.md +95 -0
  23. package/bin/dev.js +0 -216
  24. package/bin/serve.js +0 -361
  25. package/packages/web/README.md +0 -36
  26. package/packages/web/app/api/claude/sessions/route.ts +0 -44
  27. package/packages/web/app/api/claude/status/route.ts +0 -34
  28. package/packages/web/app/api/projects/[id]/icon/route.ts +0 -33
  29. package/packages/web/app/api/projects/[id]/momentum/route.ts +0 -257
  30. package/packages/web/app/api/projects/[id]/route.ts +0 -29
  31. package/packages/web/app/api/projects/[id]/stats/route.ts +0 -41
  32. package/packages/web/app/api/projects/[id]/status/route.ts +0 -21
  33. package/packages/web/app/api/projects/route.ts +0 -16
  34. package/packages/web/app/api/sessions/current/route.ts +0 -132
  35. package/packages/web/app/api/sessions/history/route.ts +0 -204
  36. package/packages/web/app/error.tsx +0 -34
  37. package/packages/web/app/favicon.ico +0 -0
  38. package/packages/web/app/globals.css +0 -198
  39. package/packages/web/app/layout.tsx +0 -53
  40. package/packages/web/app/loading.tsx +0 -7
  41. package/packages/web/app/not-found.tsx +0 -25
  42. package/packages/web/app/page.tsx +0 -12
  43. package/packages/web/app/project/[id]/code/layout.tsx +0 -18
  44. package/packages/web/app/project/[id]/code/page.tsx +0 -408
  45. package/packages/web/app/project/[id]/error.tsx +0 -41
  46. package/packages/web/app/project/[id]/loading.tsx +0 -9
  47. package/packages/web/app/project/[id]/not-found.tsx +0 -27
  48. package/packages/web/app/project/[id]/page.tsx +0 -384
  49. package/packages/web/app/project/[id]/reports/page.tsx +0 -59
  50. package/packages/web/app/project/[id]/reports/print/page.tsx +0 -58
  51. package/packages/web/app/sessions/page.tsx +0 -165
  52. package/packages/web/app/settings/page.tsx +0 -151
  53. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +0 -2
  54. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +0 -49
  55. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +0 -8
  56. package/packages/web/components/ActivityTimeline/hooks/index.ts +0 -2
  57. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +0 -9
  58. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +0 -23
  59. package/packages/web/components/ActivityTimeline/index.ts +0 -2
  60. package/packages/web/components/AgentsCard/AgentsCard.tsx +0 -93
  61. package/packages/web/components/AgentsCard/AgentsCard.types.ts +0 -14
  62. package/packages/web/components/AgentsCard/index.ts +0 -2
  63. package/packages/web/components/AppSidebar/AppSidebar.tsx +0 -316
  64. package/packages/web/components/AppSidebar/index.ts +0 -1
  65. package/packages/web/components/BackLink/BackLink.tsx +0 -18
  66. package/packages/web/components/BackLink/BackLink.types.ts +0 -5
  67. package/packages/web/components/BackLink/index.ts +0 -2
  68. package/packages/web/components/BentoCard/BentoCard.constants.ts +0 -16
  69. package/packages/web/components/BentoCard/BentoCard.tsx +0 -48
  70. package/packages/web/components/BentoCard/BentoCard.types.ts +0 -15
  71. package/packages/web/components/BentoCard/index.ts +0 -2
  72. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +0 -9
  73. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +0 -18
  74. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +0 -5
  75. package/packages/web/components/BentoCardSkeleton/index.ts +0 -2
  76. package/packages/web/components/BentoGrid/BentoGrid.tsx +0 -18
  77. package/packages/web/components/BentoGrid/BentoGrid.types.ts +0 -4
  78. package/packages/web/components/BentoGrid/index.ts +0 -2
  79. package/packages/web/components/BlockersCard/BlockersCard.tsx +0 -75
  80. package/packages/web/components/BlockersCard/BlockersCard.types.ts +0 -12
  81. package/packages/web/components/BlockersCard/index.ts +0 -2
  82. package/packages/web/components/CommandBar/CommandBar.tsx +0 -67
  83. package/packages/web/components/CommandBar/index.ts +0 -1
  84. package/packages/web/components/CommandButton/CommandButton.tsx +0 -46
  85. package/packages/web/components/CommandButton/index.ts +0 -1
  86. package/packages/web/components/ConnectionStatus/ConnectionStatus.tsx +0 -29
  87. package/packages/web/components/ConnectionStatus/index.ts +0 -1
  88. package/packages/web/components/DashboardContent/DashboardContent.tsx +0 -284
  89. package/packages/web/components/DashboardContent/index.ts +0 -1
  90. package/packages/web/components/DateGroup/DateGroup.tsx +0 -18
  91. package/packages/web/components/DateGroup/DateGroup.types.ts +0 -6
  92. package/packages/web/components/DateGroup/DateGroup.utils.ts +0 -11
  93. package/packages/web/components/DateGroup/index.ts +0 -2
  94. package/packages/web/components/EmptyState/EmptyState.tsx +0 -76
  95. package/packages/web/components/EmptyState/EmptyState.types.ts +0 -11
  96. package/packages/web/components/EmptyState/index.ts +0 -2
  97. package/packages/web/components/EventRow/EventRow.constants.ts +0 -10
  98. package/packages/web/components/EventRow/EventRow.tsx +0 -49
  99. package/packages/web/components/EventRow/EventRow.types.ts +0 -7
  100. package/packages/web/components/EventRow/EventRow.utils.ts +0 -49
  101. package/packages/web/components/EventRow/index.ts +0 -2
  102. package/packages/web/components/ExpandButton/ExpandButton.tsx +0 -18
  103. package/packages/web/components/ExpandButton/ExpandButton.types.ts +0 -6
  104. package/packages/web/components/ExpandButton/index.ts +0 -2
  105. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +0 -14
  106. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +0 -5
  107. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +0 -13
  108. package/packages/web/components/HealthGradientBackground/index.ts +0 -2
  109. package/packages/web/components/HeroSection/HeroSection.tsx +0 -92
  110. package/packages/web/components/HeroSection/HeroSection.types.ts +0 -14
  111. package/packages/web/components/HeroSection/HeroSection.utils.ts +0 -11
  112. package/packages/web/components/HeroSection/hooks/index.ts +0 -2
  113. package/packages/web/components/HeroSection/hooks/useCountUp.ts +0 -45
  114. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +0 -18
  115. package/packages/web/components/HeroSection/index.ts +0 -2
  116. package/packages/web/components/IdeasCard/IdeasCard.tsx +0 -115
  117. package/packages/web/components/IdeasCard/IdeasCard.types.ts +0 -10
  118. package/packages/web/components/IdeasCard/index.ts +0 -2
  119. package/packages/web/components/InsightMessage/InsightMessage.tsx +0 -9
  120. package/packages/web/components/InsightMessage/InsightMessage.types.ts +0 -3
  121. package/packages/web/components/InsightMessage/index.ts +0 -2
  122. package/packages/web/components/Logo/Logo.tsx +0 -65
  123. package/packages/web/components/Logo/index.ts +0 -1
  124. package/packages/web/components/MarkdownContent/MarkdownContent.tsx +0 -123
  125. package/packages/web/components/MarkdownContent/index.ts +0 -1
  126. package/packages/web/components/MasonryGrid/MasonryGrid.tsx +0 -18
  127. package/packages/web/components/MasonryGrid/index.ts +0 -1
  128. package/packages/web/components/MomentumWidget/MomentumWidget.tsx +0 -119
  129. package/packages/web/components/MomentumWidget/MomentumWidget.types.ts +0 -16
  130. package/packages/web/components/MomentumWidget/index.ts +0 -2
  131. package/packages/web/components/NowCard/NowCard.tsx +0 -118
  132. package/packages/web/components/NowCard/NowCard.types.ts +0 -16
  133. package/packages/web/components/NowCard/index.ts +0 -2
  134. package/packages/web/components/PageHeader/PageHeader.tsx +0 -24
  135. package/packages/web/components/PageHeader/index.ts +0 -1
  136. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +0 -20
  137. package/packages/web/components/ProgressRing/ProgressRing.tsx +0 -51
  138. package/packages/web/components/ProgressRing/ProgressRing.types.ts +0 -11
  139. package/packages/web/components/ProgressRing/index.ts +0 -2
  140. package/packages/web/components/ProjectAvatar/ProjectAvatar.tsx +0 -54
  141. package/packages/web/components/ProjectAvatar/index.ts +0 -1
  142. package/packages/web/components/ProjectColorDot/ProjectColorDot.tsx +0 -37
  143. package/packages/web/components/ProjectColorDot/index.ts +0 -1
  144. package/packages/web/components/ProjectSelectorModal/ProjectSelectorModal.tsx +0 -104
  145. package/packages/web/components/ProjectSelectorModal/index.ts +0 -1
  146. package/packages/web/components/Providers/Providers.tsx +0 -48
  147. package/packages/web/components/Providers/index.ts +0 -1
  148. package/packages/web/components/QueueCard/QueueCard.tsx +0 -125
  149. package/packages/web/components/QueueCard/QueueCard.types.ts +0 -12
  150. package/packages/web/components/QueueCard/QueueCard.utils.ts +0 -12
  151. package/packages/web/components/QueueCard/index.ts +0 -2
  152. package/packages/web/components/RecoverCard/RecoverCard.tsx +0 -72
  153. package/packages/web/components/RecoverCard/RecoverCard.types.ts +0 -16
  154. package/packages/web/components/RecoverCard/index.ts +0 -2
  155. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +0 -145
  156. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +0 -16
  157. package/packages/web/components/RoadmapCard/index.ts +0 -2
  158. package/packages/web/components/ShipsCard/ShipsCard.tsx +0 -95
  159. package/packages/web/components/ShipsCard/ShipsCard.types.ts +0 -14
  160. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +0 -4
  161. package/packages/web/components/ShipsCard/index.ts +0 -2
  162. package/packages/web/components/SparklineChart/SparklineChart.tsx +0 -40
  163. package/packages/web/components/SparklineChart/SparklineChart.types.ts +0 -6
  164. package/packages/web/components/SparklineChart/index.ts +0 -2
  165. package/packages/web/components/StatsMasonry/StatsMasonry.tsx +0 -95
  166. package/packages/web/components/StatsMasonry/index.ts +0 -1
  167. package/packages/web/components/StreakCard/StreakCard.constants.ts +0 -2
  168. package/packages/web/components/StreakCard/StreakCard.tsx +0 -55
  169. package/packages/web/components/StreakCard/StreakCard.types.ts +0 -4
  170. package/packages/web/components/StreakCard/index.ts +0 -2
  171. package/packages/web/components/TasksCounter/TasksCounter.tsx +0 -14
  172. package/packages/web/components/TasksCounter/TasksCounter.types.ts +0 -3
  173. package/packages/web/components/TasksCounter/index.ts +0 -2
  174. package/packages/web/components/TechStackBadges/TechStackBadges.tsx +0 -28
  175. package/packages/web/components/TechStackBadges/index.ts +0 -1
  176. package/packages/web/components/TerminalDock/DockToggleTab.tsx +0 -29
  177. package/packages/web/components/TerminalDock/TerminalDock.tsx +0 -386
  178. package/packages/web/components/TerminalDock/TerminalDockTab.tsx +0 -130
  179. package/packages/web/components/TerminalDock/TerminalTabBar.tsx +0 -142
  180. package/packages/web/components/TerminalDock/index.ts +0 -2
  181. package/packages/web/components/TerminalTabs/TerminalTab.tsx +0 -95
  182. package/packages/web/components/TerminalTabs/TerminalTabs.tsx +0 -211
  183. package/packages/web/components/TerminalTabs/index.ts +0 -1
  184. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +0 -32
  185. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +0 -3
  186. package/packages/web/components/VelocityBadge/index.ts +0 -2
  187. package/packages/web/components/VelocityCard/VelocityCard.tsx +0 -73
  188. package/packages/web/components/VelocityCard/VelocityCard.types.ts +0 -7
  189. package/packages/web/components/VelocityCard/index.ts +0 -2
  190. package/packages/web/components/WeeklyReports/PrintableReport.tsx +0 -259
  191. package/packages/web/components/WeeklyReports/ReportPreviewCard.tsx +0 -187
  192. package/packages/web/components/WeeklyReports/WeekCalendar.tsx +0 -288
  193. package/packages/web/components/WeeklyReports/WeeklyReports.tsx +0 -149
  194. package/packages/web/components/WeeklyReports/index.ts +0 -4
  195. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +0 -25
  196. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +0 -4
  197. package/packages/web/components/WeeklySparkline/index.ts +0 -2
  198. package/packages/web/components/charts/SessionsChart.tsx +0 -175
  199. package/packages/web/components/ui/alert-dialog.tsx +0 -157
  200. package/packages/web/components/ui/badge.tsx +0 -46
  201. package/packages/web/components/ui/button.tsx +0 -60
  202. package/packages/web/components/ui/card.tsx +0 -92
  203. package/packages/web/components/ui/chart.tsx +0 -385
  204. package/packages/web/components/ui/dialog.tsx +0 -143
  205. package/packages/web/components/ui/drawer.tsx +0 -135
  206. package/packages/web/components/ui/dropdown-menu.tsx +0 -257
  207. package/packages/web/components/ui/input.tsx +0 -21
  208. package/packages/web/components/ui/scroll-area.tsx +0 -58
  209. package/packages/web/components/ui/select.tsx +0 -187
  210. package/packages/web/components/ui/sheet.tsx +0 -139
  211. package/packages/web/components/ui/tabs.tsx +0 -66
  212. package/packages/web/components/ui/tooltip.tsx +0 -61
  213. package/packages/web/components.json +0 -22
  214. package/packages/web/context/GlobalTerminalContext.tsx +0 -538
  215. package/packages/web/context/TerminalContext.tsx +0 -45
  216. package/packages/web/context/TerminalTabsContext.tsx +0 -181
  217. package/packages/web/eslint.config.mjs +0 -18
  218. package/packages/web/hooks/useClaudeTerminal.ts +0 -425
  219. package/packages/web/hooks/useProjectStats.ts +0 -93
  220. package/packages/web/hooks/useProjects.ts +0 -73
  221. package/packages/web/lib/actions/projects.ts +0 -15
  222. package/packages/web/lib/commands.ts +0 -81
  223. package/packages/web/lib/format.ts +0 -23
  224. package/packages/web/lib/generate-week-report.ts +0 -285
  225. package/packages/web/lib/parse-prjct-files.ts +0 -1123
  226. package/packages/web/lib/project-colors.ts +0 -58
  227. package/packages/web/lib/projects.ts +0 -506
  228. package/packages/web/lib/pty.ts +0 -101
  229. package/packages/web/lib/query-config.ts +0 -44
  230. package/packages/web/lib/services/index.ts +0 -9
  231. package/packages/web/lib/services/projects.server.ts +0 -66
  232. package/packages/web/lib/services/stats.server.ts +0 -562
  233. package/packages/web/lib/unified-loader.ts +0 -396
  234. package/packages/web/lib/utils.ts +0 -6
  235. package/packages/web/next-env.d.ts +0 -6
  236. package/packages/web/next.config.ts +0 -7
  237. package/packages/web/package.json +0 -57
  238. package/packages/web/postcss.config.mjs +0 -7
  239. package/packages/web/public/file.svg +0 -1
  240. package/packages/web/public/globe.svg +0 -1
  241. package/packages/web/public/next.svg +0 -1
  242. package/packages/web/public/vercel.svg +0 -1
  243. package/packages/web/public/window.svg +0 -1
  244. package/packages/web/server.ts +0 -312
  245. package/packages/web/tsconfig.json +0 -34
  246. package/templates/commands/serve.md +0 -121
@@ -1,12 +0,0 @@
1
- export function getPriorityColor(priority?: 'low' | 'medium' | 'high' | 'critical' | number): string {
2
- if (typeof priority === 'string') {
3
- const colors: Record<string, string> = {
4
- critical: 'text-foreground font-bold',
5
- high: 'text-foreground',
6
- medium: 'text-muted-foreground',
7
- low: 'text-muted-foreground',
8
- }
9
- return colors[priority] ?? 'text-muted-foreground'
10
- }
11
- return 'text-muted-foreground'
12
- }
@@ -1,2 +0,0 @@
1
- export { QueueCard } from './QueueCard'
2
- export type { QueueCardProps } from './QueueCard.types'
@@ -1,72 +0,0 @@
1
- 'use client'
2
-
3
- import Link from 'next/link'
4
- import { AlertCircle, ChevronRight, Clock, MessageSquare } from 'lucide-react'
5
- import { Badge } from '@/components/ui/badge'
6
- import { cn } from '@/lib/utils'
7
- import type { RecoverCardProps } from './RecoverCard.types'
8
-
9
- export function RecoverCard({ abandonedSessions, codeHref, className }: RecoverCardProps) {
10
- if (abandonedSessions.length === 0) return null
11
-
12
- return (
13
- <div className={cn(
14
- 'relative overflow-hidden rounded-xl border border-yellow-500/30 bg-yellow-500/5 p-4 min-w-0 max-w-full',
15
- className
16
- )}>
17
- <div className="flex items-center justify-between mb-3 min-w-0">
18
- <div className="flex items-center gap-2 min-w-0">
19
- <AlertCircle className="h-4 w-4 text-yellow-500 shrink-0" />
20
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-yellow-600 dark:text-yellow-500 truncate">
21
- Recover
22
- </span>
23
- </div>
24
- <Badge variant="outline" className="text-yellow-600 dark:text-yellow-500 border-yellow-500/50 shrink-0">
25
- {abandonedSessions.length}
26
- </Badge>
27
- </div>
28
-
29
- <div className="space-y-2 min-w-0 max-w-full">
30
- {abandonedSessions.slice(0, 3).map((session) => (
31
- <Link
32
- key={session.id}
33
- href={`${codeHref}?cmd=p.%20recover`}
34
- className="block py-2 px-2 -mx-2 hover:bg-yellow-500/10 rounded-lg transition-colors group"
35
- >
36
- <div className="flex items-start justify-between gap-2">
37
- <div className="flex-1 min-w-0">
38
- <p className="text-sm font-medium leading-tight truncate group-hover:text-foreground transition-colors">
39
- {session.task}
40
- </p>
41
- <div className="flex items-center gap-2 mt-1 text-xs text-muted-foreground">
42
- <Clock className="h-3 w-3 shrink-0" />
43
- <span>{session.hoursAgo}h ago</span>
44
- {session.projectName && (
45
- <>
46
- <span className="text-muted-foreground/50">|</span>
47
- <span className="truncate">{session.projectName}</span>
48
- </>
49
- )}
50
- </div>
51
- {session.prompt && (
52
- <div className="flex items-start gap-1.5 mt-1.5">
53
- <MessageSquare className="h-3 w-3 text-muted-foreground/70 shrink-0 mt-0.5" />
54
- <p className="text-xs text-muted-foreground/70 italic line-clamp-2">
55
- &quot;{session.prompt.slice(0, 80)}{session.prompt.length > 80 ? '...' : ''}&quot;
56
- </p>
57
- </div>
58
- )}
59
- </div>
60
- <ChevronRight className="h-4 w-4 text-muted-foreground/50 opacity-0 group-hover:opacity-100 transition-opacity shrink-0 mt-1" />
61
- </div>
62
- </Link>
63
- ))}
64
- {abandonedSessions.length > 3 && (
65
- <p className="text-xs text-yellow-600/70 dark:text-yellow-500/70 text-center pt-1">
66
- +{abandonedSessions.length - 3} more abandoned sessions
67
- </p>
68
- )}
69
- </div>
70
- </div>
71
- )
72
- }
@@ -1,16 +0,0 @@
1
- export interface AbandonedSession {
2
- id: string
3
- task: string
4
- projectId: string
5
- projectName?: string
6
- startedAt: string
7
- lastActivity?: string
8
- hoursAgo: number
9
- prompt?: string
10
- }
11
-
12
- export interface RecoverCardProps {
13
- abandonedSessions: AbandonedSession[]
14
- codeHref: string
15
- className?: string
16
- }
@@ -1,2 +0,0 @@
1
- export { RecoverCard } from './RecoverCard'
2
- export type { RecoverCardProps, AbandonedSession } from './RecoverCard.types'
@@ -1,145 +0,0 @@
1
- 'use client'
2
-
3
- import Link from 'next/link'
4
- import { EmptyState } from '@/components/EmptyState'
5
- import { Map, ChevronRight, CheckCircle2, Circle } from 'lucide-react'
6
- import { cn } from '@/lib/utils'
7
- import type { RoadmapCardProps } from './RoadmapCard.types'
8
-
9
- // Traffic light colors for progress: green=100%, yellow=50-99%, red=<50%
10
- function getProgressColor(progress: number): string {
11
- if (progress >= 100) return 'bg-emerald-500'
12
- if (progress >= 50) return 'bg-amber-500'
13
- return 'bg-red-500'
14
- }
15
-
16
- export function RoadmapCard({ roadmap, codeHref, className }: RoadmapCardProps) {
17
- const hasPhases = roadmap?.phases && roadmap.phases.length > 0
18
-
19
- return (
20
- <div className={cn(
21
- 'relative overflow-hidden rounded-xl border bg-card p-4',
22
- className
23
- )}>
24
- <div className="flex items-center justify-between mb-3">
25
- <div className="flex items-center gap-2">
26
- <Map className="h-4 w-4 text-muted-foreground" />
27
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
28
- Roadmap
29
- </span>
30
- </div>
31
- {hasPhases && (
32
- <span className="text-xs font-bold tabular-nums">
33
- {roadmap.progress}%
34
- </span>
35
- )}
36
- </div>
37
-
38
- {!hasPhases ? (
39
- <EmptyState
40
- icon={Map}
41
- title="No roadmap yet"
42
- description="Plan your features"
43
- command="/p:feature"
44
- href={codeHref}
45
- />
46
- ) : (
47
- <div className="space-y-4">
48
- {/* Overall progress */}
49
- <div>
50
- <div className="flex items-center justify-between mb-2">
51
- <span className="text-xs text-muted-foreground">Overall progress</span>
52
- <span className="text-sm font-bold tabular-nums">{roadmap.progress}%</span>
53
- </div>
54
- <div className="h-3 bg-muted rounded-full overflow-hidden">
55
- <div
56
- className={cn("h-full rounded-full transition-all duration-500", getProgressColor(roadmap.progress))}
57
- style={{ width: `${roadmap.progress}%` }}
58
- />
59
- </div>
60
- </div>
61
-
62
- {/* Phases with features */}
63
- <div className="space-y-4">
64
- {roadmap.phases
65
- .filter(p => (p.features || []).length > 0)
66
- .slice(0, 6)
67
- .map((phase) => (
68
- <div key={phase.name} className="group">
69
- <div className="flex items-center justify-between mb-2">
70
- <div className="flex items-center gap-2">
71
- {phase.progress === 100 ? (
72
- <CheckCircle2 className="h-4 w-4 text-muted-foreground" />
73
- ) : (
74
- <Circle className="h-4 w-4 text-muted-foreground" />
75
- )}
76
- <span className="text-sm font-medium">
77
- {phase.name}
78
- </span>
79
- </div>
80
- <span className="text-xs font-bold tabular-nums shrink-0 ml-2 text-muted-foreground">
81
- {phase.progress}%
82
- </span>
83
- </div>
84
- <div className="h-2 bg-muted rounded-full overflow-hidden ml-6">
85
- <div
86
- className={cn("h-full rounded-full transition-all duration-300", getProgressColor(phase.progress))}
87
- style={{ width: `${phase.progress}%` }}
88
- />
89
- </div>
90
- {/* Show features under each phase */}
91
- {phase.features && phase.features.length > 0 && (
92
- <div className="ml-6 mt-2 space-y-1">
93
- {phase.features.slice(0, 3).map((feature, i) => {
94
- const isCompleted = feature.status === 'completed'
95
- const cmdHref = codeHref && !isCompleted
96
- ? `${codeHref}?cmd=${encodeURIComponent(`p. work "${feature.name}"`)}`
97
- : undefined
98
-
99
- const content = (
100
- <>
101
- <ChevronRight className="h-3 w-3 shrink-0" />
102
- <span className={cn(
103
- 'truncate',
104
- isCompleted && 'line-through opacity-60'
105
- )}>
106
- {feature.name}
107
- </span>
108
- </>
109
- )
110
-
111
- return cmdHref ? (
112
- <Link
113
- key={i}
114
- href={cmdHref}
115
- className="flex items-center gap-2 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 rounded px-1 -mx-1 py-0.5 transition-colors cursor-pointer"
116
- >
117
- {content}
118
- </Link>
119
- ) : (
120
- <div key={i} className="flex items-center gap-2 text-xs text-muted-foreground">
121
- {content}
122
- </div>
123
- )
124
- })}
125
- {phase.features.length > 3 && (
126
- <span className="text-xs text-muted-foreground/70 ml-5">
127
- +{phase.features.length - 3} more
128
- </span>
129
- )}
130
- </div>
131
- )}
132
- </div>
133
- ))}
134
- </div>
135
-
136
- {roadmap.phases.length > 0 && (
137
- <p className="text-xs text-muted-foreground border-t pt-3 mt-3">
138
- {roadmap.phases.reduce((acc, p) => acc + (p.features?.length || 0), 0)} features across {roadmap.phases.length} phases
139
- </p>
140
- )}
141
- </div>
142
- )}
143
- </div>
144
- )
145
- }
@@ -1,16 +0,0 @@
1
- export interface RoadmapPhase {
2
- name: string
3
- progress: number
4
- features?: Array<{ name: string; status: string }>
5
- }
6
-
7
- export interface RoadmapData {
8
- phases: RoadmapPhase[]
9
- progress: number
10
- }
11
-
12
- export interface RoadmapCardProps {
13
- roadmap: RoadmapData | null
14
- codeHref?: string
15
- className?: string
16
- }
@@ -1,2 +0,0 @@
1
- export { RoadmapCard } from './RoadmapCard'
2
- export type { RoadmapCardProps } from './RoadmapCard.types'
@@ -1,95 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import { EmptyState } from '@/components/EmptyState'
5
- import { ExpandButton } from '@/components/ExpandButton'
6
- import { Rocket, Clock, FileCode, Check } from 'lucide-react'
7
- import { Badge } from '@/components/ui/badge'
8
- import { cn } from '@/lib/utils'
9
- import { formatShipDate } from './ShipsCard.utils'
10
- import type { ShipsCardProps } from './ShipsCard.types'
11
-
12
- const COLLAPSED_LIMIT = 10
13
-
14
- export function ShipsCard({ ships, totalShips = 0, codeHref, className }: ShipsCardProps) {
15
- const [expanded, setExpanded] = useState(false)
16
- const displayShips = expanded ? ships : ships.slice(0, COLLAPSED_LIMIT)
17
- const hasMore = ships.length > COLLAPSED_LIMIT
18
-
19
- return (
20
- <div className={cn(
21
- 'relative overflow-hidden rounded-xl border bg-card p-4',
22
- className
23
- )}>
24
- <div className="flex items-center justify-between mb-3">
25
- <div className="flex items-center gap-2">
26
- <Rocket className="h-4 w-4 text-muted-foreground" />
27
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
28
- Shipped
29
- </span>
30
- </div>
31
- <span className="text-xs font-medium text-muted-foreground tabular-nums">
32
- {totalShips} total
33
- </span>
34
- </div>
35
-
36
- {ships.length === 0 ? (
37
- <EmptyState
38
- icon={Rocket}
39
- title="Nothing shipped yet"
40
- description="Ship your first feature"
41
- command="/p:ship"
42
- href={codeHref}
43
- compact
44
- />
45
- ) : (
46
- <div className="space-y-2">
47
- {displayShips.map((ship, i) => (
48
- <div key={i} className="group py-1.5 hover:bg-muted/50 rounded px-2 -mx-2 border-l-2 border-transparent hover:border-foreground/20">
49
- <div className="flex items-start justify-between gap-2">
50
- <div className="flex-1 min-w-0">
51
- <div className="flex items-center gap-2">
52
- <Check className="h-3 w-3 text-muted-foreground shrink-0" />
53
- <p className="text-sm font-medium truncate">
54
- {ship.name}
55
- </p>
56
- {ship.version && (
57
- <Badge variant="outline" className="text-xs px-1 py-0 font-mono shrink-0 h-4">
58
- {ship.version}
59
- </Badge>
60
- )}
61
- </div>
62
- <div className="flex items-center gap-3 mt-1 ml-5">
63
- <span className="text-xs text-muted-foreground">
64
- {formatShipDate(ship.date)}
65
- </span>
66
- {ship.duration && (
67
- <span className="inline-flex items-center gap-0.5 text-xs text-muted-foreground">
68
- <Clock className="h-2.5 w-2.5" />
69
- {ship.duration}
70
- </span>
71
- )}
72
- {ship.filesChanged && (
73
- <span className="inline-flex items-center gap-0.5 text-xs text-muted-foreground">
74
- <FileCode className="h-2.5 w-2.5" />
75
- {ship.filesChanged} files
76
- </span>
77
- )}
78
- </div>
79
- </div>
80
- </div>
81
- </div>
82
- ))}
83
- {hasMore && (
84
- <ExpandButton
85
- expanded={expanded}
86
- totalCount={ships.length}
87
- collapsedLimit={COLLAPSED_LIMIT}
88
- onToggle={() => setExpanded(!expanded)}
89
- />
90
- )}
91
- </div>
92
- )}
93
- </div>
94
- )
95
- }
@@ -1,14 +0,0 @@
1
- export interface Ship {
2
- name: string
3
- date: string
4
- version?: string
5
- duration?: string
6
- filesChanged?: number
7
- }
8
-
9
- export interface ShipsCardProps {
10
- ships: Ship[]
11
- totalShips?: number
12
- codeHref?: string
13
- className?: string
14
- }
@@ -1,4 +0,0 @@
1
- export function formatShipDate(dateString: string): string {
2
- const date = new Date(dateString)
3
- return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
4
- }
@@ -1,2 +0,0 @@
1
- export { ShipsCard } from './ShipsCard'
2
- export type { ShipsCardProps } from './ShipsCard.types'
@@ -1,40 +0,0 @@
1
- 'use client'
2
-
3
- import { Area, AreaChart, ResponsiveContainer } from 'recharts'
4
- import type { SparklineChartProps } from './SparklineChart.types'
5
-
6
- export function SparklineChart({
7
- data,
8
- color = 'currentColor',
9
- height = 32,
10
- showArea = true,
11
- }: SparklineChartProps) {
12
- const chartData = data.map((value, index) => ({ index, value }))
13
-
14
- if (data.length === 0) {
15
- return <div style={{ height }} className="w-full" />
16
- }
17
-
18
- return (
19
- <div className="w-full min-w-0" style={{ height }}>
20
- <ResponsiveContainer width="100%" height="100%">
21
- <AreaChart data={chartData} margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>
22
- <defs>
23
- <linearGradient id="sparklineGradient" x1="0" y1="0" x2="0" y2="1">
24
- <stop offset="0%" stopColor={color} stopOpacity={0.3} />
25
- <stop offset="100%" stopColor={color} stopOpacity={0} />
26
- </linearGradient>
27
- </defs>
28
- <Area
29
- type="monotone"
30
- dataKey="value"
31
- stroke={color}
32
- strokeWidth={1.5}
33
- fill={showArea ? 'url(#sparklineGradient)' : 'none'}
34
- isAnimationActive={false}
35
- />
36
- </AreaChart>
37
- </ResponsiveContainer>
38
- </div>
39
- )
40
- }
@@ -1,6 +0,0 @@
1
- export interface SparklineChartProps {
2
- data: number[]
3
- color?: string
4
- height?: number
5
- showArea?: boolean
6
- }
@@ -1,2 +0,0 @@
1
- export { SparklineChart } from './SparklineChart'
2
- export type { SparklineChartProps } from './SparklineChart.types'
@@ -1,95 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect, useState } from 'react'
4
- import { MasonryGrid } from '@/components/MasonryGrid'
5
- import { NowCard } from '@/components/NowCard'
6
- import { VelocityCard } from '@/components/VelocityCard'
7
- import { StreakCard } from '@/components/StreakCard'
8
- import { QueueCard } from '@/components/QueueCard'
9
- import { ShipsCard } from '@/components/ShipsCard'
10
- import { IdeasCard } from '@/components/IdeasCard'
11
- import { AgentsCard } from '@/components/AgentsCard'
12
- import { RoadmapCard } from '@/components/RoadmapCard'
13
- import { BlockersCard } from '@/components/BlockersCard'
14
- import { RecoverCard, type AbandonedSession } from '@/components/RecoverCard'
15
- import { ActivityTimeline } from '@/components/ActivityTimeline'
16
- import type { TimelineEvent } from '@/lib/parse-prjct-files'
17
-
18
- interface StatsMasonryProps {
19
- projectId: string
20
- currentTask: any
21
- velocity: number
22
- weeklyVelocityData: number[]
23
- velocityChange: number
24
- estimateAccuracy?: number
25
- roadmap: any
26
- queue: any[]
27
- shipped: any[]
28
- totalShips: number
29
- streak: number
30
- blockers: any[]
31
- ideas: any[]
32
- agents: any[]
33
- timeline: TimelineEvent[]
34
- }
35
-
36
- export function StatsMasonry({
37
- projectId,
38
- currentTask,
39
- velocity,
40
- weeklyVelocityData,
41
- velocityChange,
42
- estimateAccuracy,
43
- roadmap,
44
- queue,
45
- shipped,
46
- totalShips,
47
- streak,
48
- blockers,
49
- ideas,
50
- agents,
51
- timeline,
52
- }: StatsMasonryProps) {
53
- const codeHref = `/project/${projectId}/code`
54
- const [abandonedSessions, setAbandonedSessions] = useState<AbandonedSession[]>([])
55
-
56
- // Fetch abandoned sessions from API
57
- useEffect(() => {
58
- async function fetchAbandonedSessions() {
59
- try {
60
- const res = await fetch(`/api/sessions/current?projectId=${projectId}`)
61
- const data = await res.json()
62
- if (data.success && data.data.abandonedSessions) {
63
- setAbandonedSessions(data.data.abandonedSessions)
64
- }
65
- } catch {
66
- // Silently fail - abandoned sessions are not critical
67
- }
68
- }
69
- fetchAbandonedSessions()
70
- }, [projectId])
71
-
72
- return (
73
- <MasonryGrid>
74
- {/* Show RecoverCard first if there are abandoned sessions */}
75
- {abandonedSessions.length > 0 && (
76
- <RecoverCard abandonedSessions={abandonedSessions} codeHref={codeHref} />
77
- )}
78
- <NowCard currentTask={currentTask} codeHref={codeHref} />
79
- <VelocityCard
80
- tasksPerDay={velocity}
81
- weeklyData={weeklyVelocityData}
82
- change={velocityChange}
83
- estimateAccuracy={estimateAccuracy}
84
- />
85
- <RoadmapCard roadmap={roadmap} codeHref={codeHref} />
86
- <QueueCard queue={queue} codeHref={codeHref} />
87
- <ShipsCard ships={shipped} totalShips={totalShips} codeHref={codeHref} />
88
- <StreakCard streak={streak} />
89
- <BlockersCard blockers={blockers} codeHref={codeHref} />
90
- <IdeasCard ideas={ideas} codeHref={codeHref} />
91
- <AgentsCard agents={agents} codeHref={codeHref} />
92
- <ActivityTimeline timeline={timeline} />
93
- </MasonryGrid>
94
- )
95
- }
@@ -1 +0,0 @@
1
- export { StatsMasonry } from './StatsMasonry'
@@ -1,2 +0,0 @@
1
- export const STREAK_HOT_THRESHOLD = 3
2
- export const STREAK_ON_FIRE_THRESHOLD = 7
@@ -1,55 +0,0 @@
1
- 'use client'
2
-
3
- import { Flame, Calendar } from 'lucide-react'
4
- import { cn } from '@/lib/utils'
5
- import type { StreakCardProps } from './StreakCard.types'
6
-
7
- function getStreakColor(streak: number): string {
8
- if (streak >= 7) return 'text-emerald-600 dark:text-emerald-400'
9
- if (streak >= 3) return 'text-amber-600 dark:text-amber-400'
10
- return 'text-red-600 dark:text-red-400'
11
- }
12
-
13
- export function StreakCard({ streak, className }: StreakCardProps) {
14
- return (
15
- <div className={cn(
16
- 'relative overflow-hidden rounded-xl border bg-card p-4',
17
- className
18
- )}>
19
- <div className="flex items-center justify-between mb-3">
20
- <div className="flex items-center gap-2">
21
- <Flame className="h-4 w-4 text-muted-foreground" />
22
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
23
- Streak
24
- </span>
25
- </div>
26
- </div>
27
-
28
- <div className="flex items-center gap-4">
29
- <Flame className={cn("h-10 w-10", getStreakColor(streak))} />
30
- <div>
31
- <p className="text-3xl font-bold tabular-nums">{streak}</p>
32
- <p className="text-xs text-muted-foreground">consecutive day{streak !== 1 ? 's' : ''}</p>
33
- </div>
34
- </div>
35
-
36
- <div className="mt-4">
37
- <div className="flex items-center gap-1.5 mb-2">
38
- <Calendar className="h-3 w-3 text-muted-foreground" />
39
- <span className="text-xs text-muted-foreground">Last 7 days</span>
40
- </div>
41
- <div className="flex gap-1">
42
- {Array.from({ length: 7 }).map((_, i) => (
43
- <div
44
- key={i}
45
- className={cn(
46
- 'h-2 flex-1 rounded-full transition-colors',
47
- i < streak ? 'bg-foreground' : 'bg-muted'
48
- )}
49
- />
50
- ))}
51
- </div>
52
- </div>
53
- </div>
54
- )
55
- }
@@ -1,4 +0,0 @@
1
- export interface StreakCardProps {
2
- streak: number
3
- className?: string
4
- }
@@ -1,2 +0,0 @@
1
- export { StreakCard } from './StreakCard'
2
- export type { StreakCardProps } from './StreakCard.types'
@@ -1,14 +0,0 @@
1
- import type { TasksCounterProps } from './TasksCounter.types'
2
-
3
- export function TasksCounter({ count }: TasksCounterProps) {
4
- return (
5
- <div className="flex flex-col sm:flex-row sm:items-baseline gap-1 sm:gap-3">
6
- <span className="text-5xl sm:text-6xl md:text-7xl font-bold tracking-tighter tabular-nums">
7
- {count}
8
- </span>
9
- <span className="text-sm sm:text-base md:text-lg text-muted-foreground">
10
- shipped
11
- </span>
12
- </div>
13
- )
14
- }
@@ -1,3 +0,0 @@
1
- export interface TasksCounterProps {
2
- count: number
3
- }
@@ -1,2 +0,0 @@
1
- export { TasksCounter } from './TasksCounter'
2
- export type { TasksCounterProps } from './TasksCounter.types'