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