codebuff 1.0.512 → 1.0.514

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 (3) hide show
  1. package/README.md +18 -16
  2. package/index.js +140 -155
  3. package/package.json +1 -2
package/README.md CHANGED
@@ -1,49 +1,51 @@
1
- # The most powerful coding agent
1
+ # 🚀 Codecane - The most powerful coding agent (STAGING)
2
2
 
3
- Codebuff is a CLI tool that writes code for you.
3
+ **⚠️ This is a staging/beta release for testing purposes.**
4
4
 
5
- 1. Run `codebuff` from your project directory
5
+ Codecane is a CLI tool that writes code for you.
6
+
7
+ 1. Run `codecane` from your project directory
6
8
  2. Tell it what to do
7
9
  3. It will read and write to files and run commands to produce the code you want
8
10
 
9
- Note: Codebuff will run commands in your terminal as it deems necessary to fulfill your request.
11
+ Note: Codecane will run commands in your terminal as it deems necessary to fulfill your request.
10
12
 
11
13
  ## Installation
12
14
 
13
- To install Codebuff, run:
15
+ To install Codecane (staging), run:
14
16
 
15
17
  ```bash
16
- npm install -g codebuff
18
+ npm install -g codecane@beta
17
19
  ```
18
20
 
19
21
  (Use `sudo` if you get a permission error.)
20
22
 
21
23
  ## Usage
22
24
 
23
- After installation, you can start Codebuff by running:
25
+ After installation, you can start Codecane by running:
24
26
 
25
27
  ```bash
26
- codebuff [project-directory]
28
+ codecane [project-directory]
27
29
  ```
28
30
 
29
- If no project directory is specified, Codebuff will use the current directory.
31
+ If no project directory is specified, Codecane will use the current directory.
30
32
 
31
- Once running, simply chat with Codebuff to say what coding task you want done.
33
+ Once running, simply chat with Codecane to say what coding task you want done.
32
34
 
33
35
  ## Features
34
36
 
35
37
  - Understands your whole codebase
36
38
  - Creates and edits multiple files based on your request
37
39
  - Can run your tests or type checker or linter; can install packages
38
- - It's powerful: ask Codebuff to keep working until it reaches a condition and it will.
40
+ - It's powerful: ask Codecane to keep working until it reaches a condition and it will.
39
41
 
40
- Our users regularly use Codebuff to implement new features, write unit tests, refactor code,write scripts, or give advice.
42
+ Our users regularly use Codecane to implement new features, write unit tests, refactor code, write scripts, or give advice.
41
43
 
42
44
  ## Knowledge Files
43
45
 
44
46
  To unlock the full benefits of modern LLMs, we recommend storing knowledge alongside your code. Add a `knowledge.md` file anywhere in your project to provide helpful context, guidance, and tips for the LLM as it performs tasks for you.
45
47
 
46
- Codebuff can fluently read and write files, so it will add knowledge as it goes. You don't need to write knowledge manually!
48
+ Codecane can fluently read and write files, so it will add knowledge as it goes. You don't need to write knowledge manually!
47
49
 
48
50
  Some have said every change should be paired with a unit test. In 2024, every change should come with a knowledge update!
49
51
 
@@ -52,18 +54,18 @@ Some have said every change should be paired with a unit test. In 2024, every ch
52
54
  1. Type '/help' or just '/' to see available commands.
53
55
  2. Create a `knowledge.md` file and collect specific points of advice. The assistant will use this knowledge to improve its responses.
54
56
  3. Type `undo` or `redo` to revert or reapply file changes from the conversation.
55
- 4. Press `Esc` or `Ctrl+C` while Codebuff is generating a response to stop it.
57
+ 4. Press `Esc` or `Ctrl+C` while Codecane is generating a response to stop it.
56
58
 
57
59
  ## Troubleshooting
58
60
 
59
61
  If you are getting permission errors during installation, try using sudo:
60
62
 
61
63
  ```
62
- sudo npm install -g codebuff
64
+ sudo npm install -g codecane@beta
63
65
  ```
64
66
 
65
67
  If you still have errors, it's a good idea to [reinstall Node](https://nodejs.org/en/download).
