codebuff 1.0.534 → 1.0.536
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 +118 -77
- package/package.json +1 -1
- package/postinstall.js +1 -1
package/index.js
CHANGED
|
@@ -22,6 +22,8 @@ function createConfig(packageName) {
|
|
|
22
22
|
configDir,
|
|
23
23
|
binaryName,
|
|
24
24
|
binaryPath: path.join(configDir, binaryName),
|
|
25
|
+
metadataPath: path.join(configDir, 'codebuff-metadata.json'),
|
|
26
|
+
tempDownloadDir: path.join(configDir, '.download-temp'),
|
|
25
27
|
userAgent: `${packageName}-cli`,
|
|
26
28
|
requestTimeout: 20000,
|
|
27
29
|
}
|
|
@@ -111,53 +113,64 @@ function streamToString(stream) {
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
function getCurrentVersion() {
|
|
114
|
-
if (!fs.existsSync(CONFIG.binaryPath)) return null
|
|
115
|
-
|
|
116
116
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
if (!fs.existsSync(CONFIG.metadataPath)) {
|
|
118
|
+
return null
|
|
119
|
+
}
|
|
120
|
+
const metadata = JSON.parse(fs.readFileSync(CONFIG.metadataPath, 'utf8'))
|
|
121
|
+
// Also verify the binary still exists
|
|
122
|
+
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
123
|
+
return null
|
|
124
|
+
}
|
|
125
|
+
return metadata.version || null
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
}
|
|
122
130
|
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
function runSmokeTest(binaryPath) {
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
if (!fs.existsSync(binaryPath)) {
|
|
134
|
+
resolve(false)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
125
137
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
138
|
+
const child = spawn(binaryPath, ['--version'], {
|
|
139
|
+
cwd: os.homedir(),
|
|
140
|
+
stdio: 'pipe',
|
|
141
|
+
})
|
|
129
142
|
|
|
130
|
-
|
|
131
|
-
errorOutput += data.toString()
|
|
132
|
-
})
|
|
143
|
+
let output = ''
|
|
133
144
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
child.on('exit', (code) => {
|
|
145
|
-
clearTimeout(timeout)
|
|
146
|
-
if (code === 0) {
|
|
147
|
-
resolve(output.trim())
|
|
148
|
-
} else {
|
|
149
|
-
resolve('error')
|
|
145
|
+
child.stdout.on('data', (data) => {
|
|
146
|
+
output += data.toString()
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const timeout = setTimeout(() => {
|
|
150
|
+
child.kill('SIGTERM')
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
if (!child.killed) {
|
|
153
|
+
child.kill('SIGKILL')
|
|
150
154
|
}
|
|
151
|
-
})
|
|
155
|
+
}, 1000)
|
|
156
|
+
resolve(false)
|
|
157
|
+
}, 5000)
|
|
158
|
+
|
|
159
|
+
child.on('exit', (code) => {
|
|
160
|
+
clearTimeout(timeout)
|
|
161
|
+
// Check that it exits successfully and outputs something that looks like a version
|
|
162
|
+
if (code === 0 && output.trim().match(/^\d+(\.\d+)*$/)) {
|
|
163
|
+
resolve(true)
|
|
164
|
+
} else {
|
|
165
|
+
resolve(false)
|
|
166
|
+
}
|
|
167
|
+
})
|
|
152
168
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
})
|
|
169
|
+
child.on('error', () => {
|
|
170
|
+
clearTimeout(timeout)
|
|
171
|
+
resolve(false)
|
|
157
172
|
})
|
|
158
|
-
}
|
|
159
|
-
return 'error'
|
|
160
|
-
}
|
|
173
|
+
})
|
|
161
174
|
}
|
|
162
175
|
|
|
163
176
|
function compareVersions(v1, v2) {
|
|
@@ -250,33 +263,21 @@ async function downloadBinary(version) {
|
|
|
250
263
|
process.env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'https://codebuff.com'
|
|
251
264
|
}/api/releases/download/${version}/${fileName}`
|
|
252
265
|
|
|
266
|
+
// Ensure config directory exists
|
|
253
267
|
fs.mkdirSync(CONFIG.configDir, { recursive: true })
|
|
254
268
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
} catch (err) {
|
|
259
|
-
// Fallback: try renaming the locked/undeletable binary
|
|
260
|
-
const backupPath = CONFIG.binaryPath + `.old.${Date.now()}`
|
|
261
|
-
|
|
262
|
-
try {
|
|
263
|
-
fs.renameSync(CONFIG.binaryPath, backupPath)
|
|
264
|
-
} catch (renameErr) {
|
|
265
|
-
// If we can't unlink OR rename, we can't safely proceed
|
|
266
|
-
throw new Error(
|
|
267
|
-
`Failed to replace existing binary. ` +
|
|
268
|
-
`unlink error: ${err.code || err.message}, ` +
|
|
269
|
-
`rename error: ${renameErr.code || renameErr.message}`,
|
|
270
|
-
)
|
|
271
|
-
}
|
|
272
|
-
}
|
|
269
|
+
// Clean up any previous temp download directory
|
|
270
|
+
if (fs.existsSync(CONFIG.tempDownloadDir)) {
|
|
271
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
273
272
|
}
|
|
273
|
+
fs.mkdirSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
274
274
|
|
|
275
275
|
term.write('Downloading...')
|
|
276
276
|
|
|
277
277
|
const res = await httpGet(downloadUrl)
|
|
278
278
|
|
|
279
279
|
if (res.statusCode !== 200) {
|
|
280
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
280
281
|
throw new Error(`Download failed: HTTP ${res.statusCode}`)
|
|
281
282
|
}
|
|
282
283
|
|
|
@@ -302,31 +303,71 @@ async function downloadBinary(version) {
|
|
|
302
303
|
}
|
|
303
304
|
})
|
|
304
305
|
|
|
306
|
+
// Extract to temp directory
|
|
305
307
|
await new Promise((resolve, reject) => {
|
|
306
308
|
res
|
|
307
309
|
.pipe(zlib.createGunzip())
|
|
308
|
-
.pipe(tar.x({ cwd: CONFIG.
|
|
310
|
+
.pipe(tar.x({ cwd: CONFIG.tempDownloadDir }))
|
|
309
311
|
.on('finish', resolve)
|
|
310
312
|
.on('error', reject)
|
|
311
313
|
})
|
|
312
314
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
315
|
+
const tempBinaryPath = path.join(CONFIG.tempDownloadDir, CONFIG.binaryName)
|
|
316
|
+
|
|
317
|
+
// Verify the binary was extracted
|
|
318
|
+
if (!fs.existsSync(tempBinaryPath)) {
|
|
319
|
+
const files = fs.readdirSync(CONFIG.tempDownloadDir)
|
|
320
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
321
|
+
throw new Error(
|
|
322
|
+
`Binary not found after extraction. Expected: ${CONFIG.binaryName}, Available files: ${files.join(', ')}`,
|
|
323
|
+
)
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Set executable permissions
|
|
327
|
+
if (process.platform !== 'win32') {
|
|
328
|
+
fs.chmodSync(tempBinaryPath, 0o755)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Run smoke test on the downloaded binary
|
|
332
|
+
term.write('Verifying download...')
|
|
333
|
+
const smokeTestPassed = await runSmokeTest(tempBinaryPath)
|
|
316
334
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
335
|
+
if (!smokeTestPassed) {
|
|
336
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
337
|
+
throw new Error('Downloaded binary failed smoke test (--version check)')
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Smoke test passed - move binary to final location
|
|
341
|
+
try {
|
|
342
|
+
if (fs.existsSync(CONFIG.binaryPath)) {
|
|
343
|
+
try {
|
|
344
|
+
fs.unlinkSync(CONFIG.binaryPath)
|
|
345
|
+
} catch (err) {
|
|
346
|
+
// Fallback: try renaming the locked/undeletable binary (Windows)
|
|
347
|
+
const backupPath = CONFIG.binaryPath + `.old.${Date.now()}`
|
|
348
|
+
try {
|
|
349
|
+
fs.renameSync(CONFIG.binaryPath, backupPath)
|
|
350
|
+
} catch (renameErr) {
|
|
351
|
+
throw new Error(
|
|
352
|
+
`Failed to replace existing binary. ` +
|
|
353
|
+
`unlink error: ${err.code || err.message}, ` +
|
|
354
|
+
`rename error: ${renameErr.code || renameErr.message}`,
|
|
355
|
+
)
|
|
356
|
+
}
|
|
320
357
|
}
|
|
321
|
-
} else {
|
|
322
|
-
throw new Error(
|
|
323
|
-
`Binary not found after extraction. Expected: ${extractedPath}, Available files: ${files.join(', ')}`,
|
|
324
|
-
)
|
|
325
358
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
359
|
+
fs.renameSync(tempBinaryPath, CONFIG.binaryPath)
|
|
360
|
+
|
|
361
|
+
// Save version metadata for fast version checking
|
|
362
|
+
fs.writeFileSync(
|
|
363
|
+
CONFIG.metadataPath,
|
|
364
|
+
JSON.stringify({ version }, null, 2),
|
|
365
|
+
)
|
|
366
|
+
} finally {
|
|
367
|
+
// Clean up temp directory even if rename fails
|
|
368
|
+
if (fs.existsSync(CONFIG.tempDownloadDir)) {
|
|
369
|
+
fs.rmSync(CONFIG.tempDownloadDir, { recursive: true })
|
|
370
|
+
}
|
|
330
371
|
}
|
|
331
372
|
|
|
332
373
|
term.clearLine()
|
|
@@ -334,8 +375,8 @@ async function downloadBinary(version) {
|
|
|
334
375
|
}
|
|
335
376
|
|
|
336
377
|
async function ensureBinaryExists() {
|
|
337
|
-
const currentVersion =
|
|
338
|
-
if (currentVersion !== null
|
|
378
|
+
const currentVersion = getCurrentVersion()
|
|
379
|
+
if (currentVersion !== null) {
|
|
339
380
|
return
|
|
340
381
|
}
|
|
341
382
|
|
|
@@ -358,14 +399,14 @@ async function ensureBinaryExists() {
|
|
|
358
399
|
|
|
359
400
|
async function checkForUpdates(runningProcess, exitListener) {
|
|
360
401
|
try {
|
|
361
|
-
const currentVersion =
|
|
362
|
-
if (!currentVersion) return
|
|
402
|
+
const currentVersion = getCurrentVersion()
|
|
363
403
|
|
|
364
404
|
const latestVersion = await getLatestVersion()
|
|
365
405
|
if (!latestVersion) return
|
|
366
406
|
|
|
367
407
|
if (
|
|
368
|
-
|
|
408
|
+
// Download new version if current version is unknown or outdated.
|
|
409
|
+
currentVersion === null ||
|
|
369
410
|
compareVersions(currentVersion, latestVersion) < 0
|
|
370
411
|
) {
|
|
371
412
|
term.clearLine()
|
package/package.json
CHANGED