vesper-code 1.0.0 → 1.0.1
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.
- package/index.js +74 -442
- package/package.json +8 -4
- package/postinstall.js +1 -1
package/index.js
CHANGED
|
@@ -2,484 +2,116 @@
|
|
|
2
2
|
|
|
3
3
|
const { spawn } = require('child_process')
|
|
4
4
|
const fs = require('fs')
|
|
5
|
-
const http = require('http')
|
|
6
|
-
const https = require('https')
|
|
7
5
|
const os = require('os')
|
|
8
6
|
const path = require('path')
|
|
9
|
-
const zlib = require('zlib')
|
|
10
7
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
homeDir,
|
|
24
|
-
configDir,
|
|
25
|
-
binaryName,
|
|
26
|
-
binaryPath: path.join(configDir, binaryName),
|
|
27
|
-
metadataPath: path.join(configDir, 'vesper-metadata.json'),
|
|
28
|
-
tempDownloadDir: path.join(configDir, '.download-temp'),
|
|
29
|
-
userAgent: `${packageName}-cli`,
|
|
30
|
-
requestTimeout: 20000,
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const CONFIG = createConfig()
|
|
35
|
-
|
|
36
|
-
function getPostHogConfig() {
|
|
37
|
-
const apiKey =
|
|
38
|
-
process.env.VESPER_POSTHOG_API_KEY ||
|
|
39
|
-
process.env.NEXT_PUBLIC_POSTHOG_API_KEY
|
|
40
|
-
const host =
|
|
41
|
-
process.env.VESPER_POSTHOG_HOST ||
|
|
42
|
-
process.env.NEXT_PUBLIC_POSTHOG_HOST_URL
|
|
43
|
-
|
|
44
|
-
if (!apiKey || !host) {
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return { apiKey, host }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Track update failure event to PostHog.
|
|
53
|
-
* Fire-and-forget - errors are silently ignored.
|
|
54
|
-
*/
|
|
55
|
-
function trackUpdateFailed(errorMessage, version, context = {}) {
|
|
56
|
-
try {
|
|
57
|
-
const posthogConfig = getPostHogConfig()
|
|
58
|
-
if (!posthogConfig) {
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const payload = JSON.stringify({
|
|
63
|
-
api_key: posthogConfig.apiKey,
|
|
64
|
-
event: 'cli.update_vesper_failed',
|
|
65
|
-
properties: {
|
|
66
|
-
distinct_id: `anonymous-${CONFIG.homeDir}`,
|
|
67
|
-
error: errorMessage,
|
|
68
|
-
version: version || 'unknown',
|
|
69
|
-
platform: process.platform,
|
|
70
|
-
arch: process.arch,
|
|
71
|
-
...context,
|
|
72
|
-
},
|
|
73
|
-
timestamp: new Date().toISOString(),
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
const parsedUrl = new URL(`${posthogConfig.host}/capture/`)
|
|
77
|
-
const isHttps = parsedUrl.protocol === 'https:'
|
|
78
|
-
const options = {
|
|
79
|
-
hostname: parsedUrl.hostname,
|
|
80
|
-
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
81
|
-
path: parsedUrl.pathname + parsedUrl.search,
|
|
82
|
-
method: 'POST',
|
|
83
|
-
headers: {
|
|
84
|
-
'Content-Type': 'application/json',
|
|
85
|
-
'Content-Length': Buffer.byteLength(payload),
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const transport = isHttps ? https : http
|
|
90
|
-
const req = transport.request(options)
|
|
91
|
-
req.on('error', () => {}) // Silently ignore errors
|
|
92
|
-
req.write(payload)
|
|
93
|
-
req.end()
|
|
94
|
-
} catch (e) {
|
|
95
|
-
// Silently ignore any tracking errors
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const PLATFORM_TARGETS = {
|
|
100
|
-
'linux-x64': `${binaryBaseName}-linux-x64.tar.gz`,
|
|
101
|
-
'linux-arm64': `${binaryBaseName}-linux-arm64.tar.gz`,
|
|
102
|
-
'darwin-x64': `${binaryBaseName}-darwin-x64.tar.gz`,
|
|
103
|
-
'darwin-arm64': `${binaryBaseName}-darwin-arm64.tar.gz`,
|
|
104
|
-
'win32-x64': `${binaryBaseName}-win32-x64.tar.gz`,
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const term = {
|
|
108
|
-
clearLine: () => {
|
|
109
|
-
if (process.stderr.isTTY) {
|
|
110
|
-
process.stderr.write('\r\x1b[K')
|
|
111
|
-
}
|
|
8
|
+
const TARGET_PACKAGES = {
|
|
9
|
+
'darwin-arm64': {
|
|
10
|
+
packageName: 'vesper-code-darwin-arm64',
|
|
11
|
+
binaryName: 'vesper',
|
|
12
|
+
},
|
|
13
|
+
'darwin-x64': {
|
|
14
|
+
packageName: 'vesper-code-darwin-x64',
|
|
15
|
+
binaryName: 'vesper',
|
|
16
|
+
},
|
|
17
|
+
'linux-x64': {
|
|
18
|
+
packageName: 'vesper-code-linux-x64',
|
|
19
|
+
binaryName: 'vesper',
|
|
112
20
|
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
21
|
+
'linux-arm64': {
|
|
22
|
+
packageName: 'vesper-code-linux-arm64',
|
|
23
|
+
binaryName: 'vesper',
|
|
116
24
|
},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
25
|
+
'win32-x64': {
|
|
26
|
+
packageName: 'vesper-code-windows-x64',
|
|
27
|
+
binaryName: 'vesper.exe',
|
|
120
28
|
},
|
|
121
29
|
}
|
|
122
30
|
|
|
123
|
-
function
|
|
124
|
-
return
|
|
125
|
-
const parsedUrl = new URL(url)
|
|
126
|
-
const reqOptions = {
|
|
127
|
-
hostname: parsedUrl.hostname,
|
|
128
|
-
path: parsedUrl.pathname + parsedUrl.search,
|
|
129
|
-
headers: {
|
|
130
|
-
'User-Agent': CONFIG.userAgent,
|
|
131
|
-
...options.headers,
|
|
132
|
-
},
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const req = https.get(reqOptions, (res) => {
|
|
136
|
-
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
137
|
-
return httpGet(new URL(res.headers.location, url).href, options)
|
|
138
|
-
.then(resolve)
|
|
139
|
-
.catch(reject)
|
|
140
|
-
}
|
|
141
|
-
resolve(res)
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
req.on('error', reject)
|
|
145
|
-
|
|
146
|
-
const timeout = options.timeout || CONFIG.requestTimeout
|
|
147
|
-
req.setTimeout(timeout, () => {
|
|
148
|
-
req.destroy()
|
|
149
|
-
reject(new Error('Request timeout.'))
|
|
150
|
-
})
|
|
151
|
-
})
|
|
31
|
+
function getTarget() {
|
|
32
|
+
return `${process.platform}-${process.arch}`
|
|
152
33
|
}
|
|
153
34
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
`https://registry.npmjs.org/${packageName}/latest`,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
if (res.statusCode !== 200) return null
|
|
161
|
-
|
|
162
|
-
const body = await streamToString(res)
|
|
163
|
-
const packageData = JSON.parse(body)
|
|
35
|
+
function getPlatformPackage() {
|
|
36
|
+
const target = getTarget()
|
|
37
|
+
const platformPackage = TARGET_PACKAGES[target]
|
|
164
38
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
39
|
+
if (!platformPackage) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Unsupported platform: ${process.platform} ${process.arch}. ` +
|
|
42
|
+
'Supported targets: darwin-arm64, darwin-x64, linux-x64, linux-arm64, win32-x64.',
|
|
43
|
+
)
|
|
168
44
|
}
|
|
169
|
-
}
|
|
170
45
|
|
|
171
|
-
|
|
172
|
-
return new Promise((resolve, reject) => {
|
|
173
|
-
let data = ''
|
|
174
|
-
stream.on('data', (chunk) => (data += chunk))
|
|
175
|
-
stream.on('end', () => resolve(data))
|
|
176
|
-
stream.on('error', reject)
|
|
177
|
-
})
|
|
46
|
+
return platformPackage
|
|
178
47
|
}
|
|
179
48
|
|
|
180
|
-
function
|
|
49
|
+
function resolveBinaryPath() {
|
|
50
|
+
const platformPackage = getPlatformPackage()
|
|
51
|
+
|
|
52
|
+
let packageJsonPath
|
|
181
53
|
try {
|
|
182
|
-
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
const metadata = JSON.parse(fs.readFileSync(CONFIG.metadataPath, 'utf8'))
|
|
186
|
-
// Also verify the binary still exists
|
|
187
|
-
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
188
|
-
return null
|
|
189
|
-
}
|
|
190
|
-
return metadata.version || null
|
|
54
|
+
packageJsonPath = require.resolve(`${platformPackage.packageName}/package.json`)
|
|
191
55
|
} catch (error) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
function compareVersions(v1, v2) {
|
|
197
|
-
if (!v1 || !v2) return 0
|
|
198
|
-
|
|
199
|
-
// Always update if the current version is not a valid semver
|
|
200
|
-
// e.g. 1.0.420-beta.1
|
|
201
|
-
if (!v1.match(/^\d+(\.\d+)*$/)) {
|
|
202
|
-
return -1
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const parseVersion = (version) => {
|
|
206
|
-
const parts = version.split('-')
|
|
207
|
-
const mainParts = parts[0].split('.').map(Number)
|
|
208
|
-
const prereleaseParts = parts[1] ? parts[1].split('.') : []
|
|
209
|
-
return { main: mainParts, prerelease: prereleaseParts }
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const p1 = parseVersion(v1)
|
|
213
|
-
const p2 = parseVersion(v2)
|
|
214
|
-
|
|
215
|
-
for (let i = 0; i < Math.max(p1.main.length, p2.main.length); i++) {
|
|
216
|
-
const n1 = p1.main[i] || 0
|
|
217
|
-
const n2 = p2.main[i] || 0
|
|
218
|
-
|
|
219
|
-
if (n1 < n2) return -1
|
|
220
|
-
if (n1 > n2) return 1
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (p1.prerelease.length === 0 && p2.prerelease.length === 0) {
|
|
224
|
-
return 0
|
|
225
|
-
} else if (p1.prerelease.length === 0) {
|
|
226
|
-
return 1
|
|
227
|
-
} else if (p2.prerelease.length === 0) {
|
|
228
|
-
return -1
|
|
229
|
-
} else {
|
|
230
|
-
for (
|
|
231
|
-
let i = 0;
|
|
232
|
-
i < Math.max(p1.prerelease.length, p2.prerelease.length);
|
|
233
|
-
i++
|
|
234
|
-
) {
|
|
235
|
-
const pr1 = p1.prerelease[i] || ''
|
|
236
|
-
const pr2 = p2.prerelease[i] || ''
|
|
237
|
-
|
|
238
|
-
const isNum1 = !isNaN(parseInt(pr1))
|
|
239
|
-
const isNum2 = !isNaN(parseInt(pr2))
|
|
240
|
-
|
|
241
|
-
if (isNum1 && isNum2) {
|
|
242
|
-
const num1 = parseInt(pr1)
|
|
243
|
-
const num2 = parseInt(pr2)
|
|
244
|
-
if (num1 < num2) return -1
|
|
245
|
-
if (num1 > num2) return 1
|
|
246
|
-
} else if (isNum1 && !isNum2) {
|
|
247
|
-
return 1
|
|
248
|
-
} else if (!isNum1 && isNum2) {
|
|
249
|
-
return -1
|
|
250
|
-
} else if (pr1 < pr2) {
|
|
251
|
-
return -1
|
|
252
|
-
} else if (pr1 > pr2) {
|
|
253
|
-
return 1
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return 0
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function formatBytes(bytes) {
|
|
261
|
-
if (bytes === 0) return '0 B'
|
|
262
|
-
const k = 1024
|
|
263
|
-
const sizes = ['B', 'KB', 'MB', 'GB']
|
|
264
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
265
|
-
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function createProgressBar(percentage, width = 30) {
|
|
269
|
-
const filled = Math.round((width * percentage) / 100)
|
|
270
|
-
const empty = width - filled
|
|
271
|
-
return '[' + '█'.repeat(filled) + '░'.repeat(empty) + ']'
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
async function downloadBinary(version) {
|
|
275
|
-
const platformKey = `${process.platform}-${process.arch}`
|
|
276
|
-
const fileName = PLATFORM_TARGETS[platformKey]
|
|
277
|
-
|
|
278
|
-
if (!fileName) {
|
|
279
|
-
const error = new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
|
|
280
|
-
trackUpdateFailed(error.message, version, { stage: 'platform_check' })
|
|
281
|
-
throw error
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const downloadUrl = `${
|
|
285
|
-
process.env.NEXT_PUBLIC_VESPER_APP_URL || 'https://vesper-code-production.up.railway.app'
|
|
286
|
-
}/api/releases/download/${version}/${fileName}`
|
|
287
|
-
|
|
288
|
-
// Ensure config directory exists
|
|
289
|
-
fs.mkdirSync(CONFIG.configDir, { recursive: true })
|
|
290
|
-
|
|
291
|
-
// Clean up any previous temp download directory
|
|
292
|
-
if (fs.existsSync(CONFIG.tempDownloadDir)) {
|
|
293
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
294
|
-
}
|
|
295
|
-
fs.mkdirSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
296
|
-
|
|
297
|
-
term.write('Downloading...')
|
|
298
|
-
|
|
299
|
-
const res = await httpGet(downloadUrl)
|
|
300
|
-
|
|
301
|
-
if (res.statusCode !== 200) {
|
|
302
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
303
|
-
const error = new Error(`Download failed: HTTP ${res.statusCode}`)
|
|
304
|
-
trackUpdateFailed(error.message, version, { stage: 'http_download', statusCode: res.statusCode })
|
|
305
|
-
throw error
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Missing platform package ${platformPackage.packageName}. ` +
|
|
58
|
+
'Reinstall Vesper with optional dependencies enabled: npm install -g vesper-code',
|
|
59
|
+
)
|
|
306
60
|
}
|
|
307
61
|
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
downloadedSize += chunk.length
|
|
314
|
-
const now = Date.now()
|
|
315
|
-
if (now - lastProgressTime >= 100 || downloadedSize === totalSize) {
|
|
316
|
-
lastProgressTime = now
|
|
317
|
-
if (totalSize > 0) {
|
|
318
|
-
const pct = Math.round((downloadedSize / totalSize) * 100)
|
|
319
|
-
term.write(
|
|
320
|
-
`Downloading... ${createProgressBar(pct)} ${pct}% of ${formatBytes(
|
|
321
|
-
totalSize,
|
|
322
|
-
)}`,
|
|
323
|
-
)
|
|
324
|
-
} else {
|
|
325
|
-
term.write(`Downloading... ${formatBytes(downloadedSize)}`)
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
// Extract to temp directory
|
|
331
|
-
await new Promise((resolve, reject) => {
|
|
332
|
-
res
|
|
333
|
-
.pipe(zlib.createGunzip())
|
|
334
|
-
.pipe(tar.x({ cwd: CONFIG.tempDownloadDir }))
|
|
335
|
-
.on('finish', resolve)
|
|
336
|
-
.on('error', reject)
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
const tempBinaryPath = path.join(CONFIG.tempDownloadDir, CONFIG.binaryName)
|
|
340
|
-
|
|
341
|
-
// Verify the binary was extracted
|
|
342
|
-
if (!fs.existsSync(tempBinaryPath)) {
|
|
343
|
-
const files = fs.readdirSync(CONFIG.tempDownloadDir)
|
|
344
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
345
|
-
const error = new Error(
|
|
346
|
-
`Binary not found after extraction. Expected: ${CONFIG.binaryName}, Available files: ${files.join(', ')}`,
|
|
62
|
+
const binaryPath = path.join(path.dirname(packageJsonPath), platformPackage.binaryName)
|
|
63
|
+
if (!fs.existsSync(binaryPath)) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Platform package ${platformPackage.packageName} is installed, ` +
|
|
66
|
+
`but ${platformPackage.binaryName} is missing.`,
|
|
347
67
|
)
|
|
348
|
-
trackUpdateFailed(error.message, version, { stage: 'extraction' })
|
|
349
|
-
throw error
|
|
350
68
|
}
|
|
351
69
|
|
|
352
|
-
// Set executable permissions
|
|
353
70
|
if (process.platform !== 'win32') {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
try {
|
|
359
|
-
if (fs.existsSync(CONFIG.binaryPath)) {
|
|
360
|
-
try {
|
|
361
|
-
fs.unlinkSync(CONFIG.binaryPath)
|
|
362
|
-
} catch (err) {
|
|
363
|
-
// Fallback: try renaming the locked/undeletable binary (Windows)
|
|
364
|
-
const backupPath = CONFIG.binaryPath + `.old.${Date.now()}`
|
|
365
|
-
try {
|
|
366
|
-
fs.renameSync(CONFIG.binaryPath, backupPath)
|
|
367
|
-
} catch (renameErr) {
|
|
368
|
-
throw new Error(
|
|
369
|
-
`Failed to replace existing binary. ` +
|
|
370
|
-
`unlink error: ${err.code || err.message}, ` +
|
|
371
|
-
`rename error: ${renameErr.code || renameErr.message}`,
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
fs.renameSync(tempBinaryPath, CONFIG.binaryPath)
|
|
377
|
-
|
|
378
|
-
// Save version metadata for fast version checking
|
|
379
|
-
fs.writeFileSync(
|
|
380
|
-
CONFIG.metadataPath,
|
|
381
|
-
JSON.stringify({ version }, null, 2),
|
|
382
|
-
)
|
|
383
|
-
} finally {
|
|
384
|
-
// Clean up temp directory even if rename fails
|
|
385
|
-
if (fs.existsSync(CONFIG.tempDownloadDir)) {
|
|
386
|
-
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
71
|
+
try {
|
|
72
|
+
fs.chmodSync(binaryPath, 0o755)
|
|
73
|
+
} catch {
|
|
74
|
+
// Best effort. Spawn will surface a real permission error if this fails.
|
|
387
75
|
}
|
|
388
76
|
}
|
|
389
77
|
|
|
390
|
-
|
|
391
|
-
console.log('Download complete! Starting Vesper Code...')
|
|
78
|
+
return binaryPath
|
|
392
79
|
}
|
|
393
80
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
if (currentVersion !== null) {
|
|
397
|
-
return
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const version = await getLatestVersion()
|
|
401
|
-
if (!version) {
|
|
402
|
-
console.error('❌ Failed to determine latest version')
|
|
403
|
-
console.error('Please check your internet connection and try again')
|
|
404
|
-
process.exit(1)
|
|
405
|
-
}
|
|
406
|
-
|
|
81
|
+
function main() {
|
|
82
|
+
let binaryPath
|
|
407
83
|
try {
|
|
408
|
-
|
|
84
|
+
binaryPath = resolveBinaryPath()
|
|
409
85
|
} catch (error) {
|
|
410
|
-
|
|
411
|
-
console.error(
|
|
412
|
-
console.error('
|
|
86
|
+
console.error('Failed to start Vesper Code.')
|
|
87
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
88
|
+
console.error('')
|
|
89
|
+
console.error('Debug info:')
|
|
90
|
+
console.error(` platform: ${process.platform}`)
|
|
91
|
+
console.error(` arch: ${process.arch}`)
|
|
92
|
+
console.error(` node: ${process.version}`)
|
|
93
|
+
console.error(` home: ${os.homedir()}`)
|
|
413
94
|
process.exit(1)
|
|
414
95
|
}
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
async function checkForUpdates(runningProcess, exitListener) {
|
|
418
|
-
try {
|
|
419
|
-
const currentVersion = getCurrentVersion()
|
|
420
|
-
|
|
421
|
-
const latestVersion = await getLatestVersion()
|
|
422
|
-
if (!latestVersion) return
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
// Download new version if current version is unknown or outdated.
|
|
426
|
-
currentVersion === null ||
|
|
427
|
-
compareVersions(currentVersion, latestVersion) < 0
|
|
428
|
-
) {
|
|
429
|
-
term.clearLine()
|
|
430
96
|
|
|
431
|
-
|
|
432
|
-
runningProcess.kill('SIGTERM')
|
|
433
|
-
|
|
434
|
-
await new Promise((resolve) => {
|
|
435
|
-
runningProcess.on('exit', resolve)
|
|
436
|
-
setTimeout(() => {
|
|
437
|
-
if (!runningProcess.killed) {
|
|
438
|
-
runningProcess.kill('SIGKILL')
|
|
439
|
-
}
|
|
440
|
-
resolve()
|
|
441
|
-
}, 5000)
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
console.log(`Update available: ${currentVersion} → ${latestVersion}`)
|
|
445
|
-
|
|
446
|
-
await downloadBinary(latestVersion)
|
|
447
|
-
|
|
448
|
-
const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
449
|
-
stdio: 'inherit',
|
|
450
|
-
detached: false,
|
|
451
|
-
})
|
|
452
|
-
|
|
453
|
-
newChild.on('exit', (code) => {
|
|
454
|
-
process.exit(code || 0)
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
return new Promise(() => {})
|
|
458
|
-
}
|
|
459
|
-
} catch (error) {
|
|
460
|
-
// Ignore update failures
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
async function main() {
|
|
465
|
-
await ensureBinaryExists()
|
|
466
|
-
|
|
467
|
-
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
97
|
+
const child = spawn(binaryPath, process.argv.slice(2), {
|
|
468
98
|
stdio: 'inherit',
|
|
99
|
+
env: process.env,
|
|
469
100
|
})
|
|
470
101
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
102
|
+
child.on('error', (error) => {
|
|
103
|
+
console.error('Failed to start Vesper Code.')
|
|
104
|
+
console.error(error.message)
|
|
105
|
+
process.exit(1)
|
|
106
|
+
})
|
|
476
107
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
108
|
+
child.on('exit', (code, signal) => {
|
|
109
|
+
if (signal) {
|
|
110
|
+
process.kill(process.pid, signal)
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
process.exit(code || 0)
|
|
114
|
+
})
|
|
480
115
|
}
|
|
481
116
|
|
|
482
|
-
main()
|
|
483
|
-
console.error('❌ Unexpected error:', error.message)
|
|
484
|
-
process.exit(1)
|
|
485
|
-
})
|
|
117
|
+
main()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vesper-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Vesper Code — AI coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -28,14 +28,18 @@
|
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=16"
|
|
30
30
|
},
|
|
31
|
-
"
|
|
32
|
-
"
|
|
31
|
+
"optionalDependencies": {
|
|
32
|
+
"vesper-code-darwin-arm64": "1.0.1",
|
|
33
|
+
"vesper-code-darwin-x64": "1.0.1",
|
|
34
|
+
"vesper-code-linux-arm64": "1.0.1",
|
|
35
|
+
"vesper-code-linux-x64": "1.0.1",
|
|
36
|
+
"vesper-code-windows-x64": "1.0.1"
|
|
33
37
|
},
|
|
34
38
|
"repository": {
|
|
35
39
|
"type": "git",
|
|
36
40
|
"url": "https://github.com/andreygoldman13/vesper-code.git"
|
|
37
41
|
},
|
|
38
|
-
"homepage": "https://
|
|
42
|
+
"homepage": "https://vespercode.com",
|
|
39
43
|
"publishConfig": {
|
|
40
44
|
"access": "public"
|
|
41
45
|
}
|
package/postinstall.js
CHANGED