prjct-cli 0.11.1 → 0.11.3

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 (2) hide show
  1. package/bin/serve.js +136 -26
  2. package/package.json +1 -1
package/bin/serve.js CHANGED
@@ -5,27 +5,140 @@
5
5
  *
6
6
  * Launches the prjct web interface with Claude Code CLI integration.
7
7
  * Uses your existing Claude subscription via PTY - no API costs!
8
+ *
9
+ * Auto-installs dependencies on first run.
8
10
  */
9
11
 
10
- const { spawn } = require('child_process')
12
+ const { spawn, spawnSync } = require('child_process')
11
13
  const path = require('path')
12
14
  const fs = require('fs')
13
15
 
14
- const serverDir = path.join(__dirname, '..', 'packages', 'server')
15
- const webDir = path.join(__dirname, '..', 'packages', 'web')
16
+ const packagesDir = path.join(__dirname, '..', 'packages')
17
+ const sharedDir = path.join(packagesDir, 'shared')
18
+ const webDir = path.join(packagesDir, 'web')
16
19
 
17
20
  // Parse arguments
18
21
  const args = process.argv.slice(2)
19
- const portArg = args.find(a => a.startsWith('--port='))
20
- const port = portArg ? portArg.split('=')[1] : '3333'
21
- const webPort = '3000'
22
+ const portArg = args.find((a) => a.startsWith('--port='))
23
+ const port = portArg ? portArg.split('=')[1] : '3000'
22
24
 
