codecane 1.0.420-beta.26 → 1.0.420-beta.260

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 +1 -3
  2. package/index.js +81 -130
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -39,7 +39,7 @@ Once running, simply chat with Codecane to say what coding task you want done.
39
39
  - Can run your tests or type checker or linter; can install packages
40
40
  - It's powerful: ask Codecane to keep working until it reaches a condition and it will.
41
41
 
42
- Our users regularly use Codecane 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.
43
43
 
44
44
  ## Knowledge Files
45
45
 
@@ -69,5 +69,3 @@ If you still have errors, it's a good idea to [reinstall Node](https://nodejs.or
69
69
  ## Feedback
70
70
 
71
71
  We value your input! Please email your feedback to `founders@codebuff.com`. Thank you for using Codecane!
72
-
73
- <!-- Test comment for staging workflow -->
package/index.js CHANGED
@@ -1,37 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs')
4
- const path = require('path')
5
- const os = require('os')
6
3
  const { spawn } = require('child_process')
4
+ const fs = require('fs')
7
5
  const https = require('https')
6
+ const path = require('path')
8
7
  const zlib = require('zlib')
8
+
9
9
  const tar = require('tar')
10
10
 
11
- // Hardcoded package name for codecane
12
11
  const packageName = 'codecane'
13
12
 
14
13
  function createConfig(packageName) {
15
- const homeDir = os.homedir()
16
- const configDir = path.join(homeDir, '.config', 'manicode')
14
+ // Store binary in package directory instead of ~/.config/manicode
15
+ const packageDir = __dirname
16
+ const binDir = path.join(packageDir, 'bin')
17
17
  const binaryName =
18
18
  process.platform === 'win32' ? `${packageName}.exe` : packageName
19
19
 
20
20
  return {
21
- homeDir,
22
- configDir,
21
+ packageDir,
22
+ binDir,
23
23
  binaryName,
24
- binaryPath: path.join(configDir, binaryName),
25
- githubRepo: 'CodebuffAI/codebuff-community',
24
+ binaryPath: path.join(binDir, binaryName),
26
25
  userAgent: `${packageName}-cli`,
27
26
  requestTimeout: 20000,
28
- isPrerelease: true, // codecane always looks for prereleases
29
27
  }
30
28
  }
31
29
 
32
30
  const CONFIG = createConfig(packageName)
33
31
 
