codecane 1.0.412 → 1.0.420-beta.1
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/README.md +20 -16
- package/index.js +215 -85
- package/package.json +5 -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
|
-
|
|
3
|
+
**⚠️ This is a staging/beta release for testing purposes.**
|
|
4
4
|
|
|
5
|
-
|
|
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:
|
|
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
|
|
15
|
+
To install Codecane (staging), run:
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
|
-
npm install -g
|
|
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
|
|
25
|
+
After installation, you can start Codecane by running:
|
|
24
26
|
|
|
25
27
|
```bash
|
|
26
|
-
|
|
28
|
+
codecane [project-directory]
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
If no project directory is specified,
|
|
31
|
+
If no project directory is specified, Codecane will use the current directory.
|
|
30
32
|
|
|
31
|
-
Once running, simply chat with
|
|
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
|
|
40
|
+
- It's powerful: ask Codecane to keep working until it reaches a condition and it will.
|
|
39
41
|
|
|
40
|
-
Our users regularly use
|
|
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
|
-
|
|
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,20 @@ 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
|
|
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
|
|
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
|
|
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
|
@@ -3,31 +3,40 @@
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const os = require('os')
|
|
6
|
-
const { spawn
|
|
6
|
+
const { spawn } = require('child_process')
|
|
7
7
|
const https = require('https')
|
|
8
8
|
const zlib = require('zlib')
|
|
9
9
|
const tar = require('tar')
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
// Hardcoded package name for codecane
|
|
12
|
+
const packageName = 'codecane'
|
|
13
|
+
|
|
14
|
+
function createConfig(packageName) {
|
|
15
|
+
const homeDir = os.homedir()
|
|
16
|
+
const configDir = path.join(homeDir, '.config', 'manicode')
|
|
17
|
+
const binaryName = process.platform === 'win32' ? `${packageName}.exe` : packageName
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
homeDir,
|
|
21
|
+
configDir,
|
|
22
|
+
binaryName,
|
|
23
|
+
binaryPath: path.join(configDir, binaryName),
|
|
24
|
+
githubRepo: 'CodebuffAI/codebuff-community',
|
|
25
|
+
userAgent: `${packageName}-cli`,
|
|
26
|
+
requestTimeout: 20000,
|
|
27
|
+
isPrerelease: true, // codecane always looks for prereleases
|
|
28
|
+
}
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
CONFIG
|
|
31
|
+
const CONFIG = createConfig(packageName)
|
|
23
32
|
|
|
24
33
|
// Platform target mapping
|
|
25
34
|
const PLATFORM_TARGETS = {
|
|
26
|
-
'linux-x64':
|
|
27
|
-
'linux-arm64':
|
|
28
|
-
'darwin-x64':
|
|
29
|
-
'darwin-arm64':
|
|
30
|
-
'win32-x64':
|
|
35
|
+
'linux-x64': `${packageName}-linux-x64.tar.gz`,
|
|
36
|
+
'linux-arm64': `${packageName}-linux-arm64.tar.gz`,
|
|
37
|
+
'darwin-x64': `${packageName}-darwin-x64.tar.gz`,
|
|
38
|
+
'darwin-arm64': `${packageName}-darwin-arm64.tar.gz`,
|
|
39
|
+
'win32-x64': `${packageName}-win32-x64.tar.gz`,
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
// Terminal utilities
|
|
@@ -60,9 +69,16 @@ function httpGet(url, options = {}) {
|
|
|
60
69
|
},
|
|
61
70
|
}
|
|
62
71
|
|
|
72
|
+
// Add GitHub token if available
|
|
73
|
+
const token = process.env.GITHUB_TOKEN
|
|
74
|
+
if (token) {
|
|
75
|
+
console.log('Using your GITHUB_TOKEN to download the latest version.')
|
|
76
|
+
reqOptions.headers.Authorization = `Bearer ${token}`
|
|
77
|
+
}
|
|
78
|
+
|
|
63
79
|
const req = https.get(reqOptions, (res) => {
|
|
64
80
|
if (res.statusCode === 302 || res.statusCode === 301) {
|
|
65
|
-
return httpGet(res.headers.location, options)
|
|
81
|
+
return httpGet(new URL(res.headers.location, url).href, options)
|
|
66
82
|
.then(resolve)
|
|
67
83
|
.catch(reject)
|
|
68
84
|
}
|
|
@@ -74,7 +90,7 @@ function httpGet(url, options = {}) {
|
|
|
74
90
|
const timeout = options.timeout || CONFIG.requestTimeout
|
|
75
91
|
req.setTimeout(timeout, () => {
|
|
76
92
|
req.destroy()
|
|
77
|
-
reject(new Error('Request timeout'))
|
|
93
|
+
reject(new Error('Request timeout.'))
|
|
78
94
|
})
|
|
79
95
|
})
|
|
80
96
|
}
|
|
@@ -82,51 +98,167 @@ function httpGet(url, options = {}) {
|
|
|
82
98
|
async function getLatestVersion() {
|
|
83
99
|
try {
|
|
84
100
|
const res = await httpGet(
|
|
85
|
-
`https://
|
|
101
|
+
`https://github.com/${CONFIG.githubRepo}/releases.atom`
|
|
86
102
|
)
|
|
87
103
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
if (res.statusCode !== 200) return null
|
|
105
|
+
|
|
106
|
+
const body = await streamToString(res)
|
|
107
|
+
|
|
108
|
+
// Parse the Atom XML to extract releases
|
|
109
|
+
const tagMatches = body.match(
|
|
110
|
+
/<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/g
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if (!tagMatches) return null
|
|
92
114
|
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
// Extract all version tags
|
|
116
|
+
const versions = tagMatches
|
|
117
|
+
.map((match) => {
|
|
118
|
+
const tagMatch = match.match(
|
|
119
|
+
/<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/
|
|
120
|
+
)
|
|
121
|
+
return tagMatch ? tagMatch[1].replace(/^v/, '') : null
|
|
122
|
+
})
|
|
123
|
+
.filter(Boolean)
|
|
124
|
+
|
|
125
|
+
if (versions.length === 0) return null
|
|
126
|
+
|
|
127
|
+
// Filter versions based on whether we want prereleases or stable releases
|
|
128
|
+
const filteredVersions = versions.filter((version) => {
|
|
129
|
+
const isPrerelease = version.includes('-')
|
|
130
|
+
return CONFIG.isPrerelease === isPrerelease
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if (filteredVersions.length === 0) return null
|
|
134
|
+
|
|
135
|
+
// Sort and return the latest version
|
|
136
|
+
filteredVersions.sort(compareVersions)
|
|
137
|
+
return filteredVersions[filteredVersions.length - 1]
|
|
95
138
|
} catch (error) {
|
|
96
139
|
return null
|
|
97
140
|
}
|
|
98
141
|
}
|
|
99
142
|
|
|
143
|
+
function streamToString(stream) {
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
let data = ''
|
|
146
|
+
stream.on('data', (chunk) => (data += chunk))
|
|
147
|
+
stream.on('end', () => resolve(data))
|
|
148
|
+
stream.on('error', reject)
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
|
|
100
152
|
function getCurrentVersion() {
|
|
101
153
|
if (!fs.existsSync(CONFIG.binaryPath)) return null
|
|
102
154
|
|
|
103
155
|
try {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
const child = spawn(CONFIG.binaryPath, ['--version'], {
|
|
158
|
+
cwd: os.homedir(),
|
|
159
|
+
stdio: 'pipe',
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
let output = ''
|
|
163
|
+
let errorOutput = ''
|
|
164
|
+
|
|
165
|
+
child.stdout.on('data', (data) => {
|
|
166
|
+
output += data.toString()
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
child.stderr.on('data', (data) => {
|
|
170
|
+
errorOutput += data.toString()
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
const timeout = setTimeout(() => {
|
|
174
|
+
child.kill('SIGTERM')
|
|
175
|
+
setTimeout(() => {
|
|
176
|
+
if (!child.killed) {
|
|
177
|
+
child.kill('SIGKILL')
|
|
178
|
+
}
|
|
179
|
+
}, 1000)
|
|
180
|
+
resolve('error')
|
|
181
|
+
}, 1000)
|
|
182
|
+
|
|
183
|
+
child.on('exit', (code) => {
|
|
184
|
+
clearTimeout(timeout)
|
|
185
|
+
if (code === 0) {
|
|
186
|
+
resolve(output.trim())
|
|
187
|
+
} else {
|
|
188
|
+
resolve('error')
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
child.on('error', () => {
|
|
193
|
+
clearTimeout(timeout)
|
|
194
|
+
resolve('error')
|
|
195
|
+
})
|
|
108
196
|
})
|
|
109
|
-
return result.trim()
|
|
110
197
|
} catch (error) {
|
|
111
|
-
return
|
|
198
|
+
return 'error'
|
|
112
199
|
}
|
|
113
200
|
}
|
|
114
201
|
|
|
115
202
|
function compareVersions(v1, v2) {
|
|
116
203
|
if (!v1 || !v2) return 0
|
|
117
204
|
|
|
118
|
-
const
|
|
119
|
-
|
|
205
|
+
const parseVersion = (version) => {
|
|
206
|
+
const parts = version.split('-')
|
|
207
|
+
const mainParts = parts[0].split('.').map(Number)
|
|
208
|
+
const prereleaseParts = parts[1] ? parts[1].split('.') : []
|
|
209
|
+
return { main: mainParts, prerelease: prereleaseParts }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const p1 = parseVersion(v1)
|
|
213
|
+
const p2 = parseVersion(v2)
|
|
120
214
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
215
|
+
// Compare main version parts
|
|
216
|
+
for (let i = 0; i < Math.max(p1.main.length, p2.main.length); i++) {
|
|
217
|
+
const n1 = p1.main[i] || 0
|
|
218
|
+
const n2 = p2.main[i] || 0
|
|
124
219
|
|
|
125
|
-
if (
|
|
126
|
-
if (
|
|
220
|
+
if (n1 < n2) return -1
|
|
221
|
+
if (n1 > n2) return 1
|
|
127
222
|
}
|
|
128
223
|
|
|
129
|
-
|
|
224
|
+
// If main versions are equal, compare prerelease parts
|
|
225
|
+
if (p1.prerelease.length === 0 && p2.prerelease.length === 0) {
|
|
226
|
+
return 0 // No prerelease, versions are equal
|
|
227
|
+
} else if (p1.prerelease.length === 0) {
|
|
228
|
+
return 1 // v1 is a release, v2 is prerelease, so v1 > v2
|
|
229
|
+
} else if (p2.prerelease.length === 0) {
|
|
230
|
+
return -1 // v2 is a release, v1 is prerelease, so v1 < v2
|
|
231
|
+
} else {
|
|
232
|
+
// Both have prerelease parts, compare them
|
|
233
|
+
for (
|
|
234
|
+
let i = 0;
|
|
235
|
+
i < Math.max(p1.prerelease.length, p2.prerelease.length);
|
|
236
|
+
i++
|
|
237
|
+
) {
|
|
238
|
+
const pr1 = p1.prerelease[i] || ''
|
|
239
|
+
const pr2 = p2.prerelease[i] || ''
|
|
240
|
+
|
|
241
|
+
// Handle numeric vs. string parts
|
|
242
|
+
const isNum1 = !isNaN(parseInt(pr1))
|
|
243
|
+
const isNum2 = !isNaN(parseInt(pr2))
|
|
244
|
+
|
|
245
|
+
if (isNum1 && isNum2) {
|
|
246
|
+
const num1 = parseInt(pr1)
|
|
247
|
+
const num2 = parseInt(pr2)
|
|
248
|
+
if (num1 < num2) return -1
|
|
249
|
+
if (num1 > num2) return 1
|
|
250
|
+
} else if (isNum1 && !isNum2) {
|
|
251
|
+
return 1 // Numeric prerelease is generally higher than alpha/beta
|
|
252
|
+
} else if (!isNum1 && isNum2) {
|
|
253
|
+
return -1
|
|
254
|
+
} else {
|
|
255
|
+
// Lexicographical comparison for string parts
|
|
256
|
+
if (pr1 < pr2) return -1
|
|
257
|
+
if (pr1 > pr2) return 1
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return 0 // Prerelease parts are equal
|
|
261
|
+
}
|
|
130
262
|
}
|
|
131
263
|
|
|
132
264
|
function formatBytes(bytes) {
|
|
@@ -137,10 +269,6 @@ function formatBytes(bytes) {
|
|
|
137
269
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
|
|
138
270
|
}
|
|
139
271
|
|
|
140
|
-
function formatSpeed(bytesPerSecond) {
|
|
141
|
-
return formatBytes(bytesPerSecond) + '/s'
|
|
142
|
-
}
|
|
143
|
-
|
|
144
272
|
function createProgressBar(percentage, width = 30) {
|
|
145
273
|
const filled = Math.round((width * percentage) / 100)
|
|
146
274
|
const empty = width - filled
|
|
@@ -160,7 +288,11 @@ async function downloadBinary(version) {
|
|
|
160
288
|
// Ensure config directory exists
|
|
161
289
|
fs.mkdirSync(CONFIG.configDir, { recursive: true })
|
|
162
290
|
|
|
163
|
-
|
|
291
|
+
if (fs.existsSync(CONFIG.binaryPath)) {
|
|
292
|
+
fs.unlinkSync(CONFIG.binaryPath)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
term.write('Downloading...')
|
|
164
296
|
|
|
165
297
|
const res = await httpGet(downloadUrl)
|
|
166
298
|
|
|
@@ -172,46 +304,33 @@ async function downloadBinary(version) {
|
|
|
172
304
|
let downloadedSize = 0
|
|
173
305
|
let lastProgressTime = Date.now()
|
|
174
306
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
for await (const chunk of res) {
|
|
178
|
-
chunks.push(chunk)
|
|
307
|
+
res.on('data', (chunk) => {
|
|
179
308
|
downloadedSize += chunk.length
|
|
180
|
-
|
|
181
309
|
const now = Date.now()
|
|
182
310
|
if (now - lastProgressTime >= 100 || downloadedSize === totalSize) {
|
|
183
311
|
lastProgressTime = now
|
|
184
|
-
|
|
185
312
|
if (totalSize > 0) {
|
|
186
|
-
const
|
|
187
|
-
const progressBar = createProgressBar(percentage)
|
|
188
|
-
|
|
313
|
+
const pct = Math.round((downloadedSize / totalSize) * 100)
|
|
189
314
|
term.write(
|
|
190
|
-
`Downloading... ${
|
|
315
|
+
`Downloading... ${createProgressBar(pct)} ${pct}% of ${formatBytes(
|
|
316
|
+
totalSize
|
|
317
|
+
)}`
|
|
191
318
|
)
|
|
192
319
|
} else {
|
|
193
320
|
term.write(`Downloading... ${formatBytes(downloadedSize)}`)
|
|
194
321
|
}
|
|
195
322
|
}
|
|
196
|
-
}
|
|
197
|
-
term.clearLine()
|
|
198
|
-
console.log('Download complete!')
|
|
199
|
-
|
|
200
|
-
term.write('Extracting...')
|
|
323
|
+
})
|
|
201
324
|
|
|
202
|
-
|
|
325
|
+
await new Promise((resolve, reject) => {
|
|
326
|
+
res
|
|
327
|
+
.pipe(zlib.createGunzip())
|
|
328
|
+
.pipe(tar.x({ cwd: CONFIG.configDir }))
|
|
329
|
+
.on('finish', resolve)
|
|
330
|
+
.on('error', reject)
|
|
331
|
+
})
|
|
203
332
|
|
|
204
333
|
try {
|
|
205
|
-
// Unix tar.gz extraction for all platforms
|
|
206
|
-
await new Promise((resolve, reject) => {
|
|
207
|
-
const gunzip = zlib.createGunzip()
|
|
208
|
-
const extract = tar.extract({ cwd: CONFIG.configDir })
|
|
209
|
-
|
|
210
|
-
gunzip.pipe(extract).on('finish', resolve).on('error', reject)
|
|
211
|
-
|
|
212
|
-
gunzip.end(buffer)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
334
|
// Find the extracted binary - it should be named "codebuff" or "codebuff.exe"
|
|
216
335
|
const files = fs.readdirSync(CONFIG.configDir)
|
|
217
336
|
const extractedPath = path.join(CONFIG.configDir, CONFIG.binaryName)
|
|
@@ -225,13 +344,14 @@ async function downloadBinary(version) {
|
|
|
225
344
|
`Binary not found after extraction. Expected: ${extractedPath}, Available files: ${files.join(', ')}`
|
|
226
345
|
)
|
|
227
346
|
}
|
|
228
|
-
|
|
229
|
-
term.write('Starting Codebuff...')
|
|
230
347
|
} catch (error) {
|
|
231
348
|
term.clearLine()
|
|
232
349
|
console.error(`Extraction failed: ${error.message}`)
|
|
233
350
|
process.exit(1)
|
|
234
351
|
}
|
|
352
|
+
|
|
353
|
+
term.clearLine()
|
|
354
|
+
console.log('Download complete! Starting Codecane...')
|
|
235
355
|
}
|
|
236
356
|
|
|
237
357
|
async function ensureBinaryExists() {
|
|
@@ -248,7 +368,7 @@ async function ensureBinaryExists() {
|
|
|
248
368
|
} catch (error) {
|
|
249
369
|
term.clearLine()
|
|
250
370
|
console.error('❌ Failed to download codebuff:', error.message)
|
|
251
|
-
console.error('Please try again
|
|
371
|
+
console.error('Please check your internet connection and try again')
|
|
252
372
|
process.exit(1)
|
|
253
373
|
}
|
|
254
374
|
}
|
|
@@ -256,13 +376,17 @@ async function ensureBinaryExists() {
|
|
|
256
376
|
|
|
257
377
|
async function checkForUpdates(runningProcess, exitListener) {
|
|
258
378
|
try {
|
|
259
|
-
const currentVersion = getCurrentVersion()
|
|
379
|
+
const currentVersion = await getCurrentVersion()
|
|
260
380
|
if (!currentVersion) return
|
|
261
381
|
|
|
262
382
|
const latestVersion = await getLatestVersion()
|
|
263
383
|
if (!latestVersion) return
|
|
264
384
|
|
|
265
|
-
if (
|
|
385
|
+
if (
|
|
386
|
+
// Download new version if current binary errors.
|
|
387
|
+
currentVersion === 'error' ||
|
|
388
|
+
compareVersions(currentVersion, latestVersion) < 0
|
|
389
|
+
) {
|
|
266
390
|
term.clearLine()
|
|
267
391
|
|
|
268
392
|
// Remove the specific exit listener to prevent it from interfering with the update
|
|
@@ -288,11 +412,14 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
288
412
|
await downloadBinary(latestVersion)
|
|
289
413
|
|
|
290
414
|
// Restart with new binary - this replaces the current process
|
|
291
|
-
const newChild = spawn(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
415
|
+
const newChild = spawn(
|
|
416
|
+
CONFIG.binaryPath,
|
|
417
|
+
[packageName, ...process.argv.slice(2)],
|
|
418
|
+
{
|
|
419
|
+
stdio: 'inherit',
|
|
420
|
+
detached: false,
|
|
421
|
+
}
|
|
422
|
+
)
|
|
296
423
|
|
|
297
424
|
// Set up exit handler for the new process
|
|
298
425
|
newChild.on('exit', (code) => {
|
|
@@ -310,11 +437,14 @@ async function checkForUpdates(runningProcess, exitListener) {
|
|
|
310
437
|
async function main() {
|
|
311
438
|
await ensureBinaryExists()
|
|
312
439
|
|
|
313
|
-
// Start
|
|
314
|
-
const child = spawn(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
440
|
+
// Start the binary with codecane argument
|
|
441
|
+
const child = spawn(
|
|
442
|
+
CONFIG.binaryPath,
|
|
443
|
+
[packageName, ...process.argv.slice(2)],
|
|
444
|
+
{
|
|
445
|
+
stdio: 'inherit',
|
|
446
|
+
}
|
|
447
|
+
)
|
|
318
448
|
|
|
319
449
|
// Store reference to the exit listener so we can remove it during updates
|
|
320
450
|
const exitListener = (code) => {
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codecane",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "AI coding agent",
|
|
3
|
+
"version": "1.0.420-beta.1",
|
|
4
|
+
"description": "AI coding agent (staging)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
7
7
|
"codecane": "index.js"
|
|
8
8
|
},
|
|
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 */ }\""
|
|
11
|
+
},
|
|
9
12
|
"files": [
|
|
10
13
|
"index.js",
|
|
11
14
|
"README.md"
|