23
- // Check if packages exist
24
- if (!fs.existsSync(serverDir) || !fs.existsSync(webDir)) {
25
- console.error('❌ Web packages not found. Run from prjct-cli directory.')
25
+ // Check if web package exists
26
+ if (!fs.existsSync(webDir)) {
27
+ console.error('❌ Web package not found.')
28
+ console.error(' This might be a broken installation.')
29
+ console.error(' Try reinstalling: npm install -g prjct-cli')
26
30
  process.exit(1)
27
31
  }
28
32
 
33
+ // Check if dependencies are installed
34
+ const sharedNodeModules = path.join(sharedDir, 'node_modules')
35
+ const webNodeModules = path.join(webDir, 'node_modules')
36
+ const needsSharedInstall = fs.existsSync(sharedDir) && !fs.existsSync(sharedNodeModules)
37
+ const needsWebInstall = !fs.existsSync(webNodeModules)
38
+
39
+ if (needsSharedInstall || needsWebInstall) {
40
+ console.log(`
41
+ ╔═══════════════════════════════════════════════════════════╗
42
+ ║ ║
43
+ ║ ⚡ prjct - First Time Setup ║
44
+ ║ ║
45
+ ║ Installing web dependencies... ║
46
+ ║ This only happens once. ║
47
+ ║ ║
48
+ ╚═══════════════════════════════════════════════════════════╝
49
+ `)
50
+
51
+ // Install shared dependencies first (if exists)
52
+ if (needsSharedInstall) {
53
+ console.log('📦 Installing packages/shared dependencies...')
54
+ const sharedInstall = spawnSync('npm', ['install'], {
55
+ cwd: sharedDir,
56
+ stdio: 'inherit',
57
+ shell: true,
58
+ })
59
+
60
+ if (sharedInstall.status !== 0) {
61
+ console.error('❌ Failed to install shared dependencies')
62
+ process.exit(1)
63
+ }
64
+
65
+ // Build shared package
66
+ console.log('🔨 Building shared package...')
67
+ const sharedBuild = spawnSync('npm', ['run', 'build'], {
68
+ cwd: sharedDir,
69
+ stdio: 'inherit',
70
+ shell: true,
71
+ })
72
+
73
+ if (sharedBuild.status !== 0) {
74
+ console.error('⚠️ Warning: Failed to build shared package')
75
+ }
76
+ }
77
+
78
+ // Install web dependencies
79
+ if (needsWebInstall) {
80
+ console.log('📦 Installing packages/web dependencies...')
81
+ const webInstall = spawnSync('npm', ['install'], {
82
+ cwd: webDir,
83
+ stdio: 'inherit',
84
+ shell: true,
85
+ })
86
+
87
+ if (webInstall.status !== 0) {
88
+ console.error('❌ Failed to install web dependencies')
89
+ process.exit(1)
90
+ }
91
+ }
92
+
93
+ console.log('✅ Dependencies installed!\n')
94
+ }
95
+
96
+ // Kill any process using the port
97
+ function killPort(portToKill) {
98
+ try {
99
+ if (process.platform === 'win32') {
100
+ // Windows
101
+ const result = spawnSync('netstat', ['-ano'], { shell: true, encoding: 'utf8' })
102
+ const lines = result.stdout.split('\n')
103
+ for (const line of lines) {
104
+ if (line.includes(`:${portToKill}`) && line.includes('LISTENING')) {
105
+ const parts = line.trim().split(/\s+/)
106
+ const pid = parts[parts.length - 1]
107
+ if (pid && pid !== '0') {
108
+ spawnSync('taskkill', ['/F', '/PID', pid], { shell: true })
109
+ }
110
+ }
111
+ }
112
+ } else {
113
+ // macOS / Linux
114
+ const result = spawnSync('lsof', ['-ti', `:${portToKill}`], {
115
+ shell: true,
116
+ encoding: 'utf8',
117
+ })
118
+ const pids = result.stdout.trim().split('\n').filter(Boolean)
119
+ for (const pid of pids) {
120
+ spawnSync('kill', ['-9', pid], { shell: true })
121
+ }
122
+ }
123
+ } catch {
124
+ // Ignore errors - port might not be in use
125
+ }
126
+ }
127
+
128
+ // Kill port if occupied
129
+ const checkPort = spawnSync('lsof', ['-ti', `:${port}`], {
130
+ shell: true,
131
+ encoding: 'utf8',
132
+ })
133
+
134
+ if (checkPort.stdout.trim()) {
135
+ console.log(`⚠️ Port ${port} is in use. Killing existing process...`)
136
+ killPort(port)
137
+ // Small delay to ensure port is released
138
+ spawnSync('sleep', ['1'], { shell: true })
139
+ console.log(`✅ Port ${port} freed\n`)
140
+ }
141
+
29
142
  console.log(`
30
143
  ╔═══════════════════════════════════════════════════════════╗
31
144
  ║ ║
@@ -33,34 +146,35 @@ console.log(`
33
146
  ║ ║
34
147
  ║ Starting web server... ║
35
148
  ║ ║
36
- API: http://localhost:${port} ║
37
- ║ Web: http://localhost:${webPort} ║
38
- ║ Claude: ws://localhost:${port}/ws/claude ║
149
+ Web: http://localhost:${port} ║
39
150
  ║ ║
40
151
  ║ Using your Claude subscription - $0 API costs ║
41
152
  ║ ║
42
153
  ╚═══════════════════════════════════════════════════════════╝
43
154
  `)
44
155
 
45
- // Start server
46
- const server = spawn('npm', ['run', 'dev'], {
47
- cwd: serverDir,
48
- stdio: 'inherit',
49
- shell: true,
50
- env: { ...process.env, PORT: port }
51
- })
52
-
53
156
  // Start web dev server
54
157
  const web = spawn('npm', ['run', 'dev'], {
55
158
  cwd: webDir,
56
159
  stdio: 'inherit',
57
- shell: true
160
+ shell: true,
161
+ env: { ...process.env, PORT: port },
58
162
  })
59
163
 
164
+ // Open browser after a short delay
165
+ setTimeout(() => {
166
+ const openCmd =
167
+ process.platform === 'darwin'
168
+ ? 'open'
169
+ : process.platform === 'win32'
170
+ ? 'start'
171
+ : 'xdg-open'
172
+ spawn(openCmd, [`http://localhost:${port}`], { shell: true })
173
+ }, 3000)
174
+
60
175
  // Handle shutdown
61
176
  const cleanup = () => {
62
177
  console.log('\n👋 Shutting down prjct server...')
63
- server.kill()
64
178
  web.kill()
65
179
  process.exit(0)
66
180
  }
@@ -69,10 +183,6 @@ process.on('SIGINT', cleanup)
69
183
  process.on('SIGTERM', cleanup)
70
184
 
71
185
  // Handle errors
72
- server.on('error', (err) => {
73
- console.error('Server error:', err.message)
74
- })
75
-
76
186
  web.on('error', (err) => {
77
187
  console.error('Web error:', err.message)
78
188
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prjct-cli",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "Built for Claude - Ship fast, track progress, stay focused. Developer momentum tool for indie hackers.",
5
5
  "main": "core/index.js",
6
6
  "bin": {