codebuff 1.0.512 → 1.0.515
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 +140 -155
- package/package.json +1 -2
package/index.js
CHANGED
|
@@ -7,52 +7,52 @@ const os = require('os')
|
|
|
7
7
|
const path = require('path')
|
|
8
8
|
const zlib = require('zlib')
|
|
9
9
|
|
|
10
|
-
const { Command } = require('commander')
|
|
11
10
|
const tar = require('tar')
|
|
12
11
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
const packageName = 'codebuff'
|
|
13
|
+
|
|
14
|
+
function createConfig(packageName) {
|
|
15
|
+
const homeDir = os.homedir()
|
|
16
|
+
const configDir = path.join(homeDir, '.config', 'manicode')
|
|
17
|
+
const binaryName =
|
|
18
|
+
process.platform === 'win32' ? `${packageName}.exe` : packageName
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
homeDir,
|
|
22
|
+
configDir,
|
|
23
|
+
binaryName,
|
|
24
|
+
binaryPath: path.join(configDir, binaryName),
|
|
25
|
+
userAgent: `${packageName}-cli`,
|
|
26
|
+
requestTimeout: 20000,
|
|
27
|
+
}
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
CONFIG
|
|
30
|
+
const CONFIG = createConfig(packageName)
|
|
23
31
|
|
|
24
|
-
// Platform target mapping
|
|
25
32
|
const PLATFORM_TARGETS = {
|
|
26
|
-
'linux-x64':
|
|
27
|
-
'linux-arm64':
|
|
28
|
-
'darwin-x64':
|
|
29
|
-
'darwin-arm64':
|
|
30
|
-
'win32-x64':
|
|
33
|
+
'linux-x64': `${packageName}-linux-x64.tar.gz`,
|
|
34
|
+
'linux-arm64': `${packageName}-linux-arm64.tar.gz`,
|
|
35
|
+
'darwin-x64': `${packageName}-darwin-x64.tar.gz`,
|
|
36
|
+
'darwin-arm64': `${packageName}-darwin-arm64.tar.gz`,
|
|
37
|
+
'win32-x64': `${packageName}-win32-x64.tar.gz`,
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
// Terminal utilities
|
|
34
|
-
let isPrintMode = false
|
|
35
40
|
const term = {
|
|
36
41
|
clearLine: () => {
|
|
37
|
-
if (
|
|
42
|
+
if (process.stderr.isTTY) {
|
|
38
43
|
process.stderr.write('\r\x1b[K')
|
|
39
44
|
}
|
|
40
45
|
},
|
|
41
46
|
write: (text) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
process.stderr.write(text)
|
|
45
|
-
}
|
|
47
|
+
term.clearLine()
|
|
48
|
+
process.stderr.write(text)
|
|
46
49
|
},
|
|
47
50
|
writeLine: (text) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
process.stderr.write(text + '\n')
|
|
51
|
-
}
|
|
51
|
+
term.clearLine()
|
|
52
|
+
process.stderr.write(text + '\n')
|
|
52
53
|
},
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
// Utility functions
|
|
56
56
|
function httpGet(url, options = {}) {
|
|
57
57
|
return new Promise((resolve, reject) => {
|
|
58
58
|
const parsedUrl = new URL(url)
|
|
@@ -65,12 +65,6 @@ function httpGet(url, options = {}) {
|
|
|
65
65
|
},
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// Add GitHub token if available
|
|
69
|
-
const token = process.env.GITHUB_TOKEN
|
|
70
|
-
if (token) {
|
|
71
|
-
reqOptions.headers.Authorization = `Bearer ${token}`
|
|
72
|
-
}
|
|
73
|
-
|
|
74
68
|
const req = https.get(reqOptions, (res) => {
|
|
75
69
|
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
76
70
|
return httpGet(new URL(res.headers.location, url).href, options)
|
|
@@ -117,13 +111,10 @@ function streamToString(stream) {
|
|
|
117
111
|
}
|
|
118
112
|
|
|
119
113
|
function getCurrentVersion() {
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
if (!fs.existsSync(CONFIG.binaryPath)) {
|
|
123
|
-
resolve('error')
|
|
124
|
-
return
|
|
125
|
-
}
|
|
114
|
+
if (!fs.existsSync(CONFIG.binaryPath)) return null
|
|
126
115
|
|
|
116
|
+
try {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
127
118
|
const child = spawn(CONFIG.binaryPath, ['--version'], {
|
|
128
119
|
cwd: os.homedir(),
|
|
129
120
|
stdio: 'pipe',
|
|
@@ -146,9 +137,9 @@ function getCurrentVersion() {
|
|
|
146
137
|
if (!child.killed) {
|
|
147
138
|
child.kill('SIGKILL')
|
|
148
139
|
}
|
|
149
|
-
},
|
|
140
|
+
}, 4000)
|
|
150
141
|
resolve('error')
|
|
151
|
-
},
|
|
142
|
+
}, 4000)
|
|
152
143
|
|
|
153
144
|
child.on('exit', (code) => {
|
|
154
145
|
clearTimeout(timeout)
|
|
@@ -163,31 +154,74 @@ function getCurrentVersion() {
|
|
|
163
154
|
clearTimeout(timeout)
|
|
164
155
|
resolve('error')
|
|
165
156
|
})
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
157
|
+
})
|
|
158
|
+
} catch (error) {
|
|
159
|
+
return 'error'
|
|
160
|
+
}
|
|
170
161
|
}
|
|
171
162
|
|
|
172
163
|
function compareVersions(v1, v2) {
|
|
173
164
|
if (!v1 || !v2) return 0
|
|
174
165
|
|
|
166
|
+
// Always update if the current version is not a valid semver
|
|
167
|
+
// e.g. 1.0.420-beta.1
|
|
175
168
|
if (!v1.match(/^\d+(\.\d+)*$/)) {
|
|
176
169
|
return -1
|
|
177
170
|
}
|
|
178
171
|
|
|
179
|
-
const
|
|
180
|
-
|
|
172
|
+
const parseVersion = (version) => {
|
|
173
|
+
const parts = version.split('-')
|
|
174
|
+
const mainParts = parts[0].split('.').map(Number)
|
|
175
|
+
const prereleaseParts = parts[1] ? parts[1].split('.') : []
|
|
176
|
+
return { main: mainParts, prerelease: prereleaseParts }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const p1 = parseVersion(v1)
|
|
180
|
+
const p2 = parseVersion(v2)
|
|
181
181
|
|
|
182
|
-
for (let i = 0; i < Math.max(
|
|
183
|
-
const
|
|
184
|
-
const
|
|
182
|
+
for (let i = 0; i < Math.max(p1.main.length, p2.main.length); i++) {
|
|
183
|
+
const n1 = p1.main[i] || 0
|
|
184
|
+
const n2 = p2.main[i] || 0
|
|
185
185
|
|
|
186
|
-
if (
|
|
187
|
-
if (
|
|
186
|
+
if (n1 < n2) return -1
|
|
187
|
+
if (n1 > n2) return 1
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
if (p1.prerelease.length === 0 && p2.prerelease.length === 0) {
|
|
191
|
+
return 0
|
|
192
|
+
} else if (p1.prerelease.length === 0) {
|
|
193
|
+
return 1
|
|
194
|
+
} else if (p2.prerelease.length === 0) {
|
|
195
|
+
return -1
|
|
196
|
+
} else {
|
|
197
|
+
for (
|
|
198
|
+
let i = 0;
|
|
199
|
+
i < Math.max(p1.prerelease.length, p2.prerelease.length);
|
|
200
|
+
i++
|
|
201
|
+
) {
|
|
202
|
+
const pr1 = p1.prerelease[i] || ''
|
|
203
|
+
const pr2 = p2.prerelease[i] || ''
|
|
204
|
+
|
|
205
|
+
const isNum1 = !isNaN(parseInt(pr1))
|
|
206
|
+
const isNum2 = !isNaN(parseInt(pr2))
|
|
207
|
+
|
|
208
|
+
if (isNum1 && isNum2) {
|
|
209
|
+
const num1 = parseInt(pr1)
|
|
210
|
+
const num2 = parseInt(pr2)
|
|
211
|
+
if (num1 < num2) return -1
|
|
212
|
+
if (num1 > num2) return 1
|
|
213
|
+
} else if (isNum1 && !isNum2) {
|
|
214
|
+
return 1
|
|
215
|
+
} else if (!isNum1 && isNum2) {
|
|
216
|
+
return -1
|
|
217
|
+
} else if (pr1 < pr2) {
|
|
218
|
+
return -1
|
|
219
|
+
} else if (pr1 > pr2) {
|
|
220
|
+
return 1
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return 0
|
|
224
|
+
}
|
|
191
225
|
}
|
|
192
226
|
|
|
193
227
|
function formatBytes(bytes) {
|
|
@@ -212,16 +246,30 @@ async function downloadBinary(version) {
|
|
|
212
246
|
throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
|
|
213
247
|
}
|
|
214
248
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
: `https://codebuff.com/api/releases/download/${version}/${fileName}`
|
|
249
|
+
const downloadUrl = `${
|
|
250
|
+
process.env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'https://codebuff.com'
|
|
251
|
+
}/api/releases/download/${version}/${fileName}`
|
|
219
252
|
|
|
220
|
-
// Ensure config directory exists
|
|
221
253
|
fs.mkdirSync(CONFIG.configDir, { recursive: true })
|
|
222
254
|
|
|
223
255
|
if (fs.existsSync(CONFIG.binaryPath)) {
|
|
224
|
-
|
|
256
|
+
try {
|
|
257
|
+
fs.unlinkSync(CONFIG.binaryPath)
|
|
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
|
+
}
|
|
225
273
|
}
|
|
226
274
|
|
|
227
275
|
term.write('Downloading...')
|
|
@@ -263,7 +311,6 @@ async function downloadBinary(version) {
|
|
|
263
311
|
})
|
|
264
312
|
|
|
265
313
|
try {
|
|
266
|
-
// Find the extracted binary - it should be named "codebuff" or "codebuff.exe"
|
|
267
314
|
const files = fs.readdirSync(CONFIG.configDir)
|
|
268
315
|
const extractedPath = path.join(CONFIG.configDir, CONFIG.binaryName)
|
|
269
316
|
|
|
@@ -278,20 +325,12 @@ async function downloadBinary(version) {
|
|
|
278
325
|
}
|
|
279
326
|
} catch (error) {
|
|
280
327
|
term.clearLine()
|
|
281
|
-
|
|
282
|
-
console.error(`Extraction failed: ${error.message}`)
|
|
283
|
-
}
|
|
328
|
+
console.error(`Extraction failed: ${error.message}`)
|
|
284
329
|
process.exit(1)
|
|
285
330
|
}
|
|
286
331
|
|
|
287
332
|
term.clearLine()
|
|
288
|
-
|
|
289
|
-
console.log(
|
|
290
|
-
JSON.stringify({ type: 'download', version, status: 'complete' }),
|
|
291
|
-
)
|
|
292
|
-
} else {
|
|
293
|
-
console.log('Download complete! Starting Codebuff...')
|
|
294
|
-
}
|
|
333
|
+
console.log('Download complete! Starting Codebuff...')
|
|
295
334
|
}
|
|
296
335
|
|
|
297
336
|
async function ensureBinaryExists() {
|
|
@@ -302,17 +341,8 @@ async function ensureBinaryExists() {
|
|
|
302
341
|
|
|
303
342
|
const version = await getLatestVersion()
|
|
304
343
|
if (!version) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
JSON.stringify({
|
|
308
|
-
type: 'error',
|
|
309
|
-
message: 'Failed to determine latest version.',
|
|
310
|
-
}),
|
|
311
|
-
)
|
|
312
|
-
} else {
|
|
313
|
-
console.error('❌ Failed to determine latest version')
|
|
314
|
-
console.error('Please check your internet connection and try again')
|
|
315
|
-
}
|
|
344
|
+
console.error('❌ Failed to determine latest version')
|
|
345
|
+
console.error('Please check your internet connection and try again')
|
|
316
346
|
process.exit(1)
|
|
317
347
|
}
|
|
318
348
|
|
|
@@ -320,45 +350,31 @@ async function ensureBinaryExists() {
|
|
|
320
350
|
await downloadBinary(version)
|
|
321
351
|
} catch (error) {
|
|
322
352
|
term.clearLine()
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
JSON.stringify({
|
|
326
|
-
type: 'error',
|
|
327
|
-
message: `Failed to download codebuff: ${error.message}`,
|
|
328
|
-
}),
|
|
329
|
-
)
|
|
330
|
-
} else {
|
|
331
|
-
console.error('❌ Failed to download codebuff:', error.message)
|
|
332
|
-
console.error('Please check your internet connection and try again')
|
|
333
|
-
}
|
|
353
|
+
console.error('❌ Failed to download codebuff:', error.message)
|
|
354
|
+
console.error('Please check your internet connection and try again')
|
|
334
355
|
process.exit(1)
|
|
335
356
|
}
|
|
336
357
|
}
|
|
337
358
|
|
|
338
|
-
async function checkForUpdates(runningProcess, exitListener
|
|
359
|
+
async function checkForUpdates(runningProcess, exitListener) {
|
|
339
360
|
try {
|
|
340
361
|
const currentVersion = await getCurrentVersion()
|
|
362
|
+
if (!currentVersion) return
|
|
341
363
|
|
|
342
364
|
const latestVersion = await getLatestVersion()
|
|
343
365
|
if (!latestVersion) return
|
|
344
366
|
|
|
345
367
|
if (
|
|
346
|
-
// Download new version if current binary errors.
|
|
347
368
|
currentVersion === 'error' ||
|
|
348
369
|
compareVersions(currentVersion, latestVersion) < 0
|
|
349
370
|
) {
|
|
350
371
|
term.clearLine()
|
|
351
372
|
|
|
352
|
-
// Remove the specific exit listener to prevent it from interfering with the update
|
|
353
373
|
runningProcess.removeListener('exit', exitListener)
|
|
354
|
-
|
|
355
|
-
// Kill the running process
|
|
356
374
|
runningProcess.kill('SIGTERM')
|
|
357
375
|
|
|
358
|
-
// Wait for the process to actually exit
|
|
359
376
|
await new Promise((resolve) => {
|
|
360
377
|
runningProcess.on('exit', resolve)
|
|
361
|
-
// Fallback timeout in case the process doesn't exit gracefully
|
|
362
378
|
setTimeout(() => {
|
|
363
379
|
if (!runningProcess.killed) {
|
|
364
380
|
runningProcess.kill('SIGKILL')
|
|
@@ -367,76 +383,45 @@ async function checkForUpdates(runningProcess, exitListener, retry) {
|
|
|
367
383
|
}, 5000)
|
|
368
384
|
})
|
|
369
385
|
|
|
370
|
-
|
|
371
|
-
console.log(`Update available: ${currentVersion} → ${latestVersion}`)
|
|
372
|
-
}
|
|
386
|
+
console.log(`Update available: ${currentVersion} → ${latestVersion}`)
|
|
373
387
|
|
|
374
388
|
await downloadBinary(latestVersion)
|
|
375
389
|
|
|
376
|
-
|
|
390
|
+
const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
391
|
+
stdio: 'inherit',
|
|
392
|
+
detached: false,
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
newChild.on('exit', (code) => {
|
|
396
|
+
process.exit(code || 0)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
return new Promise(() => {})
|
|
377
400
|
}
|
|
378
401
|
} catch (error) {
|
|
379
|
-
//
|
|
402
|
+
// Ignore update failures
|
|
380
403
|
}
|
|
381
404
|
}
|
|
382
405
|
|
|
383
|
-
async function main(
|
|
384
|
-
isPrintMode = printMode
|
|
406
|
+
async function main() {
|
|
385
407
|
await ensureBinaryExists()
|
|
386
408
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
391
|
-
stdio: 'inherit',
|
|
392
|
-
})
|
|
409
|
+
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
|
|
410
|
+
stdio: 'inherit',
|
|
411
|
+
})
|
|
393
412
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
413
|
+
const exitListener = (code) => {
|
|
414
|
+
process.exit(code || 0)
|
|
415
|
+
}
|
|
398
416
|
|
|
399
|
-
|
|
417
|
+
child.on('exit', exitListener)
|
|
400
418
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if (!error) {
|
|
405
|
-
checkForUpdates(child, exitListener, () => main(false, isPrintMode))
|
|
406
|
-
}
|
|
407
|
-
}, 100)
|
|
408
|
-
}
|
|
409
|
-
} catch (err) {
|
|
410
|
-
error = err
|
|
411
|
-
if (firstRun) {
|
|
412
|
-
if (!isPrintMode) {
|
|
413
|
-
console.error('❌ Codebuff failed to start:', error.message)
|
|
414
|
-
console.log('Redownloading Codebuff...')
|
|
415
|
-
}
|
|
416
|
-
// Binary could be corrupted (killed before download completed), so delete and retry.
|
|
417
|
-
fs.unlinkSync(CONFIG.binaryPath)
|
|
418
|
-
await main(false, isPrintMode)
|
|
419
|
-
}
|
|
420
|
-
}
|
|
419
|
+
setTimeout(() => {
|
|
420
|
+
checkForUpdates(child, exitListener)
|
|
421
|
+
}, 100)
|
|
421
422
|
}
|
|
422
423
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
program
|
|
426
|
-
.name('codebuff')
|
|
427
|
-
.description('AI coding agent')
|
|
428
|
-
.helpOption(false)
|
|
429
|
-
.option('-p, --print', 'print mode - suppress wrapper output')
|
|
430
|
-
.allowUnknownOption()
|
|
431
|
-
.parse()
|
|
432
|
-
|
|
433
|
-
const options = program.opts()
|
|
434
|
-
isPrintMode = options.print
|
|
435
|
-
|
|
436
|
-
// Run the main function
|
|
437
|
-
main(true, isPrintMode).catch((error) => {
|
|
438
|
-
if (!isPrintMode) {
|
|
439
|
-
console.error('❌ Unexpected error:', error.message)
|
|
440
|
-
}
|
|
424
|
+
main().catch((error) => {
|
|
425
|
+
console.error('❌ Unexpected error:', error.message)
|
|
441
426
|
process.exit(1)
|
|
442
427
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codebuff",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.515",
|
|
4
4
|
"description": "AI coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"node": ">=16"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"commander": "^12.0.0",
|
|
31
30
|
"tar": "^6.2.0"
|
|
32
31
|
},
|
|
33
32
|
"repository": {
|