prjct-cli 0.11.4 → 0.12.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 (385) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +81 -25
  3. package/bin/dev.js +1 -1
  4. package/bin/generate-views.js +209 -0
  5. package/bin/migrate-to-json.js +742 -0
  6. package/bin/prjct +5 -5
  7. package/bin/serve.js +246 -54
  8. package/core/__tests__/agentic/{memory-system.test.js → memory-system.test.ts} +12 -23
  9. package/core/__tests__/agentic/{plan-mode.test.js → plan-mode.test.ts} +26 -24
  10. package/core/__tests__/agentic/{prompt-builder.test.js → prompt-builder.test.ts} +3 -8
  11. package/core/__tests__/utils/date-helper.test.ts +405 -0
  12. package/core/__tests__/utils/{output.test.js → output.test.ts} +12 -24
  13. package/core/agentic/agent-router.ts +137 -0
  14. package/core/agentic/chain-of-thought.ts +228 -0
  15. package/core/agentic/command-executor/command-executor.ts +384 -0
  16. package/core/agentic/command-executor/index.ts +16 -0
  17. package/core/agentic/command-executor/status-signal.ts +38 -0
  18. package/core/agentic/command-executor/types.ts +79 -0
  19. package/core/agentic/command-executor.ts +8 -0
  20. package/core/agentic/{context-builder.js → context-builder.ts} +99 -89
  21. package/core/agentic/context-filter.ts +365 -0
  22. package/core/agentic/ground-truth/index.ts +76 -0
  23. package/core/agentic/ground-truth/types.ts +33 -0
  24. package/core/agentic/ground-truth/utils.ts +48 -0
  25. package/core/agentic/ground-truth/verifiers/analyze.ts +54 -0
  26. package/core/agentic/ground-truth/verifiers/done.ts +75 -0
  27. package/core/agentic/ground-truth/verifiers/feature.ts +70 -0
  28. package/core/agentic/ground-truth/verifiers/index.ts +37 -0
  29. package/core/agentic/ground-truth/verifiers/init.ts +52 -0
  30. package/core/agentic/ground-truth/verifiers/now.ts +57 -0
  31. package/core/agentic/ground-truth/verifiers/ship.ts +85 -0
  32. package/core/agentic/ground-truth/verifiers/spec.ts +45 -0
  33. package/core/agentic/ground-truth/verifiers/sync.ts +47 -0
  34. package/core/agentic/ground-truth/verifiers.ts +6 -0
  35. package/core/agentic/ground-truth.ts +8 -0
  36. package/core/agentic/loop-detector/error-analysis.ts +97 -0
  37. package/core/agentic/loop-detector/hallucination.ts +71 -0
  38. package/core/agentic/loop-detector/index.ts +41 -0
  39. package/core/agentic/loop-detector/loop-detector.ts +222 -0
  40. package/core/agentic/loop-detector/types.ts +66 -0
  41. package/core/agentic/loop-detector.ts +8 -0
  42. package/core/agentic/memory-system/history.ts +53 -0
  43. package/core/agentic/memory-system/index.ts +192 -0
  44. package/core/agentic/memory-system/patterns.ts +156 -0
  45. package/core/agentic/memory-system/semantic-memories.ts +277 -0
  46. package/core/agentic/memory-system/session.ts +21 -0
  47. package/core/agentic/memory-system/types.ts +159 -0
  48. package/core/agentic/memory-system.ts +8 -0
  49. package/core/agentic/parallel-tools.ts +165 -0
  50. package/core/agentic/plan-mode/approval.ts +57 -0
  51. package/core/agentic/plan-mode/constants.ts +44 -0
  52. package/core/agentic/plan-mode/index.ts +28 -0
  53. package/core/agentic/plan-mode/plan-mode.ts +406 -0
  54. package/core/agentic/plan-mode/types.ts +193 -0
  55. package/core/agentic/plan-mode.ts +8 -0
  56. package/core/agentic/prompt-builder.ts +566 -0
  57. package/core/agentic/response-templates.ts +164 -0
  58. package/core/agentic/semantic-compression.ts +273 -0
  59. package/core/agentic/services.ts +206 -0
  60. package/core/agentic/smart-context.ts +476 -0
  61. package/core/agentic/{template-loader.js → template-loader.ts} +35 -18
  62. package/core/agentic/think-blocks.ts +202 -0
  63. package/core/agentic/tool-registry.ts +119 -0
  64. package/core/agentic/validation-rules.ts +313 -0
  65. package/core/agents/index.ts +28 -0
  66. package/core/agents/performance.ts +444 -0
  67. package/core/agents/types.ts +126 -0
  68. package/core/bus/{index.js → index.ts} +57 -61
  69. package/core/command-registry/categories.ts +23 -0
  70. package/core/command-registry/commands.ts +15 -0
  71. package/core/command-registry/core-commands.ts +319 -0
  72. package/core/command-registry/index.ts +158 -0
  73. package/core/command-registry/optional-commands.ts +119 -0
  74. package/core/command-registry/setup-commands.ts +53 -0
  75. package/core/command-registry/types.ts +59 -0
  76. package/core/command-registry.ts +9 -0
  77. package/core/commands/analysis.ts +298 -0
  78. package/core/commands/analytics.ts +288 -0
  79. package/core/commands/base.ts +273 -0
  80. package/core/commands/index.ts +211 -0
  81. package/core/commands/maintenance.ts +226 -0
  82. package/core/commands/planning.ts +311 -0
  83. package/core/commands/setup.ts +309 -0
  84. package/core/commands/shipping.ts +188 -0
  85. package/core/commands/types.ts +183 -0
  86. package/core/commands/workflow.ts +226 -0
  87. package/core/commands.ts +11 -0
  88. package/core/constants/formats.ts +187 -0
  89. package/core/constants/index.ts +7 -0
  90. package/core/{context-sync.js → context-sync.ts} +59 -26
  91. package/core/data/agents-manager.ts +76 -0
  92. package/core/data/analysis-manager.ts +83 -0
  93. package/core/data/base-manager.ts +156 -0
  94. package/core/data/ideas-manager.ts +81 -0
  95. package/core/data/index.ts +32 -0
  96. package/core/data/outcomes-manager.ts +96 -0
  97. package/core/data/project-manager.ts +75 -0
  98. package/core/data/roadmap-manager.ts +118 -0
  99. package/core/data/shipped-manager.ts +65 -0
  100. package/core/data/state-manager.ts +214 -0
  101. package/core/domain/{agent-generator.js → agent-generator.ts} +77 -57
  102. package/core/domain/{agent-loader.js → agent-loader.ts} +65 -56
  103. package/core/domain/{agent-matcher.js → agent-matcher.ts} +51 -24
  104. package/core/domain/{agent-validator.js → agent-validator.ts} +70 -37
  105. package/core/domain/{analyzer.js → analyzer.ts} +91 -85
  106. package/core/domain/{architect-session.js → architect-session.ts} +49 -34
  107. package/core/domain/{architecture-generator.js → architecture-generator.ts} +25 -13
  108. package/core/domain/{context-estimator.js → context-estimator.ts} +57 -36
  109. package/core/domain/{product-standards.js → product-standards.ts} +40 -26
  110. package/core/domain/{smart-cache.js → smart-cache.ts} +39 -30
  111. package/core/domain/{snapshot-manager.js → snapshot-manager.ts} +103 -100
  112. package/core/domain/{task-analyzer.js → task-analyzer.ts} +82 -43
  113. package/core/domain/task-stack/index.ts +19 -0
  114. package/core/domain/task-stack/parser.ts +86 -0
  115. package/core/domain/task-stack/storage.ts +123 -0
  116. package/core/domain/task-stack/task-stack.ts +340 -0
  117. package/core/domain/task-stack/types.ts +51 -0
  118. package/core/domain/task-stack.ts +8 -0
  119. package/core/{index.js → index.ts} +61 -18
  120. package/core/infrastructure/{agent-detector.js → agent-detector.ts} +62 -23
  121. package/core/infrastructure/agents/{claude-agent.js → claude-agent.ts} +61 -21
  122. package/core/infrastructure/{author-detector.js → author-detector.ts} +42 -49
  123. package/core/infrastructure/{capability-installer.js → capability-installer.ts} +51 -27
  124. package/core/infrastructure/{command-installer.js → command-installer/command-installer.ts} +43 -144
  125. package/core/infrastructure/command-installer/global-config.ts +106 -0
  126. package/core/infrastructure/command-installer/index.ts +25 -0
  127. package/core/infrastructure/command-installer/types.ts +41 -0
  128. package/core/infrastructure/command-installer.ts +8 -0
  129. package/core/infrastructure/{config-manager.js → config-manager.ts} +60 -80
  130. package/core/infrastructure/{editors-config.js → editors-config.ts} +33 -31
  131. package/core/infrastructure/legacy-installer-detector/cleanup.ts +216 -0
  132. package/core/infrastructure/legacy-installer-detector/detection.ts +95 -0
  133. package/core/infrastructure/legacy-installer-detector/index.ts +171 -0
  134. package/core/infrastructure/legacy-installer-detector/migration.ts +87 -0
  135. package/core/infrastructure/legacy-installer-detector/types.ts +42 -0
  136. package/core/infrastructure/legacy-installer-detector.ts +7 -0
  137. package/core/infrastructure/migrator/file-operations.ts +125 -0
  138. package/core/infrastructure/migrator/index.ts +288 -0
  139. package/core/infrastructure/migrator/project-scanner.ts +89 -0
  140. package/core/infrastructure/migrator/reports.ts +117 -0
  141. package/core/infrastructure/migrator/types.ts +124 -0
  142. package/core/infrastructure/migrator/validation.ts +94 -0
  143. package/core/infrastructure/migrator/version-migration.ts +117 -0
  144. package/core/infrastructure/migrator.ts +10 -0
  145. package/core/infrastructure/{path-manager.js → path-manager.ts} +51 -91
  146. package/core/infrastructure/session-manager/index.ts +23 -0
  147. package/core/infrastructure/session-manager/migration.ts +88 -0
  148. package/core/infrastructure/session-manager/session-manager.ts +307 -0
  149. package/core/infrastructure/session-manager/types.ts +45 -0
  150. package/core/infrastructure/session-manager.ts +8 -0
  151. package/core/infrastructure/{setup.js → setup.ts} +29 -21
  152. package/core/infrastructure/{update-checker.js → update-checker.ts} +40 -18
  153. package/core/outcomes/analyzer.ts +333 -0
  154. package/core/outcomes/index.ts +34 -0
  155. package/core/outcomes/recorder.ts +194 -0
  156. package/core/outcomes/types.ts +145 -0
  157. package/core/plugin/{hooks.js → hooks.ts} +56 -58
  158. package/core/plugin/{index.js → index.ts} +19 -8
  159. package/core/plugin/{loader.js → loader.ts} +87 -69
  160. package/core/plugin/{registry.js → registry.ts} +49 -45
  161. package/core/plugins/{webhook.js → webhook.ts} +43 -27
  162. package/core/schemas/agents.ts +27 -0
  163. package/core/schemas/analysis.ts +41 -0
  164. package/core/schemas/ideas.ts +83 -0
  165. package/core/schemas/index.ts +73 -0
  166. package/core/schemas/outcomes.ts +22 -0
  167. package/core/schemas/project.ts +26 -0
  168. package/core/schemas/roadmap.ts +90 -0
  169. package/core/schemas/shipped.ts +82 -0
  170. package/core/schemas/state.ts +107 -0
  171. package/core/session/index.ts +17 -0
  172. package/core/session/{metrics.js → metrics.ts} +64 -46
  173. package/core/session/{index.js → session-manager.ts} +51 -117
  174. package/core/session/types.ts +29 -0
  175. package/core/session/utils.ts +57 -0
  176. package/core/state/index.ts +25 -0
  177. package/core/state/manager.ts +376 -0
  178. package/core/state/types.ts +185 -0
  179. package/core/tsconfig.json +22 -0
  180. package/core/types/index.ts +506 -0
  181. package/core/utils/{animations.js → animations.ts} +74 -28
  182. package/core/utils/{branding.js → branding.ts} +29 -4
  183. package/core/utils/{date-helper.js → date-helper.ts} +31 -74
  184. package/core/utils/file-helper.ts +262 -0
  185. package/core/utils/{jsonl-helper.js → jsonl-helper.ts} +71 -107
  186. package/core/utils/{logger.js → logger.ts} +24 -12
  187. package/core/utils/{output.js → output.ts} +25 -13
  188. package/core/utils/{project-capabilities.js → project-capabilities.ts} +31 -18
  189. package/core/utils/{session-helper.js → session-helper.ts} +79 -66
  190. package/core/utils/{version.js → version.ts} +23 -31
  191. package/core/view-generator.ts +536 -0
  192. package/package.json +23 -17
  193. package/packages/shared/.turbo/turbo-build.log +14 -0
  194. package/packages/shared/dist/index.d.ts +8 -613
  195. package/packages/shared/dist/index.d.ts.map +1 -0
  196. package/packages/shared/dist/index.js +4110 -118
  197. package/packages/shared/dist/schemas.d.ts +408 -0
  198. package/packages/shared/dist/schemas.d.ts.map +1 -0
  199. package/packages/shared/dist/types.d.ts +144 -0
  200. package/packages/shared/dist/types.d.ts.map +1 -0
  201. package/packages/shared/dist/unified.d.ts +139 -0
  202. package/packages/shared/dist/unified.d.ts.map +1 -0
  203. package/packages/shared/dist/utils.d.ts +60 -0
  204. package/packages/shared/dist/utils.d.ts.map +1 -0
  205. package/packages/shared/package.json +4 -4
  206. package/packages/shared/src/index.ts +1 -0
  207. package/packages/shared/src/unified.ts +174 -0
  208. package/packages/web/app/api/claude/sessions/route.ts +1 -1
  209. package/packages/web/app/api/claude/status/route.ts +1 -1
  210. package/packages/web/app/api/migrate/route.ts +46 -0
  211. package/packages/web/app/api/projects/[id]/route.ts +1 -1
  212. package/packages/web/app/api/projects/[id]/stats/route.ts +30 -2
  213. package/packages/web/app/api/projects/[id]/status/route.ts +1 -1
  214. package/packages/web/app/api/projects/route.ts +1 -1
  215. package/packages/web/app/api/settings/route.ts +97 -0
  216. package/packages/web/app/api/v2/projects/[id]/unified/route.ts +57 -0
  217. package/packages/web/app/globals.css +38 -0
  218. package/packages/web/app/layout.tsx +10 -2
  219. package/packages/web/app/page.tsx +9 -224
  220. package/packages/web/app/project/[id]/page.tsx +191 -63
  221. package/packages/web/app/project/[id]/stats/loading.tsx +43 -0
  222. package/packages/web/app/project/[id]/stats/page.tsx +203 -403
  223. package/packages/web/app/settings/page.tsx +222 -2
  224. package/packages/web/components/ActivityTimeline/ActivityTimeline.constants.ts +2 -0
  225. package/packages/web/components/ActivityTimeline/ActivityTimeline.tsx +50 -0
  226. package/packages/web/components/ActivityTimeline/ActivityTimeline.types.ts +8 -0
  227. package/packages/web/components/ActivityTimeline/hooks/index.ts +2 -0
  228. package/packages/web/components/ActivityTimeline/hooks/useExpandable.ts +9 -0
  229. package/packages/web/components/ActivityTimeline/hooks/useGroupedEvents.ts +23 -0
  230. package/packages/web/components/ActivityTimeline/index.ts +2 -0
  231. package/packages/web/components/AgentsCard/AgentsCard.tsx +63 -0
  232. package/packages/web/components/AgentsCard/AgentsCard.types.ts +13 -0
  233. package/packages/web/components/AgentsCard/index.ts +2 -0
  234. package/packages/web/components/AppSidebar/AppSidebar.tsx +134 -0
  235. package/packages/web/components/AppSidebar/index.ts +1 -0
  236. package/packages/web/components/BackLink/BackLink.tsx +18 -0
  237. package/packages/web/components/BackLink/BackLink.types.ts +5 -0
  238. package/packages/web/components/BackLink/index.ts +2 -0
  239. package/packages/web/components/BentoCard/BentoCard.constants.ts +16 -0
  240. package/packages/web/components/BentoCard/BentoCard.tsx +47 -0
  241. package/packages/web/components/BentoCard/BentoCard.types.ts +15 -0
  242. package/packages/web/components/BentoCard/index.ts +2 -0
  243. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.constants.ts +9 -0
  244. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.tsx +18 -0
  245. package/packages/web/components/BentoCardSkeleton/BentoCardSkeleton.types.ts +5 -0
  246. package/packages/web/components/BentoCardSkeleton/index.ts +2 -0
  247. package/packages/web/components/BentoGrid/BentoGrid.tsx +18 -0
  248. package/packages/web/components/BentoGrid/BentoGrid.types.ts +4 -0
  249. package/packages/web/components/BentoGrid/index.ts +2 -0
  250. package/packages/web/components/CommandButton/index.ts +1 -0
  251. package/packages/web/components/ConnectionStatus/index.ts +1 -0
  252. package/packages/web/components/DashboardContent/DashboardContent.tsx +254 -0
  253. package/packages/web/components/DashboardContent/index.ts +1 -0
  254. package/packages/web/components/DateGroup/DateGroup.tsx +18 -0
  255. package/packages/web/components/DateGroup/DateGroup.types.ts +6 -0
  256. package/packages/web/components/DateGroup/DateGroup.utils.ts +11 -0
  257. package/packages/web/components/DateGroup/index.ts +2 -0
  258. package/packages/web/components/EmptyState/EmptyState.tsx +58 -0
  259. package/packages/web/components/EmptyState/EmptyState.types.ts +10 -0
  260. package/packages/web/components/EmptyState/index.ts +2 -0
  261. package/packages/web/components/EventRow/EventRow.constants.ts +10 -0
  262. package/packages/web/components/EventRow/EventRow.tsx +49 -0
  263. package/packages/web/components/EventRow/EventRow.types.ts +7 -0
  264. package/packages/web/components/EventRow/EventRow.utils.ts +49 -0
  265. package/packages/web/components/EventRow/index.ts +2 -0
  266. package/packages/web/components/ExpandButton/ExpandButton.tsx +18 -0
  267. package/packages/web/components/ExpandButton/ExpandButton.types.ts +6 -0
  268. package/packages/web/components/ExpandButton/index.ts +2 -0
  269. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.tsx +14 -0
  270. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.types.ts +5 -0
  271. package/packages/web/components/HealthGradientBackground/HealthGradientBackground.utils.ts +13 -0
  272. package/packages/web/components/HealthGradientBackground/index.ts +2 -0
  273. package/packages/web/components/HeroSection/HeroSection.tsx +55 -0
  274. package/packages/web/components/HeroSection/HeroSection.types.ts +14 -0
  275. package/packages/web/components/HeroSection/HeroSection.utils.ts +7 -0
  276. package/packages/web/components/HeroSection/hooks/index.ts +2 -0
  277. package/packages/web/components/HeroSection/hooks/useCountUp.ts +45 -0
  278. package/packages/web/components/HeroSection/hooks/useWeeklyActivity.ts +18 -0
  279. package/packages/web/components/HeroSection/index.ts +2 -0
  280. package/packages/web/components/IdeasCard/IdeasCard.tsx +48 -0
  281. package/packages/web/components/IdeasCard/IdeasCard.types.ts +9 -0
  282. package/packages/web/components/IdeasCard/index.ts +2 -0
  283. package/packages/web/components/InsightMessage/InsightMessage.tsx +9 -0
  284. package/packages/web/components/InsightMessage/InsightMessage.types.ts +3 -0
  285. package/packages/web/components/InsightMessage/index.ts +2 -0
  286. package/packages/web/components/Logo/index.ts +1 -0
  287. package/packages/web/components/MarkdownContent/index.ts +1 -0
  288. package/packages/web/components/NowCard/NowCard.tsx +93 -0
  289. package/packages/web/components/NowCard/NowCard.types.ts +15 -0
  290. package/packages/web/components/NowCard/index.ts +2 -0
  291. package/packages/web/components/ProgressRing/ProgressRing.constants.ts +20 -0
  292. package/packages/web/components/ProgressRing/ProgressRing.tsx +51 -0
  293. package/packages/web/components/ProgressRing/ProgressRing.types.ts +11 -0
  294. package/packages/web/components/ProgressRing/index.ts +2 -0
  295. package/packages/web/components/ProjectAvatar/index.ts +1 -0
  296. package/packages/web/components/Providers/index.ts +1 -0
  297. package/packages/web/components/QueueCard/QueueCard.tsx +72 -0
  298. package/packages/web/components/QueueCard/QueueCard.types.ts +11 -0
  299. package/packages/web/components/QueueCard/QueueCard.utils.ts +12 -0
  300. package/packages/web/components/QueueCard/index.ts +2 -0
  301. package/packages/web/components/RoadmapCard/RoadmapCard.tsx +77 -0
  302. package/packages/web/components/RoadmapCard/RoadmapCard.types.ts +15 -0
  303. package/packages/web/components/RoadmapCard/index.ts +2 -0
  304. package/packages/web/components/ShipsCard/ShipsCard.tsx +52 -0
  305. package/packages/web/components/ShipsCard/ShipsCard.types.ts +12 -0
  306. package/packages/web/components/ShipsCard/ShipsCard.utils.ts +4 -0
  307. package/packages/web/components/ShipsCard/index.ts +2 -0
  308. package/packages/web/components/SparklineChart/SparklineChart.tsx +38 -0
  309. package/packages/web/components/SparklineChart/SparklineChart.types.ts +6 -0
  310. package/packages/web/components/SparklineChart/index.ts +2 -0
  311. package/packages/web/components/StreakCard/StreakCard.constants.ts +2 -0
  312. package/packages/web/components/StreakCard/StreakCard.tsx +53 -0
  313. package/packages/web/components/StreakCard/StreakCard.types.ts +4 -0
  314. package/packages/web/components/StreakCard/index.ts +2 -0
  315. package/packages/web/components/TasksCounter/TasksCounter.tsx +14 -0
  316. package/packages/web/components/TasksCounter/TasksCounter.types.ts +3 -0
  317. package/packages/web/components/TasksCounter/index.ts +2 -0
  318. package/packages/web/components/TechStackBadges/index.ts +1 -0
  319. package/packages/web/components/{TerminalTab.tsx → TerminalTabs/TerminalTab.tsx} +11 -0
  320. package/packages/web/components/{TerminalTabs.tsx → TerminalTabs/TerminalTabs.tsx} +29 -28
  321. package/packages/web/components/TerminalTabs/index.ts +1 -0
  322. package/packages/web/components/VelocityBadge/VelocityBadge.tsx +27 -0
  323. package/packages/web/components/VelocityBadge/VelocityBadge.types.ts +3 -0
  324. package/packages/web/components/VelocityBadge/index.ts +2 -0
  325. package/packages/web/components/VelocityCard/VelocityCard.tsx +71 -0
  326. package/packages/web/components/VelocityCard/VelocityCard.types.ts +7 -0
  327. package/packages/web/components/VelocityCard/index.ts +2 -0
  328. package/packages/web/components/WeeklySparkline/WeeklySparkline.tsx +13 -0
  329. package/packages/web/components/WeeklySparkline/WeeklySparkline.types.ts +3 -0
  330. package/packages/web/components/WeeklySparkline/index.ts +2 -0
  331. package/packages/web/components/ui/input.tsx +21 -0
  332. package/packages/web/components/ui/tooltip.tsx +2 -2
  333. package/packages/web/context/TerminalTabsContext.tsx +46 -1
  334. package/packages/web/hooks/useClaudeTerminal.ts +71 -21
  335. package/packages/web/hooks/useProjectStats.ts +55 -0
  336. package/packages/web/hooks/useProjects.ts +6 -6
  337. package/packages/web/lib/actions/projects.ts +15 -0
  338. package/packages/web/lib/json-loader.ts +630 -0
  339. package/packages/web/lib/services/index.ts +9 -0
  340. package/packages/web/lib/services/migration.server.ts +598 -0
  341. package/packages/web/lib/services/projects.server.ts +52 -0
  342. package/packages/web/lib/services/stats.server.ts +264 -0
  343. package/packages/web/lib/unified-loader.ts +396 -0
  344. package/packages/web/next-env.d.ts +1 -1
  345. package/packages/web/package.json +10 -6
  346. package/packages/web/server.ts +36 -6
  347. package/templates/commands/done.md +76 -32
  348. package/templates/commands/feature.md +121 -47
  349. package/templates/commands/idea.md +81 -8
  350. package/templates/commands/now.md +41 -17
  351. package/templates/commands/ship.md +64 -25
  352. package/templates/commands/sync.md +28 -3
  353. package/core/agentic/agent-router.js +0 -128
  354. package/core/agentic/chain-of-thought.js +0 -578
  355. package/core/agentic/command-executor.js +0 -421
  356. package/core/agentic/context-filter.js +0 -354
  357. package/core/agentic/ground-truth.js +0 -591
  358. package/core/agentic/loop-detector.js +0 -406
  359. package/core/agentic/memory-system.js +0 -850
  360. package/core/agentic/parallel-tools.js +0 -366
  361. package/core/agentic/plan-mode.js +0 -572
  362. package/core/agentic/prompt-builder.js +0 -338
  363. package/core/agentic/response-templates.js +0 -290
  364. package/core/agentic/semantic-compression.js +0 -517
  365. package/core/agentic/think-blocks.js +0 -657
  366. package/core/agentic/tool-registry.js +0 -184
  367. package/core/agentic/validation-rules.js +0 -380
  368. package/core/command-registry.js +0 -698
  369. package/core/commands.js +0 -2237
  370. package/core/domain/task-stack.js +0 -497
  371. package/core/infrastructure/legacy-installer-detector.js +0 -546
  372. package/core/infrastructure/migrator.js +0 -799
  373. package/core/infrastructure/session-manager.js +0 -390
  374. package/core/utils/file-helper.js +0 -329
  375. package/packages/web/app/api/projects/[id]/delete/route.ts +0 -21
  376. package/packages/web/app/api/stats/route.ts +0 -38
  377. package/packages/web/components/AppSidebar.tsx +0 -113
  378. package/packages/web/hooks/useStats.ts +0 -28
  379. /package/packages/web/components/{CommandButton.tsx → CommandButton/CommandButton.tsx} +0 -0
  380. /package/packages/web/components/{ConnectionStatus.tsx → ConnectionStatus/ConnectionStatus.tsx} +0 -0
  381. /package/packages/web/components/{Logo.tsx → Logo/Logo.tsx} +0 -0
  382. /package/packages/web/components/{MarkdownContent.tsx → MarkdownContent/MarkdownContent.tsx} +0 -0
  383. /package/packages/web/components/{ProjectAvatar.tsx → ProjectAvatar/ProjectAvatar.tsx} +0 -0
  384. /package/packages/web/components/{providers.tsx → Providers/Providers.tsx} +0 -0
  385. /package/packages/web/components/{TechStackBadges.tsx → TechStackBadges/TechStackBadges.tsx} +0 -0