34
- // Platform target mapping
35
32
  const PLATFORM_TARGETS = {
36
33
  'linux-x64': `${packageName}-linux-x64.tar.gz`,
37
34
  'linux-arm64': `${packageName}-linux-arm64.tar.gz`,
@@ -40,7 +37,6 @@ const PLATFORM_TARGETS = {
40
37
  'win32-x64': `${packageName}-win32-x64.tar.gz`,
41
38
  }
42
39
 
43
- // Terminal utilities
44
40
  const term = {
45
41
  clearLine: () => {
46
42
  if (process.stderr.isTTY) {
@@ -57,7 +53,6 @@ const term = {
57
53
  },
58
54
  }
59
55
 
60
- // Utility functions
61
56
  function httpGet(url, options = {}) {
62
57
  return new Promise((resolve, reject) => {
63
58
  const parsedUrl = new URL(url)
@@ -70,13 +65,6 @@ function httpGet(url, options = {}) {
70
65
  },
71
66
  }
72
67
 
73
- // Add GitHub token if available
74
- const token = process.env.GITHUB_TOKEN
75
- if (token) {
76
- console.log('Using your GITHUB_TOKEN to download the latest version.')
77
- reqOptions.headers.Authorization = `Bearer ${token}`
78
- }
79
-
80
68
  const req = https.get(reqOptions, (res) => {
81
69
  if (res.statusCode === 302 || res.statusCode === 301) {
82
70
  return httpGet(new URL(res.headers.location, url).href, options)
@@ -99,43 +87,15 @@ function httpGet(url, options = {}) {
99
87
  async function getLatestVersion() {
100
88
  try {
101
89
  const res = await httpGet(
102
- `https://github.com/${CONFIG.githubRepo}/releases.atom`
90
+ `https://registry.npmjs.org/${packageName}/latest`,
103
91
  )
104
92
 
105
93
  if (res.statusCode !== 200) return null
106
94
 
107
95
  const body = await streamToString(res)
96
+ const packageData = JSON.parse(body)
108
97
 
109
- // Parse the Atom XML to extract releases
110
- const tagMatches = body.match(
111
- /<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/g
112
- )
113
-
114
- if (!tagMatches) return null
115
-
116
- // Extract all version tags
117
- const versions = tagMatches
118
- .map((match) => {
119
- const tagMatch = match.match(
120
- /<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/
121
- )
122
- return tagMatch ? tagMatch[1].replace(/^v/, '') : null
123
- })
124
- .filter(Boolean)
125
-
126
- if (versions.length === 0) return null
127
-
128
- // Filter versions based on whether we want prereleases or stable releases
129
- const filteredVersions = versions.filter((version) => {
130
- const isPrerelease = version.includes('-')
131
- return CONFIG.isPrerelease === isPrerelease
132
- })
133
-
134
- if (filteredVersions.length === 0) return null
135
-
136
- // Sort and return the latest version
137
- filteredVersions.sort(compareVersions)
138
- return filteredVersions[filteredVersions.length - 1]
98
+ return packageData.version || null
139
99
  } catch (error) {
140
100
  return null
141
101
  }
@@ -154,21 +114,20 @@ function getCurrentVersion() {
154
114
  if (!fs.existsSync(CONFIG.binaryPath)) return null
155
115
 
156
116
  try {
157
- return new Promise((resolve, reject) => {
117
+ return new Promise((resolve) => {
158
118
  const child = spawn(CONFIG.binaryPath, ['--version'], {
159
- cwd: os.homedir(),
119
+ cwd: CONFIG.packageDir,
160
120
  stdio: 'pipe',
161
121
  })
162
122
 
163
123
  let output = ''
164
- let errorOutput = ''
165
124
 
166
125
  child.stdout.on('data', (data) => {
167
126
  output += data.toString()
168
127
  })
169
128
 
170
- child.stderr.on('data', (data) => {
171
- errorOutput += data.toString()
129
+ child.stderr.on('data', () => {
130
+ // Ignore stderr output
172
131
  })
173
132
 
174
133
  const timeout = setTimeout(() => {
@@ -177,9 +136,9 @@ function getCurrentVersion() {
177
136
  if (!child.killed) {
178
137
  child.kill('SIGKILL')
179
138
  }
180
- }, 1000)
139
+ }, 4000)
181
140
  resolve('error')
182
- }, 1000)
141
+ }, 4000)
183
142
 
184
143
  child.on('exit', (code) => {
185
144
  clearTimeout(timeout)
@@ -213,7 +172,6 @@ function compareVersions(v1, v2) {
213
172
  const p1 = parseVersion(v1)
214
173
  const p2 = parseVersion(v2)
215
174
 
216
- // Compare main version parts
217
175
  for (let i = 0; i < Math.max(p1.main.length, p2.main.length); i++) {
218
176
  const n1 = p1.main[i] || 0
219
177
  const n2 = p2.main[i] || 0
@@ -222,15 +180,13 @@ function compareVersions(v1, v2) {
222
180
  if (n1 > n2) return 1
223
181
  }
224
182
 
225
- // If main versions are equal, compare prerelease parts
226
183
  if (p1.prerelease.length === 0 && p2.prerelease.length === 0) {
227
- return 0 // No prerelease, versions are equal
184
+ return 0
228
185
  } else if (p1.prerelease.length === 0) {
229
- return 1 // v1 is a release, v2 is prerelease, so v1 > v2
186
+ return 1
230
187
  } else if (p2.prerelease.length === 0) {
231
- return -1 // v2 is a release, v1 is prerelease, so v1 < v2
188
+ return -1
232
189
  } else {
233
- // Both have prerelease parts, compare them
234
190
  for (
235
191
  let i = 0;
236
192
  i < Math.max(p1.prerelease.length, p2.prerelease.length);
@@ -239,7 +195,6 @@ function compareVersions(v1, v2) {
239
195
  const pr1 = p1.prerelease[i] || ''
240
196
  const pr2 = p2.prerelease[i] || ''
241
197
 
242
- // Handle numeric vs. string parts
243
198
  const isNum1 = !isNaN(parseInt(pr1))
244
199
  const isNum2 = !isNaN(parseInt(pr2))
245
200
 
@@ -249,16 +204,16 @@ function compareVersions(v1, v2) {
249
204
  if (num1 < num2) return -1
250
205
  if (num1 > num2) return 1
251
206
  } else if (isNum1 && !isNum2) {
252
- return 1 // Numeric prerelease is generally higher than alpha/beta
207
+ return 1
253
208
  } else if (!isNum1 && isNum2) {
254
209
  return -1
255
- } else {
256
- // Lexicographical comparison for string parts
257
- if (pr1 < pr2) return -1
258
- if (pr1 > pr2) return 1
210
+ } else if (pr1 < pr2) {
211
+ return -1
212
+ } else if (pr1 > pr2) {
213
+ return 1
259
214
  }
260
215
  }
261
- return 0 // Prerelease parts are equal
216
+ return 0
262
217
  }
263
218
  }
264
219
 
@@ -284,13 +239,29 @@ async function downloadBinary(version) {
284
239
  throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
285
240
  }
286
241
 
287
- const downloadUrl = `https://github.com/${CONFIG.githubRepo}/releases/download/v${version}/${fileName}`
242
+ const downloadUrl = `${
243
+ process.env.NEXT_PUBLIC_CODEBUFF_APP_URL || 'https://codebuff.com'
244
+ }/api/releases/download/${version}/${fileName}`
288
245
 
289
- // Ensure config directory exists
290
- fs.mkdirSync(CONFIG.configDir, { recursive: true })
246
+ // Create bin directory in package directory
247
+ fs.mkdirSync(CONFIG.binDir, { recursive: true })
291
248
 
292
249
  if (fs.existsSync(CONFIG.binaryPath)) {
293
- fs.unlinkSync(CONFIG.binaryPath)
250
+ try {
251
+ fs.unlinkSync(CONFIG.binaryPath)
252
+ } catch (err) {
253
+ const backupPath = CONFIG.binaryPath + `.old.${Date.now()}`
254
+
255
+ try {
256
+ fs.renameSync(CONFIG.binaryPath, backupPath)
257
+ } catch (renameErr) {
258
+ throw new Error(
259
+ `Failed to replace existing binary. ` +
260
+ `unlink error: ${err.code || err.message}, ` +
261
+ `rename error: ${renameErr.code || renameErr.message}`,
262
+ )
263
+ }
264
+ }
294
265
  }
295
266
 
296
267
  term.write('Downloading...')
@@ -314,8 +285,8 @@ async function downloadBinary(version) {
314
285
  const pct = Math.round((downloadedSize / totalSize) * 100)
315
286
  term.write(
316
287
  `Downloading... ${createProgressBar(pct)} ${pct}% of ${formatBytes(
317
- totalSize
318
- )}`
288
+ totalSize,
289
+ )}`,
319
290
  )
320
291
  } else {
321
292
  term.write(`Downloading... ${formatBytes(downloadedSize)}`)
@@ -326,15 +297,14 @@ async function downloadBinary(version) {
326
297
  await new Promise((resolve, reject) => {
327
298
  res
328
299
  .pipe(zlib.createGunzip())
329
- .pipe(tar.x({ cwd: CONFIG.configDir }))
300
+ .pipe(tar.x({ cwd: CONFIG.binDir }))
330
301
  .on('finish', resolve)
331
302
  .on('error', reject)
332
303
  })
333
304
 
334
305
  try {
335
- // Find the extracted binary - it should be named "codebuff" or "codebuff.exe"
336
- const files = fs.readdirSync(CONFIG.configDir)
337
- const extractedPath = path.join(CONFIG.configDir, CONFIG.binaryName)
306
+ const files = fs.readdirSync(CONFIG.binDir)
307
+ const extractedPath = path.join(CONFIG.binDir, CONFIG.binaryName)
338
308
 
339
309
  if (fs.existsSync(extractedPath)) {
340
310
  if (process.platform !== 'win32') {
@@ -342,7 +312,7 @@ async function downloadBinary(version) {
342
312
  }
343
313
  } else {
344
314
  throw new Error(
345
- `Binary not found after extraction. Expected: ${extractedPath}, Available files: ${files.join(', ')}`
315
+ `Binary not found after extraction. Expected: ${extractedPath}, Available files: ${files.join(', ')}`,
346
316
  )
347
317
  }
348
318
  } catch (error) {
@@ -356,22 +326,25 @@ async function downloadBinary(version) {
356
326
  }
357
327
 
358
328
  async function ensureBinaryExists() {
359
- if (!fs.existsSync(CONFIG.binaryPath)) {
360
- const version = await getLatestVersion()
361
- if (!version) {
362
- console.error('❌ Failed to determine latest version')
363
- console.error('Please check your internet connection and try again')
364
- process.exit(1)
365
- }
329
+ const currentVersion = await getCurrentVersion()
330
+ if (currentVersion !== null && currentVersion !== 'error') {
331
+ return
332
+ }
366
333
 
367
- try {
368
- await downloadBinary(version)
369
- } catch (error) {
370
- term.clearLine()
371
- console.error('❌ Failed to download codebuff:', error.message)
372
- console.error('Please check your internet connection and try again')
373
- process.exit(1)
374
- }
334
+ const version = await getLatestVersion()
335
+ if (!version) {
336
+ console.error('❌ Failed to determine latest version')
337
+ console.error('Please check your internet connection and try again')
338
+ process.exit(1)
339
+ }
340
+
341
+ try {
342
+ await downloadBinary(version)
343
+ } catch (error) {
344
+ term.clearLine()
345
+ console.error('❌ Failed to download codecane:', error.message)
346
+ console.error('Please check your internet connection and try again')
347
+ process.exit(1)
375
348
  }
376
349
  }
377
350
 
@@ -384,22 +357,16 @@ async function checkForUpdates(runningProcess, exitListener) {
384
357
  if (!latestVersion) return
385
358
 
386
359
  if (
387
- // Download new version if current binary errors.
388
360
  currentVersion === 'error' ||
389
361
  compareVersions(currentVersion, latestVersion) < 0
390
362
  ) {
391
363
  term.clearLine()
392
364
 
393
- // Remove the specific exit listener to prevent it from interfering with the update
394
365
  runningProcess.removeListener('exit', exitListener)
395
-
396
- // Kill the running process
397
366
  runningProcess.kill('SIGTERM')
398
367
 
399
- // Wait for the process to actually exit
400
368
  await new Promise((resolve) => {
401
369
  runningProcess.on('exit', resolve)
402
- // Fallback timeout in case the process doesn't exit gracefully
403
370
  setTimeout(() => {
404
371
  if (!runningProcess.killed) {
405
372
  runningProcess.kill('SIGKILL')
@@ -412,64 +379,48 @@ async function checkForUpdates(runningProcess, exitListener) {
412
379
 
413
380
  await downloadBinary(latestVersion)
414
381
 
415
- // Restart with new binary - this replaces the current process
416
- const newChild = spawn(
417
- CONFIG.binaryPath,
418
- [packageName, ...process.argv.slice(2)],
419
- {
420
- stdio: 'inherit',
421
- detached: false,
422
- }
423
- )
382
+ const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
383
+ stdio: 'inherit',
384
+ detached: false,
385
+ })
424
386
 
425
- // Set up exit handler for the new process
426
387
  newChild.on('exit', (code) => {
427
388
  process.exit(code || 0)
428
389
  })
429
390
 
430
- // Don't return - keep this function running to maintain the wrapper
431
- return new Promise(() => {}) // Never resolves, keeps wrapper alive
391
+ return new Promise(() => {})
432
392
  }
433
393
  } catch (error) {
434
- // Silently ignore update check errors
394
+ // Ignore update failures
435
395
  }
436
396
  }
437
397
 
438
398
  async function main() {
439
- // Bold, bright warning for staging environment
440
399
  console.log('\x1b[1m\x1b[91m' + '='.repeat(60) + '\x1b[0m')
441
400
  console.log('\x1b[1m\x1b[93m❄️ CODECANE STAGING ENVIRONMENT ❄️\x1b[0m')
442
401
  console.log(
443
- '\x1b[1m\x1b[91mFOR TESTING PURPOSES ONLY - NOT FOR PRODUCTION USE\x1b[0m'
402
+ '\x1b[1m\x1b[91mFOR TESTING PURPOSES ONLY - NOT FOR PRODUCTION USE\x1b[0m',
444
403
  )
445
404
  console.log('\x1b[1m\x1b[91m' + '='.repeat(60) + '\x1b[0m')
446
405
  console.log('')
447
406
 
448
407
  await ensureBinaryExists()
449
408
 
450
- // Start the binary with codecane argument
451
- const child = spawn(
452
- CONFIG.binaryPath,
453
- [packageName, ...process.argv.slice(2)],
454
- {
455
- stdio: 'inherit',
456
- }
457
- )
409
+ const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
410
+ stdio: 'inherit',
411
+ })
458
412
 
459
- // Store reference to the exit listener so we can remove it during updates
460
413
  const exitListener = (code) => {
461
414
  process.exit(code || 0)
462
415
  }
463
416
 
464
417
  child.on('exit', exitListener)
465
418
 
466
- // Check for updates in background
467
419
  setTimeout(() => {
468
420
  checkForUpdates(child, exitListener)
469
421
  }, 100)
470
422
  }
471
423
 
472
- // Run the main function
473
424
  main().catch((error) => {
474
425
  console.error('❌ Unexpected error:', error.message)
475
426
  process.exit(1)
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "codecane",
3
- "version": "1.0.420-beta.26",
4
- "description": "AI coding agent (staging)",
3
+ "version": "1.0.420-beta.260",
4
+ "description": "AI coding agent CLI (staging)",
5
5
  "license": "MIT",
6
6
  "bin": {
7
7
  "codecane": "index.js"
8
8
  },
9
9
  "scripts": {
10
- "preuninstall": "node -e \"const fs = require('fs'); const path = require('path'); const os = require('os'); const binaryPath = path.join(os.homedir(), '.config', 'manicode', process.platform === 'win32' ? 'codecane.exe' : 'codecane'); try { fs.unlinkSync(binaryPath) } catch (e) { /* ignore if file doesn't exist */ }\""
10
+ "postinstall": "node -e \"const fs = require('fs'); const path = require('path'); const os = require('os'); const binaryPath = path.join(os.homedir(), '.config', 'manicode', process.platform === 'win32' ? 'codecane.exe' : 'codecane'); try { fs.unlinkSync(binaryPath) } catch (e) { /* ignore if file doesn't exist */ }\""
11
11
  },
12
12
  "files": [
13
13
  "index.js",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "repository": {
32
32
  "type": "git",
33
- "url": "https://github.com/CodebuffAI/codebuff-community.git"
33
+ "url": "https://github.com/CodebuffAI/codebuff.git"
34
34
  },
35
35
  "homepage": "https://codebuff.com",
36
36
  "publishConfig": {