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,312 +0,0 @@
1
- /**
2
- * Custom Next.js server with WebSocket support for PTY
3
- *
4
- * PTY sessions are managed here (not in API routes) to share memory context
5
- */
6
-
7
- import { createServer } from 'http'
8
- import next from 'next'
9
- import { WebSocketServer, WebSocket } from 'ws'
10
- import * as pty from 'node-pty'
11
- import type { IPty } from 'node-pty'
12
-
13
- const dev = process.env.NODE_ENV !== 'production'
14
- const hostname = 'localhost'
15
- // Dev: 9471, Prod: 9472 (allows running both simultaneously for testing)
16
- const defaultPort = dev ? 9471 : 9472
17
- const port = parseInt(process.env.PORT || String(defaultPort), 10)
18
-
19
- // PTY Sessions stored in server memory
20
- interface Session {
21
- pty: IPty
22
- projectDir: string
23
- createdAt: Date
24
- hasStartedClaude: boolean // Track if claude command was sent
25
- }
26
-
27
- const sessions = new Map<string, Session>()
28
-
29
- function createSession(sessionId: string, projectDir: string): { pty: IPty; isNew: boolean } {
30
- const existing = sessions.get(sessionId)
31
-
32
- // If session exists for this project, reuse it (allows multiple tabs)
33
- if (existing) {
34
- console.log(`[PTY] Reusing existing session: ${sessionId}`)
35
- return { pty: existing.pty, isNew: false }
36
- }
37
-
38
- // Use user's default shell (zsh, bash, etc.) - respects $SHELL env var
39
- const shell = process.platform === 'win32'
40
- ? 'cmd.exe'
41
- : process.env.SHELL || '/bin/zsh'
42
-
43
- // -l for login shell (loads .zshrc, .bashrc, etc.)
44
- // -i for interactive shell (enables job control, aliases)
45
- const args = process.platform === 'win32' ? [] : ['-l', '-i']
46
-
47
- const ptyProcess = pty.spawn(shell, args, {
48
- name: 'xterm-256color',
49
- cols: 120,
50
- rows: 30,
51
- cwd: projectDir,
52
- env: {
53
- ...process.env,
54
- TERM: 'xterm-256color',
55
- COLORTERM: 'truecolor',
56
- // Ensure shell knows it's interactive
57
- SHELL: shell
58
- }
59
- })
60
-
61
- sessions.set(sessionId, {
62
- pty: ptyProcess,
63
- projectDir,
64
- createdAt: new Date(),
65
- hasStartedClaude: false
66
- })
67
-
68
- // NOTE: Don't auto-start claude here - let the WebSocket handler do it
69
- // once the client is connected and ready to receive output
70
-
71
- return { pty: ptyProcess, isNew: true }
72
- }
73
-
74
- function getSession(sessionId: string): IPty | null {
75
- return sessions.get(sessionId)?.pty || null
76
- }
77
-
78
- function killSession(sessionId: string): void {
79
- const session = sessions.get(sessionId)
80
- if (session) {
81
- try { session.pty.kill() } catch {}
82
- sessions.delete(sessionId)
83
- }
84
- }
85
-
86
- function resizeSession(sessionId: string, cols: number, rows: number): void {
87
- const session = sessions.get(sessionId)
88
- if (session) {
89
- try { session.pty.resize(cols, rows) } catch {}
90
- }
91
- }
92
-
93
- const app = next({ dev, hostname, port })
94
- const handle = app.getRequestHandler()
95
-
96
- app.prepare().then(() => {
97
- const server = createServer(async (req, res) => {
98
- const url = new URL(req.url || '', `http://${req.headers.host}`)
99
-
100
- // Handle session creation directly in server (bypasses API route isolation)
101
- if (url.pathname === '/api/claude/sessions' && req.method === 'POST') {
102
- let body = ''
103
- let bodySize = 0
104
- const MAX_BODY_SIZE = 1024 * 1024 // 1MB limit
105
-
106
- req.on('data', chunk => {
107
- bodySize += chunk.length
108
- if (bodySize > MAX_BODY_SIZE) {
109
- res.statusCode = 413
110
- res.setHeader('Content-Type', 'application/json')
111
- res.end(JSON.stringify({ success: false, error: 'Request body too large' }))
112
- req.destroy()
113
- return
114
- }
115
- body += chunk
116
- })
117
- req.on('end', () => {
118
- try {
119
- const { sessionId, projectDir } = JSON.parse(body)
120
- if (!sessionId || !projectDir) {
121
- res.statusCode = 400
122
- res.setHeader('Content-Type', 'application/json')
123
- res.end(JSON.stringify({ success: false, error: 'sessionId and projectDir required' }))
124
- return
125
- }
126
-
127
- const { isNew } = createSession(sessionId, projectDir)
128
- console.log(`[PTY] ${isNew ? 'Created' : 'Reusing'} session: ${sessionId} for ${projectDir}`)
129
-
130
- res.statusCode = 200
131
- res.setHeader('Content-Type', 'application/json')
132
- res.end(JSON.stringify({ success: true, data: { sessionId, projectDir, isNew } }))
133
- } catch (err) {
134
- console.error('[PTY] Error creating session:', err)
135
- res.statusCode = 500
136
- res.setHeader('Content-Type', 'application/json')
137
- res.end(JSON.stringify({ success: false, error: 'Failed to create session' }))
138
- }
139
- })
140
- return
141
- }
142
-
143
- // Handle session list
144
- if (url.pathname === '/api/claude/sessions' && req.method === 'GET') {
145
- const list = Array.from(sessions.entries()).map(([id, s]) => ({
146
- sessionId: id,
147
- projectDir: s.projectDir,
148
- createdAt: s.createdAt
149
- }))
150
- res.statusCode = 200
151
- res.setHeader('Content-Type', 'application/json')
152
- res.end(JSON.stringify({ success: true, data: list }))
153
- return
154
- }
155
-
156
- // All other requests go to Next.js
157
- try {
158
- await handle(req, res)
159
- } catch (err) {
160
- console.error('Error handling request:', err)
161
- res.statusCode = 500
162
- res.end('Internal Server Error')
163
- }
164
- })
165
-
166
- // WebSocket server for PTY communication
167
- const wss = new WebSocketServer({ noServer: true })
168
-
169
- // Heartbeat interval to detect dead connections (30 seconds)
170
- const HEARTBEAT_INTERVAL = 30000
171
-
172
- const heartbeatInterval = setInterval(() => {
173
- wss.clients.forEach((ws) => {
174
- const extWs = ws as WebSocket & { isAlive?: boolean; sessionId?: string }
175
- if (extWs.isAlive === false) {
176
- console.log(`[WS] Terminating dead connection: ${extWs.sessionId}`)
177
- if (extWs.sessionId) {
178
- killSession(extWs.sessionId)
179
- }
180
- return ws.terminate()
181
- }
182
- extWs.isAlive = false
183
- ws.ping()
184
- })
185
- }, HEARTBEAT_INTERVAL)
186
-
187
- // Cleanup on WSS close
188
- wss.on('close', () => {
189
- clearInterval(heartbeatInterval)
190
- })
191
-
192
- // Cleanup on server close
193
- server.on('close', () => {
194
- clearInterval(heartbeatInterval)
195
- // Kill all active sessions
196
- sessions.forEach((_, sessionId) => killSession(sessionId))
197
- })
198
-
199
- server.on('upgrade', (request, socket, head) => {
200
- const url = new URL(request.url || '', `http://${request.headers.host}`)
201
-
202
- if (url.pathname.startsWith('/ws/claude/')) {
203
- wss.handleUpgrade(request, socket, head, (ws) => {
204
- wss.emit('connection', ws, request)
205
- })
206
- }
207
- // Other upgrades (HMR) pass through to Next.js
208
- })
209
-
210
- wss.on('connection', (ws: WebSocket, request) => {
211
- const url = new URL(request.url || '', `http://${request.headers.host}`)
212
- const sessionId = url.pathname.replace('/ws/claude/', '')
213
-
214
- console.log(`[WS] New PTY connection for session: ${sessionId}`)
215
-
216
- // Mark connection as alive and store sessionId for heartbeat
217
- const extWs = ws as WebSocket & { isAlive?: boolean; sessionId?: string }
218
- extWs.isAlive = true
219
- extWs.sessionId = sessionId
220
-
221
- // Handle pong response
222
- ws.on('pong', () => {
223
- extWs.isAlive = true
224
- })
225
-
226
- const session = sessions.get(sessionId)
227
-
228
- if (!session) {
229
- console.log(`[WS] Session not found: ${sessionId}`)
230
- ws.send(JSON.stringify({ type: 'error', message: 'Session not found' }))
231
- ws.close()
232
- return
233
- }
234
-
235
- const ptyProcess = session.pty
236
-
237
- // Output buffering for smooth terminal rendering
238
- // Batches PTY output and flushes every 16ms (one animation frame)
239
- const outputBuffer: string[] = []
240
- let flushTimer: NodeJS.Timeout | null = null
241
- const BATCH_MS = 16
242
-
243
- const flushBuffer = () => {
244
- if (outputBuffer.length > 0 && ws.readyState === WebSocket.OPEN) {
245
- ws.send(JSON.stringify({ type: 'output', data: outputBuffer.join('') }))
246
- outputBuffer.length = 0
247
- }
248
- flushTimer = null
249
- }
250
-
251
- // Register data handler FIRST before sending any commands
252
- const dataHandler = ptyProcess.onData((data: string) => {
253
- outputBuffer.push(data)
254
- if (!flushTimer) {
255
- flushTimer = setTimeout(flushBuffer, BATCH_MS)
256
- }
257
- })
258
-
259
- ws.send(JSON.stringify({ type: 'connected', sessionId }))
260
-
261
- // Auto-start Claude CLI only once, when first client connects
262
- if (!session.hasStartedClaude) {
263
- session.hasStartedClaude = true
264
- console.log(`[WS] Starting Claude CLI for session: ${sessionId}`)
265
- setTimeout(() => {
266
- ptyProcess.write('claude\r')
267
- }, 200) // Small delay to ensure client is ready
268
- }
269
-
270
- const exitHandler = ptyProcess.onExit(({ exitCode }) => {
271
- if (ws.readyState === WebSocket.OPEN) {
272
- ws.send(JSON.stringify({ type: 'exit', code: exitCode }))
273
- }
274
- killSession(sessionId)
275
- })
276
-
277
- ws.on('message', (message: Buffer) => {
278
- try {
279
- const { type, data, cols, rows } = JSON.parse(message.toString())
280
- switch (type) {
281
- case 'input':
282
- ptyProcess?.write(data)
283
- break
284
- case 'resize':
285
- if (cols && rows) resizeSession(sessionId, cols, rows)
286
- break
287
- }
288
- } catch (err) {
289
- console.error('[WS] Error:', err)
290
- }
291
- })
292
-
293
- ws.on('close', () => {
294
- console.log(`[WS] PTY connection closed: ${sessionId}`)
295
- // Clear buffer flush timer
296
- if (flushTimer) {
297
- clearTimeout(flushTimer)
298
- flushTimer = null
299
- }
300
- dataHandler.dispose()
301
- exitHandler.dispose()
302
- })
303
-
304
- ws.on('error', (error) => {
305
- console.error(`[WS] Error for ${sessionId}:`, error)
306
- })
307
- })
308
-
309
- server.listen(port, () => {
310
- console.log(`> prjct ready on http://${hostname}:${port}`)
311
- })
312
- })
@@ -1,34 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2017",
4
- "lib": ["dom", "dom.iterable", "esnext"],
5
- "allowJs": true,
6
- "skipLibCheck": true,
7
- "strict": true,
8
- "noEmit": true,
9
- "esModuleInterop": true,
10
- "module": "esnext",
11
- "moduleResolution": "bundler",
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "jsx": "react-jsx",
15
- "incremental": true,
16
- "plugins": [
17
- {
18
- "name": "next"
19
- }
20
- ],
21
- "paths": {
22
- "@/*": ["./*"]
23
- }
24
- },
25
- "include": [
26
- "next-env.d.ts",
27
- "**/*.ts",
28
- "**/*.tsx",
29
- ".next/types/**/*.ts",
30
- ".next/dev/types/**/*.ts",
31
- "**/*.mts"
32
- ],
33
- "exclude": ["node_modules"]
34
- }
@@ -1,121 +0,0 @@
1
- ---
2
- allowed-tools: [Bash]
3
- description: 'Start prjct web server'
4
- ---
5
-
6
- # /p:serve - Start Web Server
7
-
8
- ## Overview
9
- Starts the prjct web interface with Claude Code CLI integration.
10
-
11
- **CRITICAL**: Uses your Claude subscription via PTY - NO API costs!
12
-
13
- ## Usage
14
-
15
- ```bash
16
- # Start with defaults (port 3333)
17
- prjct-serve
18
-
19
- # Custom port
20
- prjct-serve --port=8080
21
- ```
22
-
23
- ## What It Does
24
-
25
- 1. **Starts API Server** (Hono)
26
- - REST endpoints for projects, sessions, tasks
27
- - WebSocket for Claude Code CLI interaction
28
- - SSE for real-time updates
29
-
30
- 2. **Starts Web App** (React + Vite)
31
- - Dashboard with metrics
32
- - Terminal with xterm.js
33
- - Session history
34
-
35
- 3. **PTY Manager**
36
- - Spawns Claude Code CLI in pseudo-terminal
37
- - Streams I/O via WebSocket
38
- - Uses YOUR subscription - $0 API costs
39
-
40
- ## Architecture
41
-
42
- ```
43
- ┌─────────────────────────────────────────────────────────┐
44
- │ Browser (localhost:3000) │
45
- │ ┌─────────────────────────────────────────────────┐ │
46
- │ │ React App │ │
47
- │ │ ├── Dashboard (metrics, projects) │ │
48
- │ │ ├── Terminal (xterm.js) │ │
49
- │ │ └── Sessions (history) │ │
50
- │ └─────────────────────────────────────────────────┘ │
51
- │ │ │
52
- │ WebSocket │
53
- │ │ │
54
- │ ┌─────────────────────────────────────────────────┐ │
55
- │ │ Hono Server (localhost:3333) │ │
56
- │ │ ├── /api/projects │ │
57
- │ │ ├── /api/sessions │ │
58
- │ │ ├── /api/claude/sessions │ │
59
- │ │ └── /ws/claude/:sessionId │ │
60
- │ └─────────────────────────────────────────────────┘ │
61
- │ │ │
62
- │ PTY (node-pty) │
63
- │ │ │
64
- │ ┌─────────────────────────────────────────────────┐ │
65
- │ │ Claude Code CLI │ │
66
- │ │ (your subscription, no API costs) │ │
67
- │ └─────────────────────────────────────────────────┘ │
68
- └─────────────────────────────────────────────────────────┘
69
- ```
70
-
71
- ## Endpoints
72
-
73
- ### REST API
74
-
75
- | Endpoint | Method | Description |
76
- |----------|--------|-------------|
77
- | `/api/projects` | GET | List all projects |
78
- | `/api/projects/:id` | GET | Get project details |
79
- | `/api/projects/:id/status` | GET | Get project status |
80
- | `/api/sessions` | GET | List sessions |
81
- | `/api/sessions/current` | GET | Get current session |
82
- | `/api/sessions` | POST | Create session |
83
- | `/api/sessions/:id/pause` | POST | Pause session |
84
- | `/api/sessions/:id/resume` | POST | Resume session |
85
- | `/api/sessions/:id/complete` | POST | Complete session |
86
- | `/api/claude/status` | GET | Check Claude CLI availability |
87
- | `/api/claude/sessions` | GET | List PTY sessions |
88
- | `/api/claude/sessions` | POST | Create PTY session |
89
-
90
- ### WebSocket
91
-
92
- | Endpoint | Description |
93
- |----------|-------------|
94
- | `/ws/claude/:sessionId` | Real-time Claude CLI interaction |
95
-
96
- **Messages:**
97
- - `{ type: 'input', data: string }` - Send input to CLI
98
- - `{ type: 'resize', cols: number, rows: number }` - Resize terminal
99
- - `{ type: 'output', data: string }` - Receive CLI output
100
-
101
- ## Requirements
102
-
103
- - Node.js 18+
104
- - Claude Code CLI installed (`claude` command available)
105
- - Active Claude subscription (Max or similar)
106
-
107
- ## Output
108
-
109
- ```
110
- ╔═══════════════════════════════════════════════════════════╗
111
- ║ ║
112
- ║ ⚡ prjct - Developer Momentum ║
113
- ║ ║
114
- ║ API: http://localhost:3333 ║
115
- ║ Web: http://localhost:3000 ║
116
- ║ Claude: ws://localhost:3333/ws/claude ║
117
- ║ ║
118
- ║ Using your Claude subscription - $0 API costs ║
119
- ║ ║
120
- ╚═══════════════════════════════════════════════════════════╝
121
- ```