@@ -1,227 +1,12 @@
1
- 'use client'
1
+ import { getProjects } from '@/lib/services/projects.server'
2
+ import { getGlobalStats } from '@/lib/services/stats.server'
3
+ import { DashboardContent } from '@/components/DashboardContent'
2
4
 
3
- import { useState, useCallback } from 'react'
4
- import Link from 'next/link'
5
- import { SessionsChart } from '@/components/charts/SessionsChart'
6
- import { Button } from '@/components/ui/button'
7
- import { ProjectAvatar } from '@/components/ProjectAvatar'
8
- import { TechStackBadges } from '@/components/TechStackBadges'
9
- import { formatRelativeTime, formatPath } from '@/lib/format'
10
- import { useProjects, useDeleteProject, type Project } from '@/hooks/useProjects'
11
- import { useStats } from '@/hooks/useStats'
12
- import {
13
- MoreHorizontal,
14
- Trash2,
15
- AlertTriangle,
16
- Target,
17
- Lightbulb,
18
- ListTodo,
19
- Zap,
20
- FolderGit2
21
- } from 'lucide-react'
22
- import {
23
- DropdownMenu,
24
- DropdownMenuContent,
25
- DropdownMenuItem,
26
- DropdownMenuTrigger,
27
- } from '@/components/ui/dropdown-menu'
28
- import {
29
- AlertDialog,
30
- AlertDialogAction,
31
- AlertDialogCancel,
32
- AlertDialogContent,
33
- AlertDialogDescription,
34
- AlertDialogFooter,
35
- AlertDialogHeader,
36
- AlertDialogTitle,
37
- } from '@/components/ui/alert-dialog'
5
+ export default async function Dashboard() {
6
+ const [projects, stats] = await Promise.all([
7
+ getProjects(),
8
+ getGlobalStats()
9
+ ])
38
10
 
39
- export default function Dashboard() {
40
- const [projectToDelete, setProjectToDelete] = useState<Project | null>(null)
41
-
42
- const { data: projects, isLoading: projectsLoading } = useProjects()
43
- const { data: stats } = useStats()
44
- const deleteMutation = useDeleteProject()
45
-
46
- const handleDeleteClick = useCallback((project: Project, e: React.MouseEvent) => {
47
- e.preventDefault()
48
- e.stopPropagation()
49
- setProjectToDelete(project)
50
- }, [])
51
-
52
- const handleConfirmDelete = useCallback(() => {
53
- if (projectToDelete) {
54
- deleteMutation.mutate(projectToDelete.id, {
55
- onSuccess: () => setProjectToDelete(null)
56
- })
57
- }
58
- }, [projectToDelete, deleteMutation])
59
-
60
- if (projectsLoading) {
61
- return (
62
- <div className="flex items-center justify-center h-full">
63
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary" />
64
- </div>
65
- )
66
- }
67
-
68
- const projectCount = projects?.length || 0
69
-
70
- return (
71
- <div className="p-8 h-full overflow-auto">
72
- <p className="text-muted-foreground">Hola! {stats?.userName || 'Developer'}</p>
73
-
74
- <h1 className="text-8xl font-bold tracking-tighter tabular-nums mt-2">{projectCount}</h1>
75
- <p className="text-muted-foreground mt-1">{projectCount === 1 ? 'project' : 'projects'}</p>
76
-
77
- <section className="mt-8">
78
- <SessionsChart />
79
- </section>
80
-
81
- <section className="mt-12">
82
- <h2 className="font-bold uppercase tracking-wide text-muted-foreground mb-6">Active Projects</h2>
83
-
84
- {projects?.length === 0 ? (
85
- <div className="border-2 border-dashed border-border rounded-xl p-8 text-center">
86
- <p className="text-muted-foreground">
87
- No projects yet. Initialize with <code className="bg-muted px-2 py-1 rounded font-mono">/p:init</code>
88
- </p>
89
- </div>
90
- ) : (
91
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
92
- {projects?.map((project: Project) => (
93
- <ProjectCard key={project.id} project={project} onDeleteClick={handleDeleteClick} />
94
- ))}
95
- </div>
96
- )}
97
- </section>
98
-
99
- <AlertDialog open={!!projectToDelete} onOpenChange={(open: boolean) => !open && setProjectToDelete(null)}>
100
- <AlertDialogContent>
101
- <AlertDialogHeader>
102
- <AlertDialogTitle className="flex items-center gap-2">
103
- <AlertTriangle className="w-5 h-5 text-destructive" />
104
- Delete Project?
105
- </AlertDialogTitle>
106
- <AlertDialogDescription>
107
- <strong>&quot;{projectToDelete?.name}&quot;</strong> will be moved to trash.
108
- <br />
109
- <span className="text-muted-foreground text-sm">
110
- Location: ~/.prjct-cli/.trash/{projectToDelete?.id}
111
- </span>
112
- </AlertDialogDescription>
113
- </AlertDialogHeader>
114
- <AlertDialogFooter>
115
- <AlertDialogCancel disabled={deleteMutation.isPending}>Cancel</AlertDialogCancel>
116
- <AlertDialogAction
117
- onClick={handleConfirmDelete}
118
- disabled={deleteMutation.isPending}
119
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
120
- >
121
- {deleteMutation.isPending ? 'Deleting...' : 'Delete'}
122
- </AlertDialogAction>
123
- </AlertDialogFooter>
124
- </AlertDialogContent>
125
- </AlertDialog>
126
- </div>
127
- )
128
- }
129
-
130
- interface ProjectCardProps {
131
- project: Project
132
- onDeleteClick: (project: Project, e: React.MouseEvent) => void
133
- }
134
-
135
- function ProjectCard({ project, onDeleteClick }: ProjectCardProps) {
136
- const hasStats = project.currentTask || project.nextTasksCount || project.ideasCount || project.lastActivity
137
-
138
- return (
139
- <div className="group relative bg-card border border-border rounded-lg overflow-hidden hover:border-primary/50 transition-all">
140
- {project.hasActiveSession && <div className="absolute top-0 left-0 right-0 h-0.5 bg-green-500" />}
141
-
142
- <Link href={`/project/${project.id}`} className="block p-4">
143
- <div className="flex items-start gap-3">
144
- <ProjectAvatar projectId={project.id} name={project.name} iconPath={project.iconPath} size="lg" />
145
-
146
- <div className="flex-1 min-w-0">
147
- <div className="flex items-center gap-2">
148
- <h3 className="font-bold truncate">{project.name}</h3>
149
- {project.hasActiveSession && (
150
- <span className="flex h-2 w-2">
151
- <span className="animate-ping absolute inline-flex h-2 w-2 rounded-full bg-green-400 opacity-75" />
152
- <span className="relative inline-flex rounded-full h-2 w-2 bg-green-500" />
153
- </span>
154
- )}
155
- </div>
156
- {project.repoPath && (
157
- <p className="text-xs text-muted-foreground truncate mt-0.5 flex items-center gap-1">
158
- <FolderGit2 className="w-3 h-3 shrink-0" />
159
- {formatPath(project.repoPath)}
160
- </p>
161
- )}
162
- </div>
163
- </div>
164
-
165
- {project.currentTask && (
166
- <div className="mt-3 p-2 bg-primary/5 rounded border border-primary/10">
167
- <div className="flex items-start gap-2">
168
- <Target className="w-3.5 h-3.5 text-primary shrink-0 mt-0.5" />
169
- <span className="text-sm text-foreground line-clamp-2">{project.currentTask}</span>
170
- </div>
171
- </div>
172
- )}
173
-
174
- {hasStats && (
175
- <div className="mt-3 flex items-center gap-3 text-xs text-muted-foreground">
176
- {(project.nextTasksCount ?? 0) > 0 && (
177
- <div className="flex items-center gap-1">
178
- <ListTodo className="w-3.5 h-3.5" />
179
- <span>{project.nextTasksCount} queued</span>
180
- </div>
181
- )}
182
- {(project.ideasCount ?? 0) > 0 && (
183
- <div className="flex items-center gap-1">
184
- <Lightbulb className="w-3.5 h-3.5" />
185
- <span>{project.ideasCount} ideas</span>
186
- </div>
187
- )}
188
- {project.lastActivity && (
189
- <div className="flex items-center gap-1 ml-auto">
190
- <Zap className="w-3.5 h-3.5" />
191
- <span>{formatRelativeTime(project.lastActivity)}</span>
192
- </div>
193
- )}
194
- </div>
195
- )}
196
-
197
- {project.techStack && project.techStack.length > 0 && (
198
- <div className="mt-3">
199
- <TechStackBadges techStack={project.techStack} />
200
- </div>
201
- )}
202
- </Link>
203
-
204
- <DropdownMenu>
205
- <DropdownMenuTrigger asChild>
206
- <Button
207
- variant="ghost"
208
- size="icon-sm"
209
- className="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity"
210
- onClick={(e) => e.preventDefault()}
211
- >
212
- <MoreHorizontal className="w-4 h-4" />
213
- </Button>
214
- </DropdownMenuTrigger>
215
- <DropdownMenuContent align="end">
216
- <DropdownMenuItem
217
- className="text-destructive focus:text-destructive"
218
- onClick={(e: React.MouseEvent) => onDeleteClick(project, e)}
219
- >
220
- <Trash2 className="w-4 h-4 mr-2" />
221
- Delete
222
- </DropdownMenuItem>
223
- </DropdownMenuContent>
224
- </DropdownMenu>
225
- </div>
226
- )
11
+ return <DashboardContent projects={projects} stats={stats} />
227
12
  }
@@ -8,6 +8,7 @@ import { TerminalTabs } from '@/components/TerminalTabs'
8
8
  import { Button } from '@/components/ui/button'
9
9
  import { Badge } from '@/components/ui/badge'
10
10
  import { TooltipProvider } from '@/components/ui/tooltip'
11
+ import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet'
11
12
  import {
12
13
  AlertDialog,
13
14
  AlertDialogAction,
@@ -41,8 +42,11 @@ import {
41
42
  Activity,
42
43
  History,
43
44
  Undo2,
44
- Redo2
45
+ Redo2,
46
+ Command,
47
+ X
45
48
  } from 'lucide-react'
49
+ import { cn } from '@/lib/utils'
46
50
 
47
51
  // Commands ordered by real developer workflow
48
52
  const WORKFLOW_COMMANDS = [
@@ -64,11 +68,77 @@ const WORKFLOW_COMMANDS = [
64
68
 
65
69
  const COMMAND_GROUPS = ['work', 'session', 'plan', 'ship', 'status', 'recovery'] as const
66
70
 
71
+ // Command sidebar content - shared between desktop and mobile
72
+ function CommandSidebarContent({
73
+ projectId,
74
+ project,
75
+ isActiveConnected,
76
+ sendCommandToActive,
77
+ onCommandClick
78
+ }: {
79
+ projectId: string
80
+ project: { name?: string; iconPath?: string | null }
81
+ isActiveConnected: boolean
82
+ sendCommandToActive: (cmd: string) => void
83
+ onCommandClick?: () => void
84
+ }) {
85
+ const router = useRouter()
86
+
87
+ const handleCommand = (cmd: string) => {
88
+ sendCommandToActive(cmd)
89
+ onCommandClick?.()
90
+ }
91
+
92
+ return (
93
+ <>
94
+ <div className="h-14 flex items-center justify-center border-b border-border w-full">
95
+ <ProjectAvatar
96
+ projectId={projectId}
97
+ name={project.name || projectId}
98
+ iconPath={project.iconPath}
99
+ />
100
+ </div>
101
+
102
+ <div className="flex-1 flex flex-col gap-1 overflow-auto py-3">
103
+ {/* Stats button - navigates to stats page */}
104
+ <CommandButton
105
+ cmd="Project stats"
106
+ icon={BarChart3}
107
+ tip="Stats"
108
+ disabled={false}
109
+ onClick={() => {
110
+ router.push(`/project/${projectId}/stats`)
111
+ onCommandClick?.()
112
+ }}
113
+ />
114
+ <div className="border-b border-border w-8 my-2 mx-auto" />
115
+
116
+ {COMMAND_GROUPS.map((group, groupIndex) => (
117
+ <div key={group} className="flex flex-col items-center">
118
+ {WORKFLOW_COMMANDS.filter(c => c.group === group).map(({ cmd, icon, tip }) => (
119
+ <CommandButton
120
+ key={cmd}
121
+ cmd={cmd}
122
+ icon={icon}
123
+ tip={tip}
124
+ disabled={!isActiveConnected}
125
+ onClick={() => handleCommand(cmd)}
126
+ />
127
+ ))}
128
+ {groupIndex < COMMAND_GROUPS.length - 1 && (
129
+ <div className="border-b border-border w-8 my-2" />
130
+ )}
131
+ </div>
132
+ ))}
133
+ </div>
134
+ </>
135
+ )
136
+ }
137
+
67
138
  // Inner component that uses the terminal context
68
139
  function ProjectPageContent({ projectId, project }: { projectId: string; project: NonNullable<ReturnType<typeof useProject>['data']> }) {
69
140
  const router = useRouter()
70
- const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
71
- const deleteMutation = useDeleteProject()
141
+ const [commandSheetOpen, setCommandSheetOpen] = useState(false)
72
142
 
73
143
  const {
74
144
  sessions,
@@ -84,74 +154,56 @@ function ProjectPageContent({ projectId, project }: { projectId: string; project
84
154
  <div className="h-full">
85
155
  <TooltipProvider>
86
156
  <div className="flex h-full">
87
- {/* Sidebar */}
88
- <aside className="w-14 border-r border-border flex flex-col bg-card/50 items-center">
89
- <div className="h-14 flex items-center justify-center border-b border-border w-full">
90
- <ProjectAvatar
91
- projectId={projectId}
92
- name={project.name || projectId}
93
- iconPath={project.iconPath}
94
- />
95
- </div>
96
-
97
- <div className="flex-1 flex flex-col gap-1 overflow-auto py-3">
98
- {/* Stats button - navigates to stats page */}
99
- <CommandButton
100
- cmd="Project stats"
101
- icon={BarChart3}
102
- tip="Stats"
103
- disabled={false}
104
- onClick={() => router.push(`/project/${projectId}/stats`)}
105
- />
106
- <div className="border-b border-border w-8 my-2 mx-auto" />
107
-
108
- {COMMAND_GROUPS.map((group, groupIndex) => (
109
- <div key={group} className="flex flex-col items-center">
110
- {WORKFLOW_COMMANDS.filter(c => c.group === group).map(({ cmd, icon, tip }) => (
111
- <CommandButton
112
- key={cmd}
113
- cmd={cmd}
114
- icon={icon}
115
- tip={tip}
116
- disabled={!isActiveConnected}
117
- onClick={() => sendCommandToActive(cmd)}
118
- />
119
- ))}
120
- {groupIndex < COMMAND_GROUPS.length - 1 && (
121
- <div className="border-b border-border w-8 my-2" />
122
- )}
123
- </div>
124
- ))}
125
- </div>
157
+ {/* Desktop Sidebar - hidden on mobile */}
158
+ <aside className="hidden md:flex w-14 border-r border-border flex-col bg-card/50 items-center">
159
+ <CommandSidebarContent
160
+ projectId={projectId}
161
+ project={project}
162
+ isActiveConnected={isActiveConnected}
163
+ sendCommandToActive={sendCommandToActive}
164
+ />
126
165
  </aside>
127
166
 
128
167
  {/* Main */}
129
- <main className="flex-1 flex flex-col">
130
- <header className="h-14 flex items-center justify-between px-4 border-b border-border bg-card">
131
- <div className="flex items-center gap-4">
132
- <div className="flex flex-col">
168
+ <main className="flex-1 flex flex-col min-w-0">
169
+ {/* Header - Responsive */}
170
+ <header className="h-auto md:h-14 flex flex-col md:flex-row md:items-center justify-between px-3 md:px-4 py-2 md:py-0 border-b border-border bg-card gap-2">
171
+ {/* Mobile: Add padding for hamburger menu */}
172
+ <div className="flex items-center gap-3 pl-12 md:pl-0">
173
+ {/* Mobile: Show project avatar */}
174
+ <div className="md:hidden">
175
+ <ProjectAvatar
176
+ projectId={projectId}
177
+ name={project.name || projectId}
178
+ iconPath={project.iconPath}
179
+ size="sm"
180
+ />
181
+ </div>
182
+ <div className="flex flex-col min-w-0">
133
183
  <div className="flex items-center gap-2">
134
- <span className="font-bold leading-tight">{project.name || projectId}</span>
184
+ <span className="font-bold leading-tight truncate">{project.name || projectId}</span>
135
185
  {project.version && (
136
- <Badge variant="outline" className="text-[10px] px-1.5 py-0 font-mono">
186
+ <Badge variant="outline" className="text-[10px] px-1.5 py-0 font-mono shrink-0">
137
187
  v{project.version}
138
188
  </Badge>
139
189
  )}
140
190
  </div>
141
191
  {project.repoPath && (
142
- <span className="text-xs text-muted-foreground leading-tight flex items-center gap-1">
143
- <FolderGit2 className="w-3 h-3" />
144
- {formatPath(project.repoPath)}
192
+ <span className="text-xs text-muted-foreground leading-tight flex items-center gap-1 truncate">
193
+ <FolderGit2 className="w-3 h-3 shrink-0" />
194
+ <span className="truncate">{formatPath(project.repoPath)}</span>
145
195
  </span>
146
196
  )}
147
197
  </div>
148
198
  {hasActiveSessions && (
149
- <Badge variant="outline" className="text-green-500 border-green-500/50">
199
+ <Badge variant="outline" className="text-green-500 border-green-500/50 shrink-0">
150
200
  {sessions.filter(s => s.isConnected).length} active
151
201
  </Badge>
152
202
  )}
153
203
  </div>
154
- <div className="flex items-center gap-4">
204
+
205
+ {/* Desktop only: metadata and tech stack */}
206
+ <div className="hidden md:flex items-center gap-4">
155
207
  <div className="flex items-center gap-3 text-xs text-muted-foreground">
156
208
  {project.stack && <span>{project.stack}</span>}
157
209
  {project.filesCount && (
@@ -166,12 +218,86 @@ function ProjectPageContent({ projectId, project }: { projectId: string; project
166
218
  </header>
167
219
 
168
220
  {/* Terminal tabs area */}
169
- <div className="flex-1">
221
+ <div className="flex-1 min-h-0">
170
222
  <TerminalTabs projectDir={project.repoPath || project.path || '/tmp'} />
171
223
  </div>
172
224
  </main>
173
225
  </div>
174
226
 
227
+ {/* Mobile: Floating Action Button for commands */}
228
+ <div className="md:hidden fixed bottom-4 right-4 z-50">
229
+ <Sheet open={commandSheetOpen} onOpenChange={setCommandSheetOpen}>
230
+ <SheetTrigger asChild>
231
+ <button
232
+ className={cn(
233
+ "h-14 w-14 rounded-full shadow-lg flex items-center justify-center transition-all",
234
+ isActiveConnected
235
+ ? "bg-primary text-primary-foreground hover:bg-primary/90"
236
+ : "bg-muted text-muted-foreground"
237
+ )}
238
+ aria-label="Open commands"
239
+ >
240
+ <Command className="h-6 w-6" />
241
+ </button>
242
+ </SheetTrigger>
243
+ <SheetContent side="bottom" className="h-[70vh] rounded-t-2xl px-0">
244
+ <div className="flex flex-col h-full">
245
+ <div className="px-4 pb-2 border-b border-border">
246
+ <div className="flex items-center justify-between">
247
+ <h3 className="font-semibold">Commands</h3>
248
+ <Badge variant={isActiveConnected ? "default" : "secondary"}>
249
+ {isActiveConnected ? "Connected" : "Disconnected"}
250
+ </Badge>
251
+ </div>
252
+ </div>
253
+
254
+ {/* Command grid for mobile */}
255
+ <div className="flex-1 overflow-auto p-4">
256
+ <div className="grid grid-cols-4 gap-3">
257
+ {/* Stats button */}
258
+ <button
259
+ onClick={() => {
260
+ router.push(`/project/${projectId}/stats`)
261
+ setCommandSheetOpen(false)
262
+ }}
263
+ className="flex flex-col items-center gap-1.5 p-3 rounded-lg hover:bg-accent transition-colors"
264
+ >
265
+ <div className="h-10 w-10 rounded-full bg-accent flex items-center justify-center">
266
+ <BarChart3 className="h-5 w-5" />
267
+ </div>
268
+ <span className="text-xs text-muted-foreground">Stats</span>
269
+ </button>
270
+
271
+ {WORKFLOW_COMMANDS.map(({ cmd, icon: Icon, tip }) => (
272
+ <button
273
+ key={cmd}
274
+ onClick={() => {
275
+ sendCommandToActive(cmd)
276
+ setCommandSheetOpen(false)
277
+ }}
278
+ disabled={!isActiveConnected}
279
+ className={cn(
280
+ "flex flex-col items-center gap-1.5 p-3 rounded-lg transition-colors",
281
+ isActiveConnected
282
+ ? "hover:bg-accent"
283
+ : "opacity-50 cursor-not-allowed"
284
+ )}
285
+ >
286
+ <div className={cn(
287
+ "h-10 w-10 rounded-full flex items-center justify-center",
288
+ isActiveConnected ? "bg-accent" : "bg-muted"
289
+ )}>
290
+ <Icon className="h-5 w-5" />
291
+ </div>
292
+ <span className="text-xs text-muted-foreground">{tip}</span>
293
+ </button>
294
+ ))}
295
+ </div>
296
+ </div>
297
+ </div>
298
+ </SheetContent>
299
+ </Sheet>
300
+ </div>
175
301
  </TooltipProvider>
176
302
  </div>
177
303
  )
@@ -195,16 +321,16 @@ export default function ProjectPage({ params }: { params: Promise<{ id: string }
195
321
 
196
322
  if (!project) {
197
323
  return (
198
- <div className="flex items-center justify-center h-full">
199
- <div className="text-center space-y-4">
324
+ <div className="flex items-center justify-center h-full p-4">
325
+ <div className="text-center space-y-4 max-w-sm">
200
326
  <div className="w-16 h-16 rounded-full bg-muted flex items-center justify-center mx-auto">
201
327
  <AlertTriangle className="w-8 h-8 text-muted-foreground" />
202
328
  </div>
203
329
  <div>
204
330
  <h2 className="text-lg font-medium">Project not found</h2>
205
- <p className="text-sm text-muted-foreground mt-1">ID: {projectId}</p>
331
+ <p className="text-sm text-muted-foreground mt-1 break-all">ID: {projectId}</p>
206
332
  </div>
207
- <div className="flex gap-2 justify-center">
333
+ <div className="flex flex-col sm:flex-row gap-2 justify-center">
208
334
  <Button variant="outline" onClick={() => router.push('/')}>
209
335
  <ArrowLeft className="w-4 h-4 mr-2" />
210
336
  Back to Dashboard
@@ -216,7 +342,7 @@ export default function ProjectPage({ params }: { params: Promise<{ id: string }
216
342
  </div>
217
343
 
218
344
  <AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
219
- <AlertDialogContent>
345
+ <AlertDialogContent className="max-w-[calc(100vw-2rem)] sm:max-w-lg">
220
346
  <AlertDialogHeader>
221
347
  <AlertDialogTitle className="flex items-center gap-2">
222
348
  <AlertTriangle className="w-5 h-5 text-destructive" />
@@ -225,15 +351,17 @@ export default function ProjectPage({ params }: { params: Promise<{ id: string }
225
351
  <AlertDialogDescription>
226
352
  This will move the project storage to trash.
227
353
  <br />
228
- <span className="text-muted-foreground text-sm">ID: {projectId}</span>
354
+ <span className="text-muted-foreground text-sm break-all">ID: {projectId}</span>
229
355
  </AlertDialogDescription>
230
356
  </AlertDialogHeader>
231
- <AlertDialogFooter>
232
- <AlertDialogCancel disabled={deleteMutation.isPending}>Cancel</AlertDialogCancel>
357
+ <AlertDialogFooter className="flex-col sm:flex-row gap-2">
358
+ <AlertDialogCancel disabled={deleteMutation.isPending} className="w-full sm:w-auto">
359
+ Cancel
360
+ </AlertDialogCancel>
233
361
  <AlertDialogAction
234
362
  onClick={() => deleteMutation.mutate(projectId, { onSuccess: () => router.push('/') })}
235
363
  disabled={deleteMutation.isPending}
236
- className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
364
+ className="bg-destructive text-destructive-foreground hover:bg-destructive/90 w-full sm:w-auto"
237
365
  >
238
366
  {deleteMutation.isPending ? 'Deleting...' : 'Delete'}
239
367
  </AlertDialogAction>
@@ -0,0 +1,43 @@
1
+ import { BentoGrid } from '@/components/BentoGrid'
2
+ import { BentoCardSkeleton } from '@/components/BentoCardSkeleton'
3
+
4
+ export default function StatsLoading() {
5
+ return (
6
+ <div className="p-4 md:p-8 space-y-6 md:space-y-8">
7
+ {/* Hero skeleton */}
8
+ <div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6 pl-10 md:pl-0">
9
+ <div className="h-16 w-16 md:h-20 md:w-20 rounded-full bg-muted animate-pulse" />
10
+ <div className="space-y-3 text-center sm:text-left">
11
+ <div className="h-12 md:h-16 w-24 md:w-32 bg-muted rounded animate-pulse mx-auto sm:mx-0" />
12
+ <div className="h-4 w-40 md:w-48 bg-muted rounded animate-pulse mx-auto sm:mx-0" />
13
+ </div>
14
+ </div>
15
+
16
+ {/* Bento grid skeleton */}
17
+ <BentoGrid>
18
+ <BentoCardSkeleton size="2x2" />
19
+ <BentoCardSkeleton size="1x1" />
20
+ <BentoCardSkeleton size="2x2" />
21
+ <BentoCardSkeleton size="1x1" />
22
+ <BentoCardSkeleton size="1x2" />
23
+ <BentoCardSkeleton size="1x2" />
24
+ <BentoCardSkeleton size="1x1" />
25
+ <BentoCardSkeleton size="1x1" />
26
+ </BentoGrid>
27
+
28
+ {/* Timeline skeleton */}
29
+ <div className="space-y-3">
30
+ <div className="h-4 w-24 bg-muted rounded animate-pulse" />
31
+ <div className="space-y-2">
32
+ {Array.from({ length: 5 }).map((_, i) => (
33
+ <div key={i} className="flex items-center gap-3">
34
+ <div className="h-2 w-2 rounded-full bg-muted animate-pulse" />
35
+ <div className="h-4 flex-1 bg-muted rounded animate-pulse" />
36
+ <div className="h-3 w-16 bg-muted rounded animate-pulse" />
37
+ </div>
38
+ ))}
39
+ </div>
40
+ </div>
41
+ </div>
42
+ )
43
+ }