66
68
 
67
69
  ## Feedback
68
70
 
69
- We value your input! Please email your feedback to `founders@codebuff.com`. Thank you for using Codebuff!
71
+ We value your input! Please email your feedback to `founders@codebuff.com`. Thank you for using Codecane!
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 CONFIG = {
14
- homeDir: os.homedir(),
15
- configDir: path.join(os.homedir(), '.config', 'manicode'),
16
- binaryName: process.platform === 'win32' ? 'codebuff.exe' : 'codebuff',
17
- githubRepo: 'CodebuffAI/codebuff',
18
- userAgent: 'codebuff-cli',
19
- requestTimeout: 20000,
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.binaryPath = path.join(CONFIG.configDir, CONFIG.binaryName)
30
+ const CONFIG = createConfig(packageName)
23
31
 
24
- // Platform target mapping
25
32
  const PLATFORM_TARGETS = {
26
- 'linux-x64': 'codebuff-linux-x64.tar.gz',
27
- 'linux-arm64': 'codebuff-linux-arm64.tar.gz',
28
- 'darwin-x64': 'codebuff-darwin-x64.tar.gz',
29
- 'darwin-arm64': 'codebuff-darwin-arm64.tar.gz',
30
- 'win32-x64': 'codebuff-win32-x64.tar.gz',
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 (!isPrintMode && process.stderr.isTTY) {
42
+ if (process.stderr.isTTY) {
38
43
  process.stderr.write('\r\x1b[K')
39
44
  }
40
45
  },
41
46
  write: (text) => {
42
- if (!isPrintMode) {
43
- term.clearLine()
44
- process.stderr.write(text)
45
- }
47
+ term.clearLine()
48
+ process.stderr.write(text)
46
49
  },
47
50
  writeLine: (text) => {
48
- if (!isPrintMode) {
49
- term.clearLine()
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
- return new Promise((resolve, reject) => {
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
- }, 1000)
140
+ }, 4000)
150
141
  resolve('error')
151
- }, 1000)
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
- } catch (error) {
167
- resolve('error')
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 parts1 = v1.split('.').map(Number)
180
- const parts2 = v2.split('.').map(Number)
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(parts1.length, parts2.length); i++) {
183
- const p1 = parts1[i] || 0
184
- const p2 = parts2[i] || 0
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 (p1 < p2) return -1
187
- if (p1 > p2) return 1
186
+ if (n1 < n2) return -1
187
+ if (n1 > n2) return 1
188
188
  }
189
189
 
190
- return 0
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
- // Use proxy endpoint that handles version mapping
216
- const downloadUrl = process.env.NEXT_PUBLIC_CODEBUFF_APP_URL
217
- ? `${process.env.NEXT_PUBLIC_CODEBUFF_APP_URL}/api/releases/download/${version}/${fileName}`
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
- fs.unlinkSync(CONFIG.binaryPath)
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
- if (!isPrintMode) {
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
- if (isPrintMode) {
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
- if (isPrintMode) {
306
- console.error(
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
- if (isPrintMode) {
324
- console.error(
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, retry) {
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
- if (!isPrintMode) {
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
- await retry(isPrintMode)
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
- // Silently ignore update check errors
402
+ // Ignore update failures
380
403
  }
381
404
  }
382
405
 
383
- async function main(firstRun = false, printMode = false) {
384
- isPrintMode = printMode
406
+ async function main() {
385
407
  await ensureBinaryExists()
386
408
 
387
- let error = null
388
- try {
389
- // Start codebuff
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
- // Store reference to the exit listener so we can remove it during updates
395
- const exitListener = (code) => {
396
- process.exit(code || 0)
397
- }
413
+ const exitListener = (code) => {
414
+ process.exit(code || 0)
415
+ }
398
416
 
399
- child.on('exit', exitListener)
417
+ child.on('exit', exitListener)
400
418
 
401
- if (firstRun) {
402
- // Check for updates in background
403
- setTimeout(() => {
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
- // Setup commander
424
- const program = new Command()
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.512",
3
+ "version": "1.0.514",
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": {