codecane 1.0.402 → 1.0.404

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codecane",
3
- "version": "1.0.402",
3
+ "version": "1.0.404",
4
4
  "description": "AI coding agent",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -8,7 +8,6 @@
8
8
  },
9
9
  "files": [
10
10
  "scripts/codebuff-wrapper.js",
11
- "scripts/download-binary.js",
12
11
  "README.md"
13
12
  ],
14
13
  "os": [
@@ -24,7 +23,8 @@
24
23
  "node": ">=16"
25
24
  },
26
25
  "dependencies": {
27
- "tar": "^6.2.0"
26
+ "tar": "^6.2.0",
27
+ "adm-zip": "^0.5.10"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
@@ -4,44 +4,308 @@ const fs = require('fs')
4
4
  const path = require('path')
5
5
  const os = require('os')
6
6
  const { spawn, execSync } = require('child_process')
7
+ const https = require('https')
8
+ const zlib = require('zlib')
9
+ const tar = require('tar')
7
10
 
8
- const homeDir = os.homedir()
9
- const manicodeDir = path.join(homeDir, '.config', 'manicode')
10
- const binaryName = process.platform === 'win32' ? 'codebuff.exe' : 'codebuff'
11
- const binaryPath = path.join(manicodeDir, binaryName)
11
+ // Configuration
12
+ const CONFIG = {
13
+ homeDir: os.homedir(),
14
+ configDir: path.join(os.homedir(), '.config', 'manicode'),
15
+ binaryName: process.platform === 'win32' ? 'codebuff.exe' : 'codebuff',
16
+ githubRepo: 'CodebuffAI/codebuff-community',
17
+ userAgent: 'codebuff-cli',
18
+ requestTimeout: 10000,
19
+ updateCheckTimeout: 5000,
20
+ }
21
+
22
+ CONFIG.binaryPath = path.join(CONFIG.configDir, CONFIG.binaryName)
23
+
24
+ // Platform target mapping
25
+ 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.zip',
31
+ }
32
+
33
+ // Utility functions
34
+ function httpGet(url, options = {}) {
35
+ return new Promise((resolve, reject) => {
36
+ const parsedUrl = new URL(url)
37
+ const reqOptions = {
38
+ hostname: parsedUrl.hostname,
39
+ path: parsedUrl.pathname + parsedUrl.search,
40
+ headers: {
41
+ 'User-Agent': CONFIG.userAgent,
42
+ ...options.headers,
43
+ },
44
+ }
12
45
 
13
- // Check if binary exists
14
- if (!fs.existsSync(binaryPath)) {
15
- console.log('šŸ”„ Codebuff binary not found. Downloading...')
16
-
46
+ const req = https.get(reqOptions, (res) => {
47
+ if (res.statusCode === 302 || res.statusCode === 301) {
48
+ return httpGet(res.headers.location, options)
49
+ .then(resolve)
50
+ .catch(reject)
51
+ }
52
+ resolve(res)
53
+ })
54
+
55
+ req.on('error', reject)
56
+
57
+ const timeout = options.timeout || CONFIG.requestTimeout
58
+ req.setTimeout(timeout, () => {
59
+ req.destroy()
60
+ reject(new Error('Request timeout'))
61
+ })
62
+ })
63
+ }
64
+
65
+ async function getLatestVersion() {
17
66
  try {
18
- // Run the download script synchronously
19
- const downloadScript = path.join(__dirname, 'download-binary.js')
20
- execSync(`node "${downloadScript}"`, { stdio: 'inherit' })
67
+ const res = await httpGet(
68
+ `https://api.github.com/repos/${CONFIG.githubRepo}/releases/latest`
69
+ )
70
+
71
+ let data = ''
72
+ for await (const chunk of res) {
73
+ data += chunk
74
+ }
75
+
76
+ const release = JSON.parse(data)
77
+ return release.tag_name?.replace(/^v/, '') || null
21
78
  } catch (error) {
22
- console.error('āŒ Failed to download codebuff binary')
23
- console.error('Please try running: npm install -g codebuff')
24
- process.exit(1)
79
+ return null
25
80
  }
26
81
  }
27
82
 
28
- // Check if binary is executable (Unix only)
29
- if (process.platform !== 'win32') {
83
+ function getCurrentVersion() {
84
+ if (!fs.existsSync(CONFIG.binaryPath)) return null
85
+
30
86
  try {
31
- fs.accessSync(binaryPath, fs.constants.X_OK)
87
+ const result = execSync(`"${CONFIG.binaryPath}" --version`, {
88
+ encoding: 'utf-8',
89
+ stdio: 'pipe',
90
+ timeout: 1000,
91
+ })
92
+ return result.trim()
32
93
  } catch (error) {
33
- console.error(`āŒ Codebuff binary is not executable: ${binaryPath}`)
34
- console.error('Please try running: npm install -g codebuff')
35
- process.exit(1)
94
+ return null
36
95
  }
37
96
  }
38
97
 
39
- // Execute the binary with all arguments passed through
40
- const child = spawn(binaryPath, process.argv.slice(2), {
41
- stdio: 'inherit',
42
- cwd: process.cwd()
43
- })
98
+ function compareVersions(v1, v2) {
99
+ if (!v1 || !v2) return 0
100
+
101
+ const parts1 = v1.split('.').map(Number)
102
+ const parts2 = v2.split('.').map(Number)
103
+
104
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
105
+ const p1 = parts1[i] || 0
106
+ const p2 = parts2[i] || 0
107
+
108
+ if (p1 < p2) return -1
109
+ if (p1 > p2) return 1
110
+ }
111
+
112
+ return 0
113
+ }
114
+
115
+ function showProgress(downloaded, total) {
116
+ if (total > 0) {
117
+ const percentage = Math.round((downloaded / total) * 100)
118
+ process.stderr.write(`\r${percentage}%`)
119
+ } else {
120
+ const downloadedMB = (downloaded / 1024 / 1024).toFixed(1)
121
+ process.stderr.write(`\r${downloadedMB} MB`)
122
+ }
123
+ }
124
+
125
+ async function downloadBinary(version) {
126
+ const platformKey = `${process.platform}-${process.arch}`
127
+ const fileName = PLATFORM_TARGETS[platformKey]
128
+
129
+ if (!fileName) {
130
+ throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
131
+ }
132
+
133
+ const downloadUrl = `https://github.com/${CONFIG.githubRepo}/releases/download/v${version}/${fileName}`
134
+
135
+ // Ensure config directory exists
136
+ fs.mkdirSync(CONFIG.configDir, { recursive: true })
137
+
138
+ console.log(`Downloading codebuff v${version}...`)
139
+
140
+ const res = await httpGet(downloadUrl)
141
+
142
+ if (res.statusCode !== 200) {
143
+ throw new Error(`Download failed: HTTP ${res.statusCode}`)
144
+ }
145
+
146
+ const totalSize = parseInt(res.headers['content-length'] || '0', 10)
147
+ let downloadedSize = 0
148
+ let lastProgressTime = Date.now()
149
+
150
+ const chunks = []
151
+
152
+ for await (const chunk of res) {
153
+ chunks.push(chunk)
154
+ downloadedSize += chunk.length
155
+
156
+ const now = Date.now()
157
+ if (now - lastProgressTime >= 100 || downloadedSize === totalSize) {
158
+ lastProgressTime = now
159
+ showProgress(downloadedSize, totalSize)
160
+ }
161
+ }
162
+
163
+ process.stderr.write('\n')
164
+ console.log('Extracting...')
165
+
166
+ const buffer = Buffer.concat(chunks)
167
+
168
+ if (fileName.endsWith('.zip')) {
169
+ // Windows ZIP extraction
170
+ const AdmZip = require('adm-zip')
171
+ const zipPath = path.join(CONFIG.configDir, fileName)
172
+
173
+ fs.writeFileSync(zipPath, buffer)
174
+
175
+ const zip = new AdmZip(zipPath)
176
+ zip.extractAllTo(CONFIG.configDir, true)
177
+
178
+ fs.unlinkSync(zipPath)
179
+ } else {
180
+ // Unix tar.gz extraction
181
+ await new Promise((resolve, reject) => {
182
+ const gunzip = zlib.createGunzip()
183
+ const extract = tar.extract({ cwd: CONFIG.configDir })
184
+
185
+ gunzip.pipe(extract).on('finish', resolve).on('error', reject)
186
+
187
+ gunzip.end(buffer)
188
+ })
189
+ }
190
+
191
+ // Rename extracted binary to standard name
192
+ const extractedName = fileName.replace(/\.(tar\.gz|zip)$/, '')
193
+ const extractedPath = path.join(CONFIG.configDir, extractedName)
194
+
195
+ if (fs.existsSync(extractedPath)) {
196
+ if (process.platform !== 'win32') {
197
+ fs.chmodSync(extractedPath, 0o755)
198
+ }
199
+ fs.renameSync(extractedPath, CONFIG.binaryPath)
200
+ } else {
201
+ throw new Error(`Binary not found after extraction`)
202
+ }
203
+ }
204
+
205
+ async function ensureBinaryExists() {
206
+ if (!fs.existsSync(CONFIG.binaryPath)) {
207
+ const version = await getLatestVersion()
208
+ if (!version) {
209
+ console.error('āŒ Failed to determine latest version')
210
+ console.error('Please check your internet connection and try again')
211
+ process.exit(1)
212
+ }
213
+
214
+ try {
215
+ await downloadBinary(version)
216
+ } catch (error) {
217
+ console.error('āŒ Failed to download codebuff:', error.message)
218
+ console.error('Please try again later.')
219
+ process.exit(1)
220
+ }
221
+ }
222
+
223
+ // Verify binary is executable (Unix only)
224
+ if (process.platform !== 'win32') {
225
+ try {
226
+ fs.accessSync(CONFIG.binaryPath, fs.constants.X_OK)
227
+ } catch (error) {
228
+ console.error(`āŒ Binary is not executable: ${CONFIG.binaryPath}`)
229
+ console.error('Run: chmod +x', CONFIG.binaryPath)
230
+ process.exit(1)
231
+ }
232
+ }
233
+ }
234
+
235
+ async function checkForUpdates(runningProcess, exitListener) {
236
+ try {
237
+ const currentVersion = getCurrentVersion()
238
+ if (!currentVersion) return
239
+
240
+ const latestVersion = await getLatestVersion()
241
+ if (!latestVersion) return
242
+
243
+ console.log(`Current version: ${currentVersion}`)
244
+ console.log(`Latest version: ${latestVersion}`)
245
+
246
+ if (compareVersions(currentVersion, latestVersion) < 0) {
247
+ process.stdout.write(`Updating...`)
248
+
249
+ // Remove the specific exit listener to prevent it from interfering with the update
250
+ runningProcess.removeListener('exit', exitListener)
251
+
252
+ // Kill the running process
253
+ runningProcess.kill('SIGTERM')
254
+
255
+ // Wait for the process to actually exit
256
+ await new Promise((resolve) => {
257
+ runningProcess.on('exit', resolve)
258
+ // Fallback timeout in case the process doesn't exit gracefully
259
+ setTimeout(() => {
260
+ if (!runningProcess.killed) {
261
+ runningProcess.kill('SIGKILL')
262
+ }
263
+ resolve()
264
+ }, 5000)
265
+ })
266
+
267
+ await downloadBinary(latestVersion)
268
+
269
+ // Restart with new binary
270
+ const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
271
+ stdio: 'inherit',
272
+ cwd: process.cwd(),
273
+ })
274
+
275
+ newChild.on('exit', (code) => {
276
+ process.exit(code || 0)
277
+ })
278
+ }
279
+ } catch (error) {
280
+ // Silently ignore update check errors
281
+ }
282
+ }
283
+
284
+ async function main() {
285
+ // Ensure binary exists
286
+ await ensureBinaryExists()
287
+
288
+ // Start codebuff
289
+ const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
290
+ stdio: 'inherit',
291
+ cwd: process.cwd(),
292
+ })
293
+
294
+ // Store reference to the exit listener so we can remove it during updates
295
+ const exitListener = (code) => {
296
+ process.exit(code || 0)
297
+ }
298
+
299
+ child.on('exit', exitListener)
300
+
301
+ // Check for updates in background
302
+ setTimeout(() => {
303
+ checkForUpdates(child, exitListener)
304
+ }, 100)
305
+ }
44
306
 
