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,151 +0,0 @@
1
- 'use client'
2
-
3
- import { useQuery } from '@tanstack/react-query'
4
- import { useTheme } from 'next-themes'
5
- import { Settings as SettingsIcon, CheckCircle, XCircle, Terminal, Sun, Moon, Monitor } from 'lucide-react'
6
- import { Button } from '@/components/ui/button'
7
-
8
- export default function Settings() {
9
- const { theme, setTheme } = useTheme()
10
-
11
- const { data: claudeStatus } = useQuery({
12
- queryKey: ['claude-status'],
13
- queryFn: async () => {
14
- const res = await fetch('/api/claude/status')
15
- const json = await res.json()
16
- return json.data
17
- }
18
- })
19
-
20
- return (
21
- <div className="p-6 h-full overflow-auto">
22
- <header className="mb-6">
23
- <h1 className="text-2xl font-bold flex items-center gap-2">
24
- <SettingsIcon className="w-6 h-6" />
25
- Settings
26
- </h1>
27
- </header>
28
-
29
- <div className="space-y-6 max-w-2xl">
30
- {/* Appearance */}
31
- <section className="bg-card border border-border rounded-lg p-6">
32
- <h2 className="text-lg font-semibold mb-4 flex items-center gap-2">
33
- <Sun className="w-5 h-5" />
34
- Appearance
35
- </h2>
36
-
37
- <div className="space-y-4">
38
- <div>
39
- <p className="text-sm text-muted-foreground mb-3">
40
- Choose how prjct looks to you. Select a single theme, or sync with your system settings.
41
- </p>
42
- <div className="flex gap-2">
43
- <Button
44
- variant={theme === 'light' ? 'default' : 'outline'}
45
- size="sm"
46
- onClick={() => setTheme('light')}
47
- className="flex items-center gap-2"
48
- >
49
- <Sun className="w-4 h-4" />
50
- Light
51
- </Button>
52
- <Button
53
- variant={theme === 'dark' ? 'default' : 'outline'}
54
- size="sm"
55
- onClick={() => setTheme('dark')}
56
- className="flex items-center gap-2"
57
- >
58
- <Moon className="w-4 h-4" />
59
- Dark
60
- </Button>
61
- <Button
62
- variant={theme === 'system' ? 'default' : 'outline'}
63
- size="sm"
64
- onClick={() => setTheme('system')}
65
- className="flex items-center gap-2"
66
- >
67
- <Monitor className="w-4 h-4" />
68
- System
69
- </Button>
70
- </div>
71
- </div>
72
- </div>
73
- </section>
74
-
75
- {/* Claude Code Status */}
76
- <section className="bg-card border border-border rounded-lg p-6">
77
- <h2 className="text-lg font-semibold mb-4 flex items-center gap-2">
78
- <Terminal className="w-5 h-5" />
79
- Claude Code CLI
80
- </h2>
81
-
82
- <div className="flex items-center gap-3 mb-4">
83
- {claudeStatus?.available ? (
84
- <>
85
- <CheckCircle className="w-5 h-5 text-green-500" />
86
- <span className="text-green-500">Available</span>
87
- </>
88
- ) : (
89
- <>
90
- <XCircle className="w-5 h-5 text-red-500" />
91
- <span className="text-red-500">Not Found</span>
92
- </>
93
- )}
94
- </div>
95
-
96
- {claudeStatus?.version && (
97
- <p className="text-sm text-muted-foreground mb-4">
98
- Version: {claudeStatus.version}
99
- </p>
100
- )}
101
-
102
- <div className="bg-muted/50 rounded-md p-4 text-sm">
103
- <p className="font-medium mb-2">How it works:</p>
104
- <ul className="list-disc list-inside space-y-1 text-muted-foreground">
105
- <li>prjct uses Claude Code CLI via PTY (pseudo-terminal)</li>
106
- <li>Uses your existing Claude subscription (no API costs)</li>
107
- <li>Full Claude Code experience in your browser</li>
108
- <li>All tools work: Read, Write, Bash, etc.</li>
109
- </ul>
110
- </div>
111
-
112
- {!claudeStatus?.available && (
113
- <div className="mt-4 p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-md">
114
- <p className="text-sm text-yellow-500">
115
- Install Claude Code CLI from{' '}
116
- <a
117
- href="https://claude.ai/code"
118
- target="_blank"
119
- rel="noopener noreferrer"
120
- className="underline"
121
- >
122
- claude.ai/code
123
- </a>
124
- </p>
125
- </div>
126
- )}
127
- </section>
128
-
129
- {/* About */}
130
- <section className="bg-card border border-border rounded-lg p-6">
131
- <h2 className="text-lg font-semibold mb-4">About prjct</h2>
132
-
133
- <div className="space-y-2 text-sm text-muted-foreground">
134
- <p>
135
- <strong className="text-foreground">prjct</strong> is a developer momentum tool.
136
- </p>
137
- <p>
138
- Track progress, ship features, stay focused. Built for Claude.
139
- </p>
140
- </div>
141
-
142
- <div className="mt-4 pt-4 border-t border-border">
143
- <p className="text-xs text-muted-foreground">
144
- Version 0.1.0 • Made with prjct.app
145
- </p>
146
- </div>
147
- </section>
148
- </div>
149
- </div>
150
- )
151
- }
@@ -1,2 +0,0 @@
1
- export const TIMELINE_COLLAPSED_LIMIT = 8
2
- export const TIMELINE_EXPANDED_LIMIT = 20
@@ -1,49 +0,0 @@
1
- 'use client'
2
-
3
- import { Activity } from 'lucide-react'
4
- import { BentoCard } from '@/components/BentoCard'
5
- import { EmptyState } from '@/components/EmptyState'
6
- import { DateGroup } from '@/components/DateGroup'
7
- import { ExpandButton } from '@/components/ExpandButton'
8
- import { useExpandable, useGroupedEvents } from './hooks'
9
- import { TIMELINE_COLLAPSED_LIMIT, TIMELINE_EXPANDED_LIMIT } from './ActivityTimeline.constants'
10
- import type { ActivityTimelineProps } from './ActivityTimeline.types'
11
-
12
- export function ActivityTimeline({ timeline, className }: ActivityTimelineProps) {
13
- const { expanded, toggle } = useExpandable(false)
14
- const limit = expanded ? TIMELINE_EXPANDED_LIMIT : TIMELINE_COLLAPSED_LIMIT
15
- const { grouped, hasMore } = useGroupedEvents(timeline, limit)
16
-
17
- return (
18
- <BentoCard
19
- title="Recent Activity"
20
- icon={Activity}
21
- count={timeline.length > 0 ? `${timeline.length} events` : undefined}
22
- className={className}
23
- >
24
- {timeline.length === 0 ? (
25
- <EmptyState
26
- icon={Activity}
27
- title="No recent activity"
28
- description="Activity will appear as you work"
29
- compact
30
- />
31
- ) : (
32
- <div className="space-y-3 sm:space-y-4">
33
- {Array.from(grouped.entries()).map(([dateKey, events]) => (
34
- <DateGroup key={dateKey} dateKey={dateKey} events={events} />
35
- ))}
36
-
37
- {hasMore && (
38
- <ExpandButton
39
- expanded={expanded}
40
- totalCount={timeline.length}
41
- collapsedLimit={TIMELINE_COLLAPSED_LIMIT}
42
- onToggle={toggle}
43
- />
44
- )}
45
- </div>
46
- )}
47
- </BentoCard>
48
- )
49
- }
@@ -1,8 +0,0 @@
1
- import type { TimelineEvent } from '@/lib/parse-prjct-files'
2
-
3
- export type { TimelineEvent }
4
-
5
- export interface ActivityTimelineProps {
6
- timeline: TimelineEvent[]
7
- className?: string
8
- }
@@ -1,2 +0,0 @@
1
- export { useExpandable } from './useExpandable'
2
- export { useGroupedEvents } from './useGroupedEvents'
@@ -1,9 +0,0 @@
1
- 'use client'
2
-
3
- import { useState } from 'react'
4
-
5
- export function useExpandable(initialExpanded: boolean = false) {
6
- const [expanded, setExpanded] = useState(initialExpanded)
7
- const toggle = () => setExpanded(prev => !prev)
8
- return { expanded, toggle }
9
- }
@@ -1,23 +0,0 @@
1
- 'use client'
2
-
3
- import { useMemo } from 'react'
4
- import type { TimelineEvent } from '../ActivityTimeline.types'
5
-
6
- export function useGroupedEvents(events: TimelineEvent[], limit: number) {
7
- return useMemo(() => {
8
- const displayEvents = events.slice(0, limit)
9
- const groups = new Map<string, TimelineEvent[]>()
10
-
11
- displayEvents.forEach(event => {
12
- if (!event.ts) return
13
- const dateKey = event.ts.split('T')[0]
14
- const existing = groups.get(dateKey) ?? []
15
- groups.set(dateKey, [...existing, event])
16
- })
17
-
18
- return {
19
- grouped: groups,
20
- hasMore: events.length > limit,
21
- }
22
- }, [events, limit])
23
- }
@@ -1,2 +0,0 @@
1
- export { ActivityTimeline } from './ActivityTimeline'
2
- export type { ActivityTimelineProps } from './ActivityTimeline.types'
@@ -1,93 +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 { Bot, Star, TrendingUp, Wrench } from 'lucide-react'
7
- import { Badge } from '@/components/ui/badge'
8
- import { cn } from '@/lib/utils'
9
- import type { AgentsCardProps } from './AgentsCard.types'
10
-
11
- const COLLAPSED_LIMIT = 12
12
-
13
- export function AgentsCard({ agents, codeHref, className }: AgentsCardProps) {
14
- const [expanded, setExpanded] = useState(false)
15
- const displayAgents = expanded ? agents : agents.slice(0, COLLAPSED_LIMIT)
16
- const hasMore = agents.length > COLLAPSED_LIMIT
17
-
18
- return (
19
- <div className={cn(
20
- 'relative overflow-hidden rounded-xl border bg-card p-4',
21
- className
22
- )}>
23
- <div className="flex items-center justify-between mb-3">
24
- <div className="flex items-center gap-2">
25
- <Bot className="h-4 w-4 text-muted-foreground" />
26
- <span className="text-xs font-bold uppercase tracking-[0.15em] text-muted-foreground">
27
- Agents
28
- </span>
29
- </div>
30
- <span className="text-xs font-medium text-muted-foreground tabular-nums">
31
- {agents.length} available
32
- </span>
33
- </div>
34
-
35
- {agents.length === 0 ? (
36
- <EmptyState
37
- icon={Bot}
38
- title="No agents"
39
- description="Run /p:sync to generate"
40
- command="/p:sync"
41
- href={codeHref}
42
- compact
43
- />
44
- ) : (
45
- <div className="space-y-2">
46
- {displayAgents.map((agent) => {
47
- const hasPerformance = agent.successRate !== undefined
48
- const isTopPerformer = hasPerformance && agent.successRate! >= 80
49
-
50
- return (
51
- <div
52
- key={agent.name}
53
- className="flex items-center justify-between gap-2 py-1.5 px-2 rounded-lg -mx-2 hover:bg-muted/50"
54
- >
55
- <div className="flex items-center gap-2 min-w-0">
56
- {isTopPerformer ? (
57
- <Star className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
58
- ) : (
59
- <Wrench className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
60
- )}
61
- <span className="font-mono text-sm truncate">@{agent.name}</span>
62
- </div>
63
- <div className="flex items-center gap-2 shrink-0">
64
- {hasPerformance && (
65
- <span className="text-xs font-medium tabular-nums text-muted-foreground">
66
- {agent.successRate}%
67
- </span>
68
- )}
69
- {agent.improving && (
70
- <TrendingUp className="h-3 w-3 text-muted-foreground" />
71
- )}
72
- {agent.tasksCompleted !== undefined && agent.tasksCompleted > 0 && (
73
- <Badge variant="secondary" className="text-xs px-1.5 py-0 h-4">
74
- {agent.tasksCompleted} tasks
75
- </Badge>
76
- )}
77
- </div>
78
- </div>
79
- )
80
- })}
81
- {hasMore && (
82
- <ExpandButton
83
- expanded={expanded}
84
- totalCount={agents.length}
85
- collapsedLimit={COLLAPSED_LIMIT}
86
- onToggle={() => setExpanded(!expanded)}
87
- />
88
- )}
89
- </div>
90
- )}
91
- </div>
92
- )
93
- }
@@ -1,14 +0,0 @@
1
- export interface Agent {
2
- name: string
3
- description?: string
4
- successRate?: number
5
- tasksCompleted?: number
6
- improving?: boolean
7
- bestFor?: string[]
8
- }
9
-
10
- export interface AgentsCardProps {
11
- agents: Agent[]
12
- codeHref?: string
13
- className?: string
14
- }
@@ -1,2 +0,0 @@
1
- export { AgentsCard } from './AgentsCard'
2
- export type { AgentsCardProps } from './AgentsCard.types'
@@ -1,316 +0,0 @@
1
- 'use client'
2
-
3
- import Link from 'next/link'
4
- import { usePathname } from 'next/navigation'
5
- import {
6
- LayoutDashboard,
7
- Settings,
8
- HelpCircle,
9
- Menu,
10
- PanelLeft,
11
- Terminal,
12
- } from 'lucide-react'
13
- import { useGlobalTerminal } from '@/context/GlobalTerminalContext'
14
- import { Badge } from '@/components/ui/badge'
15
- import { ProjectSelectorModal } from '@/components/ProjectSelectorModal'
16
- import { Logo } from '@/components/Logo'
17
- import { cn } from '@/lib/utils'
18
- import { useState, useEffect } from 'react'
19
- import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
20
- import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
21
-
22
- const navItems = [
23
- { href: '/', icon: LayoutDashboard, label: 'Dashboard' },
24
- ]
25
-
26
- function SidebarContent({
27
- onNavigate,
28
- isCollapsed = false,
29
- onToggleCollapse,
30
- onTerminalClick,
31
- sessionCount
32
- }: {
33
- onNavigate?: () => void
34
- isCollapsed?: boolean
35
- onToggleCollapse?: () => void
36
- onTerminalClick?: () => void
37
- sessionCount?: number
38
- }) {
39
- const pathname = usePathname()
40
-
41
- return (
42
- <>
43
- {/* Header */}
44
- <div className={cn(
45
- "flex h-14 items-center border-b border-border",
46
- isCollapsed ? "justify-center px-2" : "justify-between px-3"
47
- )}>
48
- {!isCollapsed && (
49
- <Link href="/" onClick={onNavigate}>
50
- <Logo size="xs" showText rounded />
51
- </Link>
52
- )}
53
- {onToggleCollapse && (
54
- <Tooltip>
55
- <TooltipTrigger asChild>
56
- <button
57
- onClick={onToggleCollapse}
58
- className="h-8 w-8 rounded-md flex items-center justify-center text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors"
59
- aria-label={isCollapsed ? "Expand sidebar" : "Collapse sidebar"}
60
- >
61
- <PanelLeft className="h-4 w-4" />
62
- </button>
63
- </TooltipTrigger>
64
- <TooltipContent side="right">
65
- {isCollapsed ? "Expand" : "Collapse"}
66
- </TooltipContent>
67
- </Tooltip>
68
- )}
69
- </div>
70
-
71
- {/* Nav */}
72
- <nav className={cn("flex-1 overflow-y-auto py-4", isCollapsed ? "px-2" : "px-3")}>
73
- <div className="space-y-1">
74
- {navItems.map(({ href, icon: Icon, label }) => {
75
- const isActive = pathname === href || (href !== '/' && pathname.startsWith(href))
76
- const linkContent = (
77
- <Link
78
- key={href}
79
- href={href}
80
- onClick={onNavigate}
81
- className={cn(
82
- 'flex items-center rounded-md transition-colors min-h-[44px]',
83
- isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
84
- 'py-2.5',
85
- isActive
86
- ? 'bg-accent text-accent-foreground'
87
- : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
88
- )}
89
- >
90
- <Icon className="h-5 w-5 shrink-0" />
91
- {!isCollapsed && <span className="text-sm font-medium">{label}</span>}
92
- </Link>
93
- )
94
-
95
- if (isCollapsed) {
96
- return (
97
- <Tooltip key={href}>
98
- <TooltipTrigger asChild>{linkContent}</TooltipTrigger>
99
- <TooltipContent side="right">{label}</TooltipContent>
100
- </Tooltip>
101
- )
102
- }
103
- return linkContent
104
- })}
105
-
106
- {/* Terminal Button */}
107
- {onTerminalClick && (
108
- (() => {
109
- const terminalButton = (
110
- <button
111
- onClick={onTerminalClick}
112
- className={cn(
113
- 'flex items-center rounded-md transition-colors min-h-[44px] w-full',
114
- isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
115
- 'py-2.5',
116
- 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
117
- )}
118
- >
119
- <div className="relative">
120
- <Terminal className="h-5 w-5 shrink-0" />
121
- {sessionCount !== undefined && sessionCount > 0 && (
122
- <Badge
123
- className="absolute -top-2 -right-2 h-4 w-4 p-0 flex items-center justify-center text-[10px] bg-primary"
124
- >
125
- {sessionCount}
126
- </Badge>
127
- )}
128
- </div>
129
- {!isCollapsed && <span className="text-sm font-medium">Terminal</span>}
130
- </button>
131
- )
132
-
133
- if (isCollapsed) {
134
- return (
135
- <Tooltip key="terminal">
136
- <TooltipTrigger asChild>{terminalButton}</TooltipTrigger>
137
- <TooltipContent side="right">Terminal</TooltipContent>
138
- </Tooltip>
139
- )
140
- }
141
- return terminalButton
142
- })()
143
- )}
144
- </div>
145
- </nav>
146
-
147
- {/* Footer */}
148
- <div className={cn("border-t border-border space-y-1", isCollapsed ? "p-2" : "p-3")}>
149
- {[
150
- { href: '/settings', icon: Settings, label: 'Settings' },
151
- { href: '/help', icon: HelpCircle, label: 'Need help?' }
152
- ].map(({ href, icon: Icon, label }) => {
153
- const isActive = pathname === href
154
- const linkContent = (
155
- <Link
156
- key={href}
157
- href={href}
158
- onClick={onNavigate}
159
- className={cn(
160
- 'flex items-center rounded-md transition-colors min-h-[44px]',
161
- isCollapsed ? 'justify-center px-2' : 'gap-3 px-3',
162
- 'py-2.5',
163
- isActive
164
- ? 'bg-accent text-accent-foreground'
165
- : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
166
- )}
167
- >
168
- <Icon className="h-5 w-5 shrink-0" />
169
- {!isCollapsed && <span className="text-sm font-medium">{label}</span>}
170
- </Link>
171
- )
172
-
173
- if (isCollapsed) {
174
- return (
175
- <Tooltip key={href}>
176
- <TooltipTrigger asChild>{linkContent}</TooltipTrigger>
177
- <TooltipContent side="right">{label}</TooltipContent>
178
- </Tooltip>
179
- )
180
- }
181
- return linkContent
182
- })}
183
- </div>
184
- </>
185
- )
186
- }
187
-
188
- const SIDEBAR_COLLAPSED_KEY = 'prjct-sidebar-collapsed'
189
-
190
- export function AppSidebar() {
191
- const [isOpen, setIsOpen] = useState(false)
192
- const [isMobile, setIsMobile] = useState(false)
193
- const [isCollapsed, setIsCollapsed] = useState(false)
194
- const [showProjectSelector, setShowProjectSelector] = useState(false)
195
- const pathname = usePathname()
196
-
197
- // Terminal context
198
- const {
199
- toggleDock,
200
- openDock,
201
- getTotalSessionCount,
202
- projectSessions,
203
- createSessionForProject,
204
- } = useGlobalTerminal()
205
-
206
- const sessionCount = getTotalSessionCount()
207
-
208
- // Handle terminal button click
209
- const handleTerminalClick = () => {
210
- // If we're on a project page, auto-detect project
211
- const projectMatch = pathname?.match(/\/project\/([^/]+)/)
212
-
213
- if (projectMatch) {
214
- const projectId = projectMatch[1]
215
- const existingProject = projectSessions.get(projectId)
216
-
217
- if (existingProject) {
218
- // Project already has sessions, just toggle dock
219
- toggleDock()
220
- } else {
221
- // Need to show project selector to get project details
222
- // For now, open dock (will be empty) - the user should create session from the dock
223
- setShowProjectSelector(true)
224
- }
225
- } else if (sessionCount > 0) {
226
- // Has sessions, toggle dock
227
- toggleDock()
228
- } else {
229
- // No sessions and no project context - show project selector
230
- setShowProjectSelector(true)
231
- }
232
- }
233
-
234
- // Load collapsed state from localStorage on mount
235
- useEffect(() => {
236
- const stored = localStorage.getItem(SIDEBAR_COLLAPSED_KEY)
237
- if (stored !== null) {
238
- setIsCollapsed(stored === 'true')
239
- }
240
- }, [])
241
-
242
- // Persist collapsed state to localStorage
243
- const handleToggleCollapse = () => {
244
- const newValue = !isCollapsed
245
- setIsCollapsed(newValue)
246
- localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(newValue))
247
- }
248
-
249
- // Detect mobile on mount and resize
250
- useEffect(() => {
251
- const checkMobile = () => {
252
- setIsMobile(window.innerWidth < 768)
253
- }
254
- checkMobile()
255
- window.addEventListener('resize', checkMobile)
256
- return () => window.removeEventListener('resize', checkMobile)
257
- }, [])
258
-
259
- // Mobile: Sheet/Drawer
260
- if (isMobile) {
261
- return (
262
- <Sheet open={isOpen} onOpenChange={setIsOpen}>
263
- <SheetTrigger asChild>
264
- <button
265
- className="fixed top-3 left-3 z-50 h-10 w-10 rounded-lg bg-card border border-border flex items-center justify-center text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors shadow-sm"
266
- aria-label="Open menu"
267
- >
268
- <Menu className="h-5 w-5" />
269
- </button>
270
- </SheetTrigger>
271
- <SheetContent side="left" className="w-[280px] p-0 flex flex-col">
272
- <SidebarContent
273
- onNavigate={() => setIsOpen(false)}
274
- onTerminalClick={handleTerminalClick}
275
- sessionCount={sessionCount}
276
- />
277
- </SheetContent>
278
- </Sheet>
279
- )
280
- }
281
-
282
- // Desktop: Collapsible sidebar
283
- return (
284
- <>
285
- <aside className={cn(
286
- "hidden md:flex h-full flex-col border-r border-border bg-card transition-all duration-200",
287
- isCollapsed ? "w-14" : "w-60"
288
- )}>
289
- <SidebarContent
290
- isCollapsed={isCollapsed}
291
- onToggleCollapse={handleToggleCollapse}
292
- onTerminalClick={handleTerminalClick}
293
- sessionCount={sessionCount}
294
- />
295
- </aside>
296
-
297
- {/* Project Selector Modal - will be implemented separately */}
298
- {showProjectSelector && (
299
- <ProjectSelectorModal
300
- isOpen={showProjectSelector}
301
- onClose={() => setShowProjectSelector(false)}
302
- onSelectProject={(projectId, projectName, projectPath) => {
303
- createSessionForProject(projectId, projectName, projectPath)
304
- openDock()
305
- setShowProjectSelector(false)
306
- }}
307
- />
308
- )}
309
- </>
310
- )
311
- }
312
-
313
- // Mobile header spacer - use in pages that need top padding for the menu button
314
- export function MobileHeaderSpacer() {
315
- return <div className="h-16 md:h-0" />
316
- }