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,16 +0,0 @@
1
- export type MomentumStatus = 'hot' | 'active' | 'cooling' | 'cold'
2
-
3
- export interface MomentumData {
4
- dailyTasks: number[]
5
- totalTasks: number
6
- totalShips: number
7
- lastActivityDate: string | null
8
- daysSinceActivity: number
9
- streak: number
10
- status: MomentumStatus
11
- message: string
12
- }
13
-
14
- export interface MomentumWidgetProps {
15
- projectId: string
16
- }
@@ -1,2 +0,0 @@
1
- export { MomentumWidget } from './MomentumWidget'
2
- export type { MomentumWidgetProps, MomentumData, MomentumStatus } from './MomentumWidget.types'
@@ -1,118 +0,0 @@
1
- 'use client'
2
-
3
- import Link from 'next/link'
4
- import { EmptyState } from '@/components/EmptyState'
5
- import { Target, Clock, Bot, Pause, Play, CheckCircle2 } from 'lucide-react'
6
- import { cn } from '@/lib/utils'
7
- import type { NowCardProps } from './NowCard.types'
8
-
9
- export function NowCard({ currentTask, codeHref, className }: NowCardProps) {
10
- return (
11
- <div className={cn(
12
- 'relative overflow-hidden rounded-xl border bg-card p-4',
13
- className
14
- )}>
15
- <div className="flex items-center justify-between mb-3">
16
- <div className="flex items-center gap-2">
17
- <Target className="h-4 w-4 text-muted-foreground" />
18
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
19
- Now
20
- </span>
21
- </div>
22
- {currentTask && (
23
- <div className="flex items-center gap-2">
24
- {currentTask.pausedAt ? (
25
- <span className="inline-flex items-center gap-1 text-xs font-semibold text-muted-foreground bg-muted px-2 py-0.5 rounded-full">
26
- <Pause className="w-2.5 h-2.5" />
27
- Paused
28
- </span>
29
- ) : (
30
- <span className="inline-flex items-center gap-1 text-xs font-semibold text-foreground bg-muted px-2 py-0.5 rounded-full">
31
- <Play className="w-2.5 h-2.5 fill-current" />
32
- Working
33
- </span>
34
- )}
35
- </div>
36
- )}
37
- </div>
38
-
39
- {currentTask ? (
40
- <div className="space-y-3">
41
- <p className="text-sm font-medium leading-tight break-words">
42
- {currentTask.task}
43
- </p>
44
-
45
- <div className="flex flex-wrap items-center gap-3">
46
- {currentTask.agent && (
47
- <div className="inline-flex items-center gap-1.5 text-xs text-muted-foreground bg-muted/50 px-2 py-1 rounded">
48
- <Bot className="h-3 w-3" />
49
- <span className="font-mono">{currentTask.agent}</span>
50
- </div>
51
- )}
52
-
53
- {currentTask.startedAt && (
54
- <div className="inline-flex items-center gap-1.5 text-xs text-muted-foreground">
55
- <Clock className="h-3 w-3" />
56
- <span>Started {new Date(currentTask.startedAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>
57
- </div>
58
- )}
59
-
60
- {currentTask.estimatedDuration && (
61
- <span className="text-xs text-muted-foreground">
62
- Est. {currentTask.estimatedDuration}
63
- </span>
64
- )}
65
- </div>
66
-
67
- {/* Progress indicator */}
68
- <div className="pt-1">
69
- <div className="h-1.5 bg-muted rounded-full overflow-hidden">
70
- <div
71
- className="h-full rounded-full transition-all duration-300 bg-foreground"
72
- style={{ width: currentTask.pausedAt ? '30%' : '60%' }}
73
- />
74
- </div>
75
- </div>
76
-
77
- {/* Action buttons */}
78
- {codeHref && (
79
- <div className="flex gap-2 pt-2">
80
- <Link
81
- href={`${codeHref}?cmd=p.%20done`}
82
- className="flex-1 flex items-center justify-center gap-1.5 text-xs font-medium px-3 py-2 rounded-lg bg-muted text-foreground hover:bg-muted/80 transition-colors"
83
- >
84
- <CheckCircle2 className="h-3.5 w-3.5" />
85
- Done
86
- </Link>
87
- {currentTask.pausedAt ? (
88
- <Link
89
- href={`${codeHref}?cmd=p.%20resume`}
90
- className="flex-1 flex items-center justify-center gap-1.5 text-xs font-medium px-3 py-2 rounded-lg bg-muted text-foreground hover:bg-muted/80 transition-colors"
91
- >
92
- <Play className="h-3.5 w-3.5" />
93
- Resume
94
- </Link>
95
- ) : (
96
- <Link
97
- href={`${codeHref}?cmd=p.%20pause`}
98
- className="flex-1 flex items-center justify-center gap-1.5 text-xs font-medium px-3 py-2 rounded-lg bg-muted text-foreground hover:bg-muted/80 transition-colors"
99
- >
100
- <Pause className="h-3.5 w-3.5" />
101
- Pause
102
- </Link>
103
- )}
104
- </div>
105
- )}
106
- </div>
107
- ) : (
108
- <EmptyState
109
- icon={Target}
110
- title="No active task"
111
- description="Start working on something"
112
- command="/p:now"
113
- href={codeHref}
114
- />
115
- )}
116
- </div>
117
- )
118
- }
@@ -1,16 +0,0 @@
1
- export interface CurrentTask {
2
- task: string
3
- startedAt?: string
4
- agent?: string
5
- agentConfidence?: number
6
- estimatedDuration?: string
7
- pausedAt?: string
8
- pauseReason?: string
9
- duration?: string
10
- }
11
-
12
- export interface NowCardProps {
13
- currentTask: CurrentTask | null
14
- codeHref?: string
15
- className?: string
16
- }
@@ -1,2 +0,0 @@
1
- export { NowCard } from './NowCard'
2
- export type { NowCardProps } from './NowCard.types'
@@ -1,24 +0,0 @@
1
- import { getProjectBgClass } from '@/lib/project-colors'
2
-
3
- interface PageHeaderProps {
4
- projectId: string
5
- projectName: string
6
- section?: string
7
- }
8
-
9
- export function PageHeader({ projectId, projectName, section }: PageHeaderProps) {
10
- const colorBg = getProjectBgClass(projectId)
11
-
12
- return (
13
- <div className="flex items-center gap-3 mb-6">
14
- <div className={`w-3 h-3 rounded-full shrink-0 ${colorBg}`} />
15
- <h1 className="text-2xl font-semibold">{projectName}</h1>
16
- {section && (
17
- <>
18
- <span className="text-muted-foreground/50">/</span>
19
- <span className="text-xl text-muted-foreground">{section}</span>
20
- </>
21
- )}
22
- </div>
23
- )
24
- }
@@ -1 +0,0 @@
1
- export { PageHeader } from './PageHeader'
@@ -1,20 +0,0 @@
1
- import type { ProgressRingSize, AccentColor } from './ProgressRing.types'
2
-
3
- export const PROGRESS_RING_SIZES: Record<ProgressRingSize, {
4
- container: string
5
- text: string
6
- viewBox: number
7
- radius: number
8
- }> = {
9
- sm: { container: 'h-8 w-8', text: 'text-xs', viewBox: 36, radius: 14 },
10
- md: { container: 'h-12 w-12', text: 'text-xs', viewBox: 36, radius: 14 },
11
- lg: { container: 'h-16 w-16', text: 'text-sm', viewBox: 36, radius: 14 },
12
- xl: { container: 'h-20 w-20', text: 'text-base', viewBox: 36, radius: 14 },
13
- }
14
-
15
- export const PROGRESS_RING_COLOR_STYLES: Record<AccentColor, string> = {
16
- default: 'text-foreground',
17
- success: 'text-emerald-500',
18
- warning: 'text-amber-500',
19
- destructive: 'text-red-500',
20
- }
@@ -1,51 +0,0 @@
1
- 'use client'
2
-
3
- import { cn } from '@/lib/utils'
4
- import { PROGRESS_RING_SIZES, PROGRESS_RING_COLOR_STYLES } from './ProgressRing.constants'
5
- import type { ProgressRingProps } from './ProgressRing.types'
6
-
7
- export function ProgressRing({
8
- value,
9
- size = 'md',
10
- showValue = true,
11
- strokeWidth = 3,
12
- className,
13
- accentColor = 'default',
14
- }: ProgressRingProps) {
15
- const { container, text, viewBox, radius } = PROGRESS_RING_SIZES[size]
16
- const circumference = 2 * Math.PI * radius
17
- const strokeDashoffset = circumference - (value / 100) * circumference
18
-
19
- return (
20
- <div className={cn('relative', container, className)}>
21
- <svg className="h-full w-full -rotate-90" viewBox={`0 0 ${viewBox} ${viewBox}`}>
22
- <circle
23
- cx={viewBox / 2}
24
- cy={viewBox / 2}
25
- r={radius}
26
- fill="none"
27
- stroke="currentColor"
28
- strokeWidth={strokeWidth}
29
- className="text-foreground/10"
30
- />
31
- <circle
32
- cx={viewBox / 2}
33
- cy={viewBox / 2}
34
- r={radius}
35
- fill="none"
36
- stroke="currentColor"
37
- strokeWidth={strokeWidth}
38
- strokeDasharray={circumference}
39
- strokeDashoffset={strokeDashoffset}
40
- strokeLinecap="round"
41
- className={cn('transition-all duration-700 ease-out', PROGRESS_RING_COLOR_STYLES[accentColor])}
42
- />
43
- </svg>
44
- {showValue && (
45
- <span className={cn('absolute inset-0 flex items-center justify-center font-bold tabular-nums', text)}>
46
- {value}
47
- </span>
48
- )}
49
- </div>
50
- )
51
- }
@@ -1,11 +0,0 @@
1
- export type ProgressRingSize = 'sm' | 'md' | 'lg' | 'xl'
2
- export type AccentColor = 'default' | 'success' | 'warning' | 'destructive'
3
-
4
- export interface ProgressRingProps {
5
- value: number
6
- size?: ProgressRingSize
7
- showValue?: boolean
8
- strokeWidth?: number
9
- className?: string
10
- accentColor?: AccentColor
11
- }
@@ -1,2 +0,0 @@
1
- export { ProgressRing } from './ProgressRing'
2
- export type { ProgressRingProps } from './ProgressRing.types'
@@ -1,54 +0,0 @@
1
- 'use client'
2
-
3
- import { cn } from '@/lib/utils'
4
-
5
- interface ProjectAvatarProps {
6
- projectId: string
7
- name: string
8
- iconPath?: string | null
9
- size?: 'sm' | 'md' | 'lg'
10
- className?: string
11
- }
12
-
13
- const sizeClasses = {
14
- sm: 'w-8 h-8 text-xs',
15
- md: 'w-9 h-9 text-sm',
16
- lg: 'w-10 h-10 text-sm'
17
- }
18
-
19
- export function ProjectAvatar({
20
- projectId,
21
- name,
22
- iconPath,
23
- size = 'md',
24
- className
25
- }: ProjectAvatarProps) {
26
- const initials = name.slice(0, 2).toUpperCase()
27
-
28
- return (
29
- <div
30
- className={cn(
31
- 'rounded-lg flex items-center justify-center overflow-hidden shrink-0 bg-muted border border-border',
32
- sizeClasses[size],
33
- className
34
- )}
35
- >
36
- {iconPath ? (
37
- <img
38
- src={`/api/projects/${projectId}/icon`}
39
- alt=""
40
- className="w-full h-full object-cover"
41
- onError={(e) => {
42
- e.currentTarget.style.display = 'none'
43
- if (e.currentTarget.nextElementSibling) {
44
- (e.currentTarget.nextElementSibling as HTMLElement).classList.remove('hidden')
45
- }
46
- }}
47
- />
48
- ) : null}
49
- <span className={cn('font-medium text-muted-foreground', iconPath ? 'hidden' : '')}>
50
- {initials}
51
- </span>
52
- </div>
53
- )
54
- }
@@ -1 +0,0 @@
1
- export { ProjectAvatar } from './ProjectAvatar'
@@ -1,37 +0,0 @@
1
- 'use client'
2
-
3
- import { cn } from '@/lib/utils'
4
- import { getProjectColor } from '@/lib/project-colors'
5
-
6
- interface ProjectColorDotProps {
7
- projectId: string
8
- size?: 'sm' | 'md' | 'lg' | 'xl'
9
- className?: string
10
- }
11
-
12
- const sizeClasses = {
13
- sm: 'w-2 h-2',
14
- md: 'w-3 h-3',
15
- lg: 'w-4 h-4',
16
- xl: 'w-5 h-5',
17
- }
18
-
19
- export function ProjectColorDot({
20
- projectId,
21
- size = 'md',
22
- className
23
- }: ProjectColorDotProps) {
24
- const color = getProjectColor(projectId)
25
-
26
- return (
27
- <div
28
- className={cn(
29
- 'rounded-full shrink-0',
30
- sizeClasses[size],
31
- color.bg,
32
- className
33
- )}
34
- aria-hidden="true"
35
- />
36
- )
37
- }
@@ -1 +0,0 @@
1
- export { ProjectColorDot } from './ProjectColorDot'
@@ -1,104 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
- import { useProjects } from '@/hooks/useProjects'
5
- import {
6
- Dialog,
7
- DialogContent,
8
- DialogHeader,
9
- DialogTitle,
10
- DialogDescription,
11
- } from '@/components/ui/dialog'
12
- import { Input } from '@/components/ui/input'
13
- import { ProjectAvatar } from '@/components/ProjectAvatar'
14
- import { Loader2, Search, FolderGit2 } from 'lucide-react'
15
- import { cn } from '@/lib/utils'
16
- import { formatPath } from '@/lib/format'
17
-
18
- interface ProjectSelectorModalProps {
19
- isOpen: boolean
20
- onClose: () => void
21
- onSelectProject: (projectId: string, projectName: string, projectPath: string) => void
22
- }
23
-
24
- export function ProjectSelectorModal({
25
- isOpen,
26
- onClose,
27
- onSelectProject,
28
- }: ProjectSelectorModalProps) {
29
- const [search, setSearch] = useState('')
30
- const { data: projects, isLoading } = useProjects()
31
-
32
- const filteredProjects = projects?.filter((project) =>
33
- project.name?.toLowerCase().includes(search.toLowerCase()) ||
34
- project.repoPath?.toLowerCase().includes(search.toLowerCase())
35
- ) || []
36
-
37
- return (
38
- <Dialog open={isOpen} onOpenChange={onClose}>
39
- <DialogContent className="sm:max-w-md">
40
- <DialogHeader>
41
- <DialogTitle>Select a Project</DialogTitle>
42
- <DialogDescription>
43
- Choose a project to open a terminal session
44
- </DialogDescription>
45
- </DialogHeader>
46
-
47
- <div className="relative">
48
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
49
- <Input
50
- placeholder="Search projects..."
51
- value={search}
52
- onChange={(e) => setSearch(e.target.value)}
53
- className="pl-9"
54
- />
55
- </div>
56
-
57
- <div className="max-h-[300px] overflow-y-auto space-y-1">
58
- {isLoading ? (
59
- <div className="flex items-center justify-center py-8">
60
- <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
61
- </div>
62
- ) : filteredProjects.length === 0 ? (
63
- <div className="text-center py-8 text-muted-foreground">
64
- {search ? 'No projects found' : 'No projects available'}
65
- </div>
66
- ) : (
67
- filteredProjects.map((project) => (
68
- <button
69
- key={project.id}
70
- onClick={() => {
71
- const projectPath = project.repoPath || project.path || '/tmp'
72
- const projectName = project.name || project.id
73
- onSelectProject(project.id, projectName, projectPath)
74
- }}
75
- className={cn(
76
- 'w-full flex items-center gap-3 p-3 rounded-lg transition-colors',
77
- 'hover:bg-accent text-left'
78
- )}
79
- >
80
- <ProjectAvatar
81
- projectId={project.id}
82
- name={project.name || project.id}
83
- iconPath={project.iconPath}
84
- size="sm"
85
- />
86
- <div className="flex-1 min-w-0">
87
- <div className="font-medium truncate">
88
- {project.name || project.id}
89
- </div>
90
- {project.repoPath && (
91
- <div className="text-xs text-muted-foreground flex items-center gap-1 truncate">
92
- <FolderGit2 className="h-3 w-3 shrink-0" />
93
- <span className="truncate">{formatPath(project.repoPath)}</span>
94
- </div>
95
- )}
96
- </div>
97
- </button>
98
- ))
99
- )}
100
- </div>
101
- </DialogContent>
102
- </Dialog>
103
- )
104
- }
@@ -1 +0,0 @@
1
- export { ProjectSelectorModal } from './ProjectSelectorModal'
@@ -1,48 +0,0 @@
1
- 'use client'
2
-
3
- import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
4
- import { useState, type ReactNode } from 'react'
5
- import { ThemeProvider, type ThemeProviderProps } from 'next-themes'
6
- import { TerminalProvider } from '@/context/TerminalContext'
7
- import { GlobalTerminalProvider } from '@/context/GlobalTerminalContext'
8
-
9
- function ThemeWrapper({ children, ...props }: ThemeProviderProps & { children: ReactNode }) {
10
- return <ThemeProvider {...props}>{children}</ThemeProvider>
11
- }
12
-
13
- export function Providers({ children }: { children: ReactNode }) {
14
- const [queryClient] = useState(() => new QueryClient({
15
- defaultOptions: {
16
- queries: {
17
- // Data considered fresh for 2.5 seconds
18
- staleTime: 2500,
19
- // Garbage collect after 5 minutes
20
- gcTime: 5 * 60 * 1000,
21
- // Refetch on window focus for real-time feel
22
- refetchOnWindowFocus: true,
23
- // Refetch when reconnecting
24
- refetchOnReconnect: true,
25
- // Retry failed requests once
26
- retry: 1,
27
- retryDelay: 1000,
28
- },
29
- },
30
- }))
31
-
32
- return (
33
- <QueryClientProvider client={queryClient}>
34
- <ThemeWrapper
35
- attribute="class"
36
- defaultTheme="dark"
37
- enableSystem
38
- disableTransitionOnChange
39
- >
40
- <TerminalProvider>
41
- <GlobalTerminalProvider>
42
- {children}
43
- </GlobalTerminalProvider>
44
- </TerminalProvider>
45
- </ThemeWrapper>
46
- </QueryClientProvider>
47
- )
48
- }
@@ -1 +0,0 @@
1
- export { Providers } from './Providers'
@@ -1,125 +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 { ListTodo, Bot, Play, X } from 'lucide-react'
8
- import { cn } from '@/lib/utils'
9
- import { getPriorityColor } from './QueueCard.utils'
10
- import type { QueueCardProps } from './QueueCard.types'
11
-
12
- const COLLAPSED_LIMIT = 10
13
- const EXPANDED_LIMIT = 50
14
-
15
- export function QueueCard({ queue, codeHref, className }: QueueCardProps) {
16
- const [expanded, setExpanded] = useState(false)
17
- const limit = expanded ? EXPANDED_LIMIT : COLLAPSED_LIMIT
18
- const displayItems = queue.slice(0, limit)
19
- const hasMore = queue.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
- <ListTodo className="h-4 w-4 text-muted-foreground" />
29
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
30
- Queue
31
- </span>
32
- </div>
33
- <span className="text-xs font-medium text-muted-foreground tabular-nums">
34
- {queue.length} tasks
35
- </span>
36
- </div>
37
-
38
- {queue.length === 0 ? (
39
- <EmptyState
40
- icon={ListTodo}
41
- title="Queue empty"
42
- description="Plan your next tasks"
43
- command="/p:next"
44
- href={codeHref}
45
- compact
46
- />
47
- ) : (
48
- <div className="space-y-1.5">
49
- {displayItems.map((item, i) => {
50
- const priorityColor = getPriorityColor(item.priority)
51
- const startHref = codeHref
52
- ? `${codeHref}?cmd=${encodeURIComponent(`p. now "${item.task}"`)}`
53
- : undefined
54
- const deleteHref = codeHref
55
- ? `${codeHref}?cmd=${encodeURIComponent(`p. queue remove ${i + 1}`)}`
56
- : undefined
57
-
58
- return (
59
- <div
60
- key={i}
61
- className="flex items-start gap-2 group py-1.5 hover:bg-muted/50 rounded px-1 -mx-1"
62
- >
63
- <span className={cn(
64
- "text-xs font-bold w-5 shrink-0 pt-0.5 tabular-nums",
65
- priorityColor
66
- )}>
67
- {i + 1}.
68
- </span>
69
- <div className="flex-1 min-w-0">
70
- <p className="text-sm leading-tight">
71
- {item.task}
72
- </p>
73
- {(item.suggestedAgent || item.estimatedDuration) && (
74
- <div className="flex items-center gap-2 mt-0.5">
75
- {item.suggestedAgent && (
76
- <span className="inline-flex items-center gap-0.5 text-xs text-muted-foreground">
77
- <Bot className="h-3 w-3" />
78
- {item.suggestedAgent}
79
- </span>
80
- )}
81
- {item.estimatedDuration && (
82
- <span className="text-xs text-muted-foreground">
83
- ~{item.estimatedDuration}
84
- </span>
85
- )}
86
- </div>
87
- )}
88
- </div>
89
- {/* Always visible action buttons */}
90
- <div className="flex items-center gap-1 shrink-0">
91
- {startHref && (
92
- <Link
93
- href={startHref}
94
- className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
95
- title="Start now"
96
- >
97
- <Play className="h-3.5 w-3.5" />
98
- </Link>
99
- )}
100
- {deleteHref && (
101
- <Link
102
- href={deleteHref}
103
- className="p-1 rounded hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
104
- title="Remove from queue"
105
- >
106
- <X className="h-3.5 w-3.5" />
107
- </Link>
108
- )}
109
- </div>
110
- </div>
111
- )
112
- })}
113
- {(hasMore || expanded) && queue.length > COLLAPSED_LIMIT && (
114
- <ExpandButton
115
- expanded={expanded}
116
- totalCount={queue.length}
117
- collapsedLimit={COLLAPSED_LIMIT}
118
- onToggle={() => setExpanded(!expanded)}
119
- />
120
- )}
121
- </div>
122
- )}
123
- </div>
124
- )
125
- }
@@ -1,12 +0,0 @@
1
- export interface QueueItem {
2
- task: string
3
- priority?: 'low' | 'medium' | 'high' | 'critical' | number
4
- suggestedAgent?: string
5
- estimatedDuration?: string
6
- }
7
-
8
- export interface QueueCardProps {
9
- queue: QueueItem[]
10
- codeHref?: string
11
- className?: string
12
- }