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,92 +0,0 @@
1
- 'use client'
2
-
3
- import Link from 'next/link'
4
- import { Play, FileText, Flame } from 'lucide-react'
5
- import { ProgressRing } from '@/components/ProgressRing'
6
- import { TasksCounter } from '@/components/TasksCounter'
7
- import { InsightMessage } from '@/components/InsightMessage'
8
- import { WeeklySparkline } from '@/components/WeeklySparkline'
9
- import { HealthGradientBackground } from '@/components/HealthGradientBackground'
10
- import { useCountUp, useWeeklyActivity } from './hooks'
11
- import { getCompletionColor } from './HeroSection.utils'
12
- import type { HeroProps } from './HeroSection.types'
13
-
14
- export function HeroSection({
15
- projectId,
16
- projectName,
17
- projectVersion,
18
- totalShips,
19
- completionRate,
20
- streak,
21
- insightMessage,
22
- timeline = [],
23
- }: HeroProps) {
24
- const animatedCount = useCountUp(totalShips)
25
- const weeklyData = useWeeklyActivity(timeline)
26
- const completionColor = getCompletionColor(completionRate)
27
-
28
- return (
29
- <div className="relative mb-6 md:mb-8">
30
- <HealthGradientBackground score={completionRate} />
31
-
32
- <div className="relative z-10 flex items-center justify-between my-16">
33
- <div className="flex items-baseline gap-3">
34
- <h1 className="text-5xl md:text-6xl font-bold tracking-tight">{projectName}</h1>
35
- {projectVersion && (
36
- <span className="text-lg md:text-xl font-mono text-muted-foreground">v{projectVersion}</span>
37
- )}
38
- </div>
39
-
40
- <div className="flex items-center gap-3">
41
- {/* Reports Link */}
42
- <Link
43
- href={`/project/${projectId}/reports`}
44
- className="inline-flex items-center gap-2 px-4 py-3 bg-muted hover:bg-muted/80 text-foreground font-medium rounded-xl transition-all duration-200 hover:scale-105"
45
- >
46
- <FileText className="h-5 w-5" />
47
- <span>Reports</span>
48
- </Link>
49
-
50
- {/* Start Working CTA */}
51
- <Link
52
- href={`/project/${projectId}/code`}
53
- className="group relative inline-flex items-center gap-2 px-6 py-3 bg-emerald-500 hover:bg-emerald-600 text-white font-semibold rounded-xl shadow-lg shadow-emerald-500/25 hover:shadow-emerald-500/40 transition-all duration-200 hover:scale-105"
54
- >
55
- <Play className="h-5 w-5 fill-current" />
56
- <span>Start Working</span>
57
- <div className="absolute inset-0 rounded-xl bg-gradient-to-r from-emerald-400 to-emerald-600 opacity-0 group-hover:opacity-100 transition-opacity -z-10" />
58
- </Link>
59
- </div>
60
- </div>
61
-
62
- <div className="relative flex flex-col md:flex-row md:items-start md:justify-between gap-4 md:gap-0">
63
- <div className="flex items-center md:items-start gap-4 md:gap-6">
64
- <ProgressRing
65
- value={completionRate}
66
- size="xl"
67
- accentColor={completionColor}
68
- className="shrink-0"
69
- />
70
-
71
- <div className="flex-1 min-w-0">
72
- <TasksCounter count={animatedCount} />
73
- {/* Streak badge */}
74
- {streak > 0 && (
75
- <div className="flex items-center gap-1.5 mt-1">
76
- <Flame className="h-4 w-4 text-muted-foreground" />
77
- <span className="text-sm font-medium text-muted-foreground">
78
- {streak} day streak
79
- </span>
80
- </div>
81
- )}
82
- <InsightMessage message={insightMessage} />
83
- </div>
84
- </div>
85
-
86
- <div className="flex flex-col items-start md:items-end gap-3 md:gap-4">
87
- <WeeklySparkline data={weeklyData} size="lg" />
88
- </div>
89
- </div>
90
- </div>
91
- )
92
- }
@@ -1,14 +0,0 @@
1
- import type { TimelineEvent } from '@/lib/parse-prjct-files'
2
-
3
- export type { TimelineEvent }
4
-
5
- export interface HeroProps {
6
- projectId: string
7
- projectName: string
8
- projectVersion?: string | null
9
- totalShips: number
10
- completionRate: number
11
- streak: number
12
- insightMessage: string
13
- timeline?: TimelineEvent[]
14
- }
@@ -1,11 +0,0 @@
1
- export type AccentColor = 'default' | 'success' | 'warning' | 'destructive'
2
-
3
- // Completion rate color: traffic light based on project progress
4
- // Green >= 75% (almost done!)
5
- // Yellow 25-74% (good progress)
6
- // Red < 25% (just getting started)
7
- export function getCompletionColor(rate: number): AccentColor {
8
- if (rate >= 75) return 'success'
9
- if (rate >= 25) return 'warning'
10
- return 'destructive'
11
- }
@@ -1,2 +0,0 @@
1
- export { useCountUp } from './useCountUp'
2
- export { useWeeklyActivity } from './useWeeklyActivity'
@@ -1,45 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect, useRef, useState } from 'react'
4
-
5
- export function useCountUp(target: number, duration: number = 800): number {
6
- const [count, setCount] = useState(0)
7
- const prevTargetRef = useRef(target)
8
-
9
- useEffect(() => {
10
- if (target === 0) {
11
- // Only reset if target changed to 0 (not if it was already 0)
12
- if (prevTargetRef.current !== 0) {
13
- // Defer state update to avoid synchronous setState in effect
14
- const timeoutId = setTimeout(() => setCount(0), 0)
15
- prevTargetRef.current = target
16
- return () => clearTimeout(timeoutId)
17
- }
18
- prevTargetRef.current = target
19
- return
20
- }
21
-
22
- prevTargetRef.current = target
23
-
24
- const startTime = performance.now()
25
-
26
- const animate = (currentTime: number) => {
27
- const elapsed = currentTime - startTime
28
- const progress = Math.min(elapsed / duration, 1)
29
- const easeOut = 1 - Math.pow(1 - progress, 3)
30
- const current = Math.floor(easeOut * target)
31
-
32
- setCount(current)
33
-
34
- if (progress < 1) {
35
- requestAnimationFrame(animate)
36
- } else {
37
- setCount(target)
38
- }
39
- }
40
-
41
- requestAnimationFrame(animate)
42
- }, [target, duration])
43
-
44
- return count
45
- }
@@ -1,18 +0,0 @@
1
- 'use client'
2
-
3
- import { useMemo } from 'react'
4
- import type { TimelineEvent } from '../HeroSection.types'
5
-
6
- export function useWeeklyActivity(timeline: TimelineEvent[]): number[] {
7
- return useMemo(() => {
8
- const today = new Date()
9
-
10
- return Array.from({ length: 7 }, (_, i) => {
11
- const date = new Date(today)
12
- date.setDate(date.getDate() - (6 - i))
13
- const dateStr = date.toISOString().split('T')[0]
14
-
15
- return timeline.filter(e => e.ts?.startsWith(dateStr)).length
16
- })
17
- }, [timeline])
18
- }
@@ -1,2 +0,0 @@
1
- export { HeroSection } from './HeroSection'
2
- export type { HeroProps } from './HeroSection.types'
@@ -1,115 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import Link from 'next/link'
5
- import { EmptyState } from '@/components/EmptyState'
6
- import { ExpandButton } from '@/components/ExpandButton'
7
- import { Lightbulb, Sparkles, Rocket, X } from 'lucide-react'
8
- import { cn } from '@/lib/utils'
9
- import type { IdeasCardProps } from './IdeasCard.types'
10
-
11
- const COLLAPSED_LIMIT = 8
12
- const EXPANDED_LIMIT = 30
13
-
14
- export function IdeasCard({ ideas, codeHref, className }: IdeasCardProps) {
15
- const [expanded, setExpanded] = useState(false)
16
- const limit = expanded ? EXPANDED_LIMIT : COLLAPSED_LIMIT
17
- const displayIdeas = ideas.slice(0, limit)
18
- const highImpactCount = ideas.filter(i => i.impact === 'HIGH').length
19
- const hasMore = ideas.length > limit
20
-
21
- return (
22
- <div className={cn(
23
- 'relative overflow-hidden rounded-xl border bg-card p-4',
24
- className
25
- )}>
26
- <div className="flex items-center justify-between mb-3">
27
- <div className="flex items-center gap-2">
28
- <Lightbulb className="h-4 w-4 text-muted-foreground" />
29
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
30
- Ideas
31
- </span>
32
- </div>
33
- <div className="flex items-center gap-2">
34
- {highImpactCount > 0 && (
35
- <span className="text-xs font-medium text-muted-foreground bg-muted px-1.5 py-0.5 rounded">
36
- {highImpactCount} high impact
37
- </span>
38
- )}
39
- <span className="text-xs font-medium text-muted-foreground tabular-nums">
40
- {ideas.length}
41
- </span>
42
- </div>
43
- </div>
44
-
45
- {ideas.length === 0 ? (
46
- <EmptyState
47
- icon={Lightbulb}
48
- title="No ideas yet"
49
- command="/p:idea"
50
- href={codeHref}
51
- compact
52
- />
53
- ) : (
54
- <div className="space-y-1">
55
- {displayIdeas.map((idea, i) => {
56
- const featureHref = codeHref
57
- ? `${codeHref}?cmd=${encodeURIComponent(`p. feature "${idea.title}"`)}`
58
- : undefined
59
- const deleteHref = codeHref
60
- ? `${codeHref}?cmd=${encodeURIComponent(`p. idea remove ${i + 1}`)}`
61
- : undefined
62
-
63
- return (
64
- <div
65
- key={i}
66
- className="flex items-start gap-2 py-1.5 group hover:bg-muted/50 rounded px-1 -mx-1"
67
- >
68
- {idea.impact === 'HIGH' ? (
69
- <Sparkles className="h-3 w-3 mt-0.5 shrink-0 text-foreground" />
70
- ) : (
71
- <Lightbulb className="h-3 w-3 mt-0.5 shrink-0 text-muted-foreground" />
72
- )}
73
- <p className={cn(
74
- 'text-sm flex-1 min-w-0',
75
- idea.impact === 'HIGH' && 'font-medium'
76
- )}>
77
- {idea.title}
78
- </p>
79
- {/* Always visible action buttons */}
80
- <div className="flex items-center gap-1 shrink-0">
81
- {featureHref && (
82
- <Link
83
- href={featureHref}
84
- className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
85
- title="Convert to feature"
86
- >
87
- <Rocket className="h-3.5 w-3.5" />
88
- </Link>
89
- )}
90
- {deleteHref && (
91
- <Link
92
- href={deleteHref}
93
- className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
94
- title="Delete idea"
95
- >
96
- <X className="h-3.5 w-3.5" />
97
- </Link>
98
- )}
99
- </div>
100
- </div>
101
- )
102
- })}
103
- {(hasMore || expanded) && ideas.length > COLLAPSED_LIMIT && (
104
- <ExpandButton
105
- expanded={expanded}
106
- totalCount={ideas.length}
107
- collapsedLimit={COLLAPSED_LIMIT}
108
- onToggle={() => setExpanded(!expanded)}
109
- />
110
- )}
111
- </div>
112
- )}
113
- </div>
114
- )
115
- }
@@ -1,10 +0,0 @@
1
- export interface Idea {
2
- title: string
3
- impact?: string
4
- }
5
-
6
- export interface IdeasCardProps {
7
- ideas: Idea[]
8
- codeHref?: string
9
- className?: string
10
- }
@@ -1,2 +0,0 @@
1
- export { IdeasCard } from './IdeasCard'
2
- export type { IdeasCardProps } from './IdeasCard.types'
@@ -1,9 +0,0 @@
1
- import type { InsightMessageProps } from './InsightMessage.types'
2
-
3
- export function InsightMessage({ message }: InsightMessageProps) {
4
- return (
5
- <p className="text-sm md:text-base text-muted-foreground mt-2 md:mt-3 max-w-md">
6
- {message}
7
- </p>
8
- )
9
- }
@@ -1,3 +0,0 @@
1
- export interface InsightMessageProps {
2
- message: string
3
- }
@@ -1,2 +0,0 @@
1
- export { InsightMessage } from './InsightMessage'
2
- export type { InsightMessageProps } from './InsightMessage.types'
@@ -1,65 +0,0 @@
1
- import { cn } from '@/lib/utils'
2
-
3
- interface LogoProps {
4
- showText?: boolean
5
- size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
6
- rounded?: boolean
7
- }
8
-
9
- export function Logo({ showText = true, size = 'md', rounded = false }: LogoProps) {
10
- const logoSize = {
11
- xs: 'size-7',
12
- sm: 'size-10',
13
- md: 'size-12',
14
- lg: 'size-14',
15
- xl: 'size-16',
16
- }
17
-
18
- const textSize = {
19
- xs: 'text-sm',
20
- sm: 'text-lg',
21
- md: 'text-lg',
22
- lg: 'text-2xl',
23
- xl: 'text-3xl',
24
- }
25
-
26
- const containerTextSize = {
27
- xs: 'text-sm',
28
- sm: 'text-base',
29
- md: 'text-xl',
30
- lg: 'text-2xl',
31
- xl: 'text-3xl',
32
- }
33
-
34
- const brandTextSize = {
35
- xs: 'text-xs',
36
- sm: 'text-sm',
37
- md: 'text-lg',
38
- lg: 'text-xl',
39
- xl: 'text-2xl',
40
- }
41
-
42
- return (
43
- <div
44
- className={cn('flex items-center gap-2', containerTextSize[size])}
45
- data-testid="prjct-logo"
46
- >
47
- <div className="relative isolate overflow-visible">
48
- <div className={cn("fancy-border pointer-events-none", rounded && "rounded-full")}></div>
49
- <div
50
- className={cn(
51
- 'relative z-10 flex items-center justify-center border border-border bg-foreground text-background shadow-sm',
52
- rounded ? 'rounded-full' : 'rounded-lg',
53
- logoSize[size]
54
- )}
55
- data-testid="prjct-logo-icon"
56
- >
57
- <p className={cn('mb-0.5 inline-block font-bold leading-none', textSize[size])}>p/</p>
58
- </div>
59
- </div>
60
- {showText && (
61
- <span className={cn(brandTextSize[size], 'font-bold text-foreground')}>prjct</span>
62
- )}
63
- </div>
64
- )
65
- }
@@ -1 +0,0 @@
1
- export { Logo } from './Logo'
@@ -1,123 +0,0 @@
1
- 'use client'
2
-
3
- import ReactMarkdown from 'react-markdown'
4
- import remarkGfm from 'remark-gfm'
5
- import { cn } from '@/lib/utils'
6
-
7
- interface MarkdownContentProps {
8
- content: string
9
- className?: string
10
- }
11
-
12
- export function MarkdownContent({ content, className }: MarkdownContentProps) {
13
- if (!content || !content.trim()) {
14
- return (
15
- <p className="text-sm text-muted-foreground italic">No content</p>
16
- )
17
- }
18
-
19
- return (
20
- <div className={cn('prose prose-sm dark:prose-invert max-w-none', className)}>
21
- <ReactMarkdown
22
- remarkPlugins={[remarkGfm]}
23
- components={{
24
- // Headers
25
- h1: ({ children }) => (
26
- <h1 className="text-xl font-bold mt-4 mb-2 first:mt-0">{children}</h1>
27
- ),
28
- h2: ({ children }) => (
29
- <h2 className="text-lg font-semibold mt-4 mb-2 border-b pb-1">{children}</h2>
30
- ),
31
- h3: ({ children }) => (
32
- <h3 className="text-base font-medium mt-3 mb-1">{children}</h3>
33
- ),
34
- // Lists
35
- ul: ({ children }) => (
36
- <ul className="list-disc list-inside space-y-1 my-2">{children}</ul>
37
- ),
38
- ol: ({ children }) => (
39
- <ol className="list-decimal list-inside space-y-1 my-2">{children}</ol>
40
- ),
41
- li: ({ children }) => (
42
- <li className="text-sm">{children}</li>
43
- ),
44
- // Checkbox lists (GFM)
45
- input: ({ checked, ...props }) => (
46
- <input
47
- type="checkbox"
48
- checked={checked}
49
- readOnly
50
- className="mr-2 rounded"
51
- {...props}
52
- />
53
- ),
54
- // Paragraphs
55
- p: ({ children }) => (
56
- <p className="text-sm my-1.5 leading-relaxed">{children}</p>
57
- ),
58
- // Code
59
- code: ({ className, children, ...props }) => {
60
- const isInline = !className
61
- if (isInline) {
62
- return (
63
- <code className="bg-muted px-1 py-0.5 rounded text-xs font-mono" {...props}>
64
- {children}
65
- </code>
66
- )
67
- }
68
- return (
69
- <code className={cn('block bg-muted p-2 rounded text-xs font-mono overflow-x-auto', className)} {...props}>
70
- {children}
71
- </code>
72
- )
73
- },
74
- pre: ({ children }) => (
75
- <pre className="bg-muted p-3 rounded-md overflow-x-auto my-2 text-xs">
76
- {children}
77
- </pre>
78
- ),
79
- // Tables
80
- table: ({ children }) => (
81
- <div className="overflow-x-auto my-2">
82
- <table className="min-w-full text-xs border-collapse">{children}</table>
83
- </div>
84
- ),
85
- thead: ({ children }) => (
86
- <thead className="bg-muted">{children}</thead>
87
- ),
88
- th: ({ children }) => (
89
- <th className="px-2 py-1 text-left font-medium border-b">{children}</th>
90
- ),
91
- td: ({ children }) => (
92
- <td className="px-2 py-1 border-b">{children}</td>
93
- ),
94
- // Blockquotes
95
- blockquote: ({ children }) => (
96
- <blockquote className="border-l-2 border-muted-foreground/30 pl-3 italic text-muted-foreground my-2">
97
- {children}
98
- </blockquote>
99
- ),
100
- // Horizontal rules
101
- hr: () => (
102
- <hr className="my-4 border-border" />
103
- ),
104
- // Strong/em
105
- strong: ({ children }) => (
106
- <strong className="font-semibold">{children}</strong>
107
- ),
108
- em: ({ children }) => (
109
- <em className="italic">{children}</em>
110
- ),
111
- // Links
112
- a: ({ href, children }) => (
113
- <a href={href} className="text-primary hover:underline" target="_blank" rel="noopener noreferrer">
114
- {children}
115
- </a>
116
- ),
117
- }}
118
- >
119
- {content}
120
- </ReactMarkdown>
121
- </div>
122
- )
123
- }
@@ -1 +0,0 @@
1
- export { MarkdownContent } from './MarkdownContent'
@@ -1,18 +0,0 @@
1
- import { cn } from '@/lib/utils'
2
-
3
- interface MasonryGridProps {
4
- children: React.ReactNode
5
- className?: string
6
- }
7
-
8
- export function MasonryGrid({ children, className }: MasonryGridProps) {
9
- return (
10
- <div className={cn(
11
- 'columns-1 sm:columns-2 xl:columns-3 gap-4 max-w-full overflow-x-hidden',
12
- '[&>*]:mb-4 [&>*]:break-inside-avoid',
13
- className
14
- )}>
15
- {children}
16
- </div>
17
- )
18
- }
@@ -1 +0,0 @@
1
- export { MasonryGrid } from './MasonryGrid'
@@ -1,119 +0,0 @@
1
- 'use client'
2
-
3
- import { useEffect, useState } from 'react'
4
- import { SparklineChart } from '@/components/SparklineChart'
5
- import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
6
- import { Flame, TrendingUp, Activity, Heart } from 'lucide-react'
7
- import { cn } from '@/lib/utils'
8
- import type { MomentumWidgetProps, MomentumData, MomentumStatus } from './MomentumWidget.types'
9
-
10
- const statusConfig: Record<MomentumStatus, {
11
- color: string
12
- bgColor: string
13
- textColor: string
14
- icon: typeof Flame
15
- }> = {
16
- // Growing - you're killing it!
17
- hot: {
18
- color: '#22c55e',
19
- bgColor: 'bg-green-500/10',
20
- textColor: 'text-green-500',
21
- icon: Flame
22
- },
23
- // Normal activity - neutral tones
24
- active: {
25
- color: '#a1a1aa',
26
- bgColor: 'bg-muted',
27
- textColor: 'text-muted-foreground',
28
- icon: Activity
29
- },
30
- // Slight slowdown - still neutral
31
- cooling: {
32
- color: '#a1a1aa',
33
- bgColor: 'bg-muted',
34
- textColor: 'text-muted-foreground',
35
- icon: TrendingUp
36
- },
37
- // Abandoned (7+ days) - red alert
38
- cold: {
39
- color: '#ef4444',
40
- bgColor: 'bg-red-500/10',
41
- textColor: 'text-red-500',
42
- icon: Heart
43
- }
44
- }
45
-
46
- export function MomentumWidget({ projectId }: MomentumWidgetProps) {
47
- const [data, setData] = useState<MomentumData | null>(null)
48
- const [loading, setLoading] = useState(true)
49
-
50
- useEffect(() => {
51
- async function fetchMomentum() {
52
- try {
53
- const res = await fetch(`/api/projects/${projectId}/momentum`)
54
- const json = await res.json()
55
- if (json.success) {
56
- setData(json.data)
57
- }
58
- } catch (error) {
59
- console.error('Failed to fetch momentum:', error)
60
- } finally {
61
- setLoading(false)
62
- }
63
- }
64
-
65
- fetchMomentum()
66
- }, [projectId])
67
-
68
- if (loading) {
69
- return (
70
- <div className="flex items-center gap-2 h-10 animate-pulse">
71
- <div className="h-10 w-32 bg-muted rounded" />
72
- <div className="h-4 w-16 bg-muted rounded" />
73
- </div>
74
- )
75
- }
76
-
77
- if (!data) return null
78
-
79
- const config = statusConfig[data.status]
80
- const Icon = config.icon
81
-
82
- return (
83
- <Tooltip>
84
- <TooltipTrigger asChild>
85
- <div className={cn(
86
- 'flex items-center gap-2 px-2 py-1 rounded-md cursor-default transition-colors',
87
- config.bgColor
88
- )}>
89
- {/* Mini sparkline - matching button width for visual weight */}
90
- <div className="w-32 h-10">
91
- <SparklineChart
92
- data={data.dailyTasks}
93
- color={config.color}
94
- height={40}
95
- showArea={true}
96
- />
97
- </div>
98
-
99
- {/* Status badge */}
100
- <div className={cn('flex items-center gap-1.5', config.textColor)}>
101
- <Icon className="w-4 h-4" />
102
- <span className="text-sm font-medium whitespace-nowrap">
103
- {data.message}
104
- </span>
105
- </div>
106
- </div>
107
- </TooltipTrigger>
108
- <TooltipContent side="bottom" className="text-xs">
109
- <div className="space-y-1">
110
- <p className="font-medium">7-day activity</p>
111
- <p>{data.totalTasks} tasks, {data.totalShips} ships</p>
112
- {data.streak > 0 && (
113
- <p className="text-foreground font-medium">{data.streak} day streak!</p>
114
- )}
115
- </div>
116
- </TooltipContent>
117
- </Tooltip>
118
- )
119
- }