45
- child.on('exit', (code) => {
46
- process.exit(code || 0)
307
+ // Run the main function
308
+ main().catch((error) => {
309
+ console.error('āŒ Unexpected error:', error.message)
310
+ process.exit(1)
47
311
  })
@@ -1,153 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const https = require('https')
4
- const fs = require('fs')
5
- const path = require('path')
6
- const os = require('os')
7
- const { platform, arch } = process
8
-
9
- // Get version from package.json
10
- const packageJsonPath = path.join(__dirname, '..', 'package.json')
11
- let version
12
- try {
13
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
14
- version = packageJson.version
15
- } catch (error) {
16
- console.error('āŒ Could not read package.json version')
17
- process.exit(1)
18
- }
19
-
20
- const targets = {
21
- 'linux-x64': 'codebuff-linux-x64.tar.gz',
22
- 'linux-arm64': 'codebuff-linux-arm64.tar.gz',
23
- 'darwin-x64': 'codebuff-darwin-x64.tar.gz',
24
- 'darwin-arm64': 'codebuff-darwin-arm64.tar.gz',
25
- 'win32-x64': 'codebuff-win32-x64.zip'
26
- }
27
-
28
- const key = `${platform}-${arch}`
29
- const file = targets[key]
30
-
31
- if (!file) {
32
- console.error(`āŒ Unsupported platform: ${platform} ${arch}`)
33
- console.error('Supported platforms:', Object.keys(targets).join(', '))
34
- process.exit(1)
35
- }
36
-
37
- const url = `https://github.com/CodebuffAI/codebuff-community/releases/download/v${version}/${file}`
38
- const homeDir = os.homedir()
39
- const manicodeDir = path.join(homeDir, '.config', 'manicode')
40
- const binaryName = platform === 'win32' ? 'codebuff.exe' : 'codebuff'
41
- const binaryPath = path.join(manicodeDir, binaryName)
42
-
43
- // Check if binary already exists
44
- if (fs.existsSync(binaryPath)) {
45
- console.log('āœ… Binary already exists')
46
- process.exit(0)
47
- }
48
-
49
- // Create .config/manicode directory
50
- fs.mkdirSync(manicodeDir, { recursive: true })
51
-
52
- console.log(`ā¬‡ļø Downloading ${file} from GitHub releases...`)
53
- console.log(`šŸ“ Installing to: ${manicodeDir}`)
54
-
55
- const request = https.get(url, (res) => {
56
- if (res.statusCode === 302 || res.statusCode === 301) {
57
- // Follow redirect
58
- return https.get(res.headers.location, handleResponse)
59
- }
60
- handleResponse(res)
61
- })
62
-
63
- request.on('error', (err) => {
64
- console.error(`āŒ Download failed: ${err.message}`)
65
- process.exit(1)
66
- })
67
-
68
- function handleResponse(res) {
69
- if (res.statusCode !== 200) {
70
- console.error(`āŒ Download failed: HTTP ${res.statusCode}`)
71
- console.error(`URL: ${url}`)
72
- process.exit(1)
73
- }
74
-
75
- const totalSize = parseInt(res.headers['content-length'] || '0', 10)
76
- let downloadedSize = 0
77
- let lastProgressTime = Date.now()
78
-
79
- // Show progress for downloads
80
- const showProgress = (downloaded, total) => {
81
- const now = Date.now()
82
- // Update progress every 100ms to avoid too frequent updates
83
- if (now - lastProgressTime < 100 && downloaded < total) return
84
- lastProgressTime = now
85
-
86
- if (total > 0) {
87
- const percentage = Math.round((downloaded / total) * 100)
88
- const downloadedMB = (downloaded / 1024 / 1024).toFixed(1)
89
- const totalMB = (total / 1024 / 1024).toFixed(1)
90
- process.stderr.write(`\ršŸ“„ Downloaded ${downloadedMB}MB / ${totalMB}MB (${percentage}%)`)
91
- } else {
92
- const downloadedMB = (downloaded / 1024 / 1024).toFixed(1)
93
- process.stderr.write(`\ršŸ“„ Downloaded ${downloadedMB}MB`)
94
- }
95
- }
96
-
97
- res.on('data', (chunk) => {
98
- downloadedSize += chunk.length
99
- showProgress(downloadedSize, totalSize)
100
- })
101
-
102
- if (file.endsWith('.zip')) {
103
- // Handle zip files (Windows)
104
- const zipPath = path.join(manicodeDir, file)
105
- const writeStream = fs.createWriteStream(zipPath)
106
-
107
- res.pipe(writeStream)
108
-
109
- writeStream.on('finish', () => {
110
- process.stderr.write('\n') // New line after progress
111
- console.log('šŸ“¦ Extracting...')
112
- // Extract zip file
113
- const { execSync } = require('child_process')
114
- try {
115
- execSync(`cd "${manicodeDir}" && unzip -o "${file}"`, { stdio: 'inherit' })
116
- fs.unlinkSync(zipPath) // Clean up zip file
117
- console.log('āœ… codebuff installed successfully!')
118
- } catch (error) {
119
- console.error('āŒ Failed to extract zip:', error.message)
120
- process.exit(1)
121
- }
122
- })
123
- } else {
124
- // Handle tar.gz files (Unix)
125
- const zlib = require('zlib')
126
- const tar = require('tar')
127
-
128
- res.pipe(zlib.createGunzip())
129
- .pipe(tar.extract({ cwd: manicodeDir }))
130
- .on('finish', () => {
131
- process.stderr.write('\n') // New line after progress
132
- // The extracted binary will have the platform/arch in the name
133
- const extractedBinaryName = file.replace('.tar.gz', '').replace('.zip', '')
134
- const finalBinaryName = platform === 'win32' ? 'codebuff.exe' : 'codebuff'
135
- const extractedBinaryPath = path.join(manicodeDir, extractedBinaryName)
136
- const finalBinaryPath = path.join(manicodeDir, finalBinaryName)
137
-
138
- if (fs.existsSync(extractedBinaryPath)) {
139
- fs.chmodSync(extractedBinaryPath, 0o755)
140
- // Rename to the standard name
141
- fs.renameSync(extractedBinaryPath, finalBinaryPath)
142
- console.log('āœ… codebuff installed successfully!')
143
- } else {
144
- console.error(`āŒ Binary not found at ${extractedBinaryPath}`)
145
- process.exit(1)
146
- }
147
- })
148
- .on('error', (err) => {
149
- console.error(`āŒ Extraction failed: ${err.message}`)
150
- process.exit(1)
151
- })
152
- }
153
- }