codo-ai 2.23.12 → 2.23.14
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 +2 -0
- package/bin/codo.js +307 -0
- package/package.json +23 -18
- package/bin/codo +0 -10
- package/postinstall.mjs +0 -205
package/README.md
CHANGED
|
@@ -100,6 +100,8 @@ npx codo-ai
|
|
|
100
100
|
|
|
101
101
|
Requirements: Node 18+ or Bun · macOS / Linux / Windows · any provider API key (Anthropic, OpenAI, NVIDIA free tier, Google, or OpenAI-compatible).
|
|
102
102
|
|
|
103
|
+
> No extra flags needed: the install works out of the box even when install scripts are blocked (`allowScripts` policies, `--ignore-scripts`), because the launcher resolves the prebuilt platform binary automatically on first run.
|
|
104
|
+
|
|
103
105
|
> Migrating from `@codo-ai/cli`? That package is deprecated — `codo-ai` replaces it.
|
|
104
106
|
|
|
105
107
|
## Documentation
|
package/bin/codo.js
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const childProcess = require("child_process")
|
|
4
|
+
const fs = require("fs")
|
|
5
|
+
const path = require("path")
|
|
6
|
+
const os = require("os")
|
|
7
|
+
|
|
8
|
+
const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"]
|
|
9
|
+
|
|
10
|
+
function run(target) {
|
|
11
|
+
const child = childProcess.spawn(target, process.argv.slice(2), {
|
|
12
|
+
stdio: "inherit",
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
child.on("error", (error) => {
|
|
16
|
+
console.error(error.message)
|
|
17
|
+
process.exit(1)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const forwarders = {}
|
|
21
|
+
for (const signal of forwardedSignals) {
|
|
22
|
+
forwarders[signal] = () => {
|
|
23
|
+
try {
|
|
24
|
+
child.kill(signal)
|
|
25
|
+
} catch {
|
|
26
|
+
// The child may have already exited.
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
process.on(signal, forwarders[signal])
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
child.on("exit", (code, signal) => {
|
|
33
|
+
for (const forwardedSignal of forwardedSignals) {
|
|
34
|
+
process.removeListener(forwardedSignal, forwarders[forwardedSignal])
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (signal) {
|
|
38
|
+
process.kill(process.pid, signal)
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.exit(typeof code === "number" ? code : 0)
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const envPath = process.env.CODO_BIN_PATH
|
|
47
|
+
|
|
48
|
+
const scriptPath = fs.realpathSync(__filename)
|
|
49
|
+
const scriptDir = path.dirname(scriptPath)
|
|
50
|
+
|
|
51
|
+
const platformMap = {
|
|
52
|
+
darwin: "darwin",
|
|
53
|
+
linux: "linux",
|
|
54
|
+
win32: "windows",
|
|
55
|
+
}
|
|
56
|
+
const archMap = {
|
|
57
|
+
x64: "x64",
|
|
58
|
+
arm64: "arm64",
|
|
59
|
+
arm: "arm",
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let platform = platformMap[os.platform()]
|
|
63
|
+
if (!platform) {
|
|
64
|
+
platform = os.platform()
|
|
65
|
+
}
|
|
66
|
+
let arch = archMap[os.arch()]
|
|
67
|
+
if (!arch) {
|
|
68
|
+
arch = os.arch()
|
|
69
|
+
}
|
|
70
|
+
const base = "codo-" + platform + "-" + arch
|
|
71
|
+
const binary = platform === "windows" ? "codo.exe" : "codo"
|
|
72
|
+
|
|
73
|
+
function supportsAvx2() {
|
|
74
|
+
if (arch !== "x64") return false
|
|
75
|
+
|
|
76
|
+
if (platform === "linux") {
|
|
77
|
+
try {
|
|
78
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
79
|
+
} catch {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (platform === "darwin") {
|
|
85
|
+
try {
|
|
86
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
87
|
+
encoding: "utf8",
|
|
88
|
+
timeout: 1500,
|
|
89
|
+
})
|
|
90
|
+
if (result.status !== 0) return false
|
|
91
|
+
return (result.stdout || "").trim() === "1"
|
|
92
|
+
} catch {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (platform === "windows") {
|
|
98
|
+
const cmd =
|
|
99
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
100
|
+
|
|
101
|
+
for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
102
|
+
try {
|
|
103
|
+
const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
|
|
104
|
+
encoding: "utf8",
|
|
105
|
+
timeout: 3000,
|
|
106
|
+
windowsHide: true,
|
|
107
|
+
})
|
|
108
|
+
if (result.status !== 0) continue
|
|
109
|
+
const out = (result.stdout || "").trim().toLowerCase()
|
|
110
|
+
if (out === "true" || out === "1") return true
|
|
111
|
+
if (out === "false" || out === "0") return false
|
|
112
|
+
} catch {
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const names = (() => {
|
|
124
|
+
const avx2 = supportsAvx2()
|
|
125
|
+
const baseline = arch === "x64" && !avx2
|
|
126
|
+
|
|
127
|
+
if (platform === "linux") {
|
|
128
|
+
const musl = (() => {
|
|
129
|
+
try {
|
|
130
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
131
|
+
} catch {
|
|
132
|
+
// ignore
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
137
|
+
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
|
|
138
|
+
if (text.includes("musl")) return true
|
|
139
|
+
} catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return false
|
|
144
|
+
})()
|
|
145
|
+
|
|
146
|
+
if (musl) {
|
|
147
|
+
if (arch === "x64") {
|
|
148
|
+
if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
149
|
+
return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
150
|
+
}
|
|
151
|
+
return [`${base}-musl`, base]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (arch === "x64") {
|
|
155
|
+
if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
156
|
+
return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
157
|
+
}
|
|
158
|
+
return [base, `${base}-musl`]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (arch === "x64") {
|
|
162
|
+
if (baseline) return [`${base}-baseline`, base]
|
|
163
|
+
return [base, `${base}-baseline`]
|
|
164
|
+
}
|
|
165
|
+
return [base]
|
|
166
|
+
})()
|
|
167
|
+
|
|
168
|
+
// Published platform packages name the binary with a version suffix
|
|
169
|
+
// ("codo-2.23.12" / "codo-2.23.12.exe"), so resolve by pattern rather than
|
|
170
|
+
// by a single hardcoded filename. Prefer an exact (unsuffixed) match so a
|
|
171
|
+
// binary staged by postinstall wins over a stale suffixed one.
|
|
172
|
+
function findBinaryIn(packageDir) {
|
|
173
|
+
let entries
|
|
174
|
+
try {
|
|
175
|
+
entries = fs.readdirSync(path.join(packageDir, "bin"))
|
|
176
|
+
} catch {
|
|
177
|
+
return undefined
|
|
178
|
+
}
|
|
179
|
+
if (entries.includes(binary)) return path.join(packageDir, "bin", binary)
|
|
180
|
+
const suffix = platform === "windows" ? ".exe" : ""
|
|
181
|
+
const match = entries
|
|
182
|
+
.filter((entry) => entry.startsWith("codo-") && (suffix === "" ? !entry.endsWith(".exe") : entry.endsWith(suffix)))
|
|
183
|
+
.sort()
|
|
184
|
+
.at(-1)
|
|
185
|
+
if (!match) return undefined
|
|
186
|
+
return path.join(packageDir, "bin", match)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function findBinary(startDir) {
|
|
190
|
+
let current = startDir
|
|
191
|
+
for (;;) {
|
|
192
|
+
const modules = path.join(current, "node_modules")
|
|
193
|
+
if (fs.existsSync(modules)) {
|
|
194
|
+
for (const name of names) {
|
|
195
|
+
const candidate = findBinaryIn(path.join(modules, `@codo-ai/${name}`))
|
|
196
|
+
if (candidate && fs.existsSync(candidate)) return candidate
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const parent = path.dirname(current)
|
|
200
|
+
if (parent === current) {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
current = parent
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// A fetched binary is staged next to this launcher so it can be found
|
|
208
|
+
// without walking node_modules on later runs.
|
|
209
|
+
const stagedName = platform === "windows" ? "codo.exe" : "codo"
|
|
210
|
+
const staged = path.join(scriptDir, stagedName)
|
|
211
|
+
const stagedBinary = (() => {
|
|
212
|
+
try {
|
|
213
|
+
if (fs.existsSync(staged)) return staged
|
|
214
|
+
} catch {
|
|
215
|
+
// ignore
|
|
216
|
+
}
|
|
217
|
+
return undefined
|
|
218
|
+
})()
|
|
219
|
+
|
|
220
|
+
const wrapperPkg = (() => {
|
|
221
|
+
try {
|
|
222
|
+
return JSON.parse(fs.readFileSync(path.join(scriptDir, "..", "package.json"), "utf8"))
|
|
223
|
+
} catch {
|
|
224
|
+
return {}
|
|
225
|
+
}
|
|
226
|
+
})()
|
|
227
|
+
|
|
228
|
+
// Last resort: download the platform package on demand with npm and stage
|
|
229
|
+
// its binary next to this launcher. Runs only when the package manager
|
|
230
|
+
// skipped the optional platform packages at install time.
|
|
231
|
+
function fetchBinary() {
|
|
232
|
+
const deps = wrapperPkg.optionalDependencies || {}
|
|
233
|
+
for (const name of names) {
|
|
234
|
+
const scoped = `@codo-ai/${name}`
|
|
235
|
+
const version = deps[scoped]
|
|
236
|
+
if (!version) continue
|
|
237
|
+
let tmp
|
|
238
|
+
try {
|
|
239
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "codo-bin-"))
|
|
240
|
+
} catch {
|
|
241
|
+
continue
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
// `npm` is a shell script on Windows, so plain spawn fails with
|
|
245
|
+
// ENOENT. Prefer node + npm-cli.js (no shell, no quoting hazards);
|
|
246
|
+
// fall back to a shell spawn only when the CLI file is missing.
|
|
247
|
+
let cmd = "npm"
|
|
248
|
+
const args = ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", tmp, `${scoped}@${version}`]
|
|
249
|
+
const opts = { encoding: "utf8", timeout: 300000, windowsHide: true }
|
|
250
|
+
if (process.platform === "win32") {
|
|
251
|
+
const cli = path.join(path.dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js")
|
|
252
|
+
let cliExists = false
|
|
253
|
+
try {
|
|
254
|
+
cliExists = fs.existsSync(cli)
|
|
255
|
+
} catch {
|
|
256
|
+
cliExists = false
|
|
257
|
+
}
|
|
258
|
+
if (cliExists) {
|
|
259
|
+
cmd = process.execPath
|
|
260
|
+
args.unshift(cli)
|
|
261
|
+
} else {
|
|
262
|
+
opts.shell = true
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const result = childProcess.spawnSync(cmd, args, opts)
|
|
266
|
+
if (result.status !== 0) continue
|
|
267
|
+
const found = findBinaryIn(path.join(tmp, "node_modules", scoped))
|
|
268
|
+
if (!found) continue
|
|
269
|
+
try {
|
|
270
|
+
if (!fs.existsSync(found)) continue
|
|
271
|
+
} catch {
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
fs.copyFileSync(found, staged)
|
|
276
|
+
try {
|
|
277
|
+
fs.chmodSync(staged, 0o755)
|
|
278
|
+
} catch {
|
|
279
|
+
// chmod is best-effort on Windows.
|
|
280
|
+
}
|
|
281
|
+
return staged
|
|
282
|
+
} catch {
|
|
283
|
+
return found
|
|
284
|
+
}
|
|
285
|
+
} catch {
|
|
286
|
+
continue
|
|
287
|
+
} finally {
|
|
288
|
+
try {
|
|
289
|
+
fs.rmSync(tmp, { recursive: true, force: true })
|
|
290
|
+
} catch {
|
|
291
|
+
// ignore
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return undefined
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const resolved = envPath || stagedBinary || findBinary(scriptDir) || fetchBinary()
|
|
299
|
+
if (!resolved) {
|
|
300
|
+
console.error(
|
|
301
|
+
"Could not find the codo native binary. Your package manager may have skipped the optional platform packages. Try installing manually: " +
|
|
302
|
+
names.map((n) => `"@codo-ai/${n}"`).join(" or "),
|
|
303
|
+
)
|
|
304
|
+
process.exit(1)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
run(resolved)
|
package/package.json
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
"description": "The security-native AI coding agent. Six Sec-Test security personas, compliance-first /scraper, a business documents & research suite, and multi-agent Compose orchestration — spec-driven workflow engines in one terminal-first CLI.",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"ai",
|
|
6
|
+
"ai-agent",
|
|
6
7
|
"coding-agent",
|
|
8
|
+
"coding-assistant",
|
|
7
9
|
"cli",
|
|
8
10
|
"terminal",
|
|
9
11
|
"tui",
|
|
@@ -16,8 +18,14 @@
|
|
|
16
18
|
"pentest",
|
|
17
19
|
"spec-driven",
|
|
18
20
|
"multi-agent",
|
|
21
|
+
"autonomous",
|
|
22
|
+
"mcp",
|
|
23
|
+
"devtools",
|
|
19
24
|
"opencode"
|
|
20
25
|
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
21
29
|
"homepage": "https://codo-ai.vercel.app/",
|
|
22
30
|
"repository": {
|
|
23
31
|
"type": "git",
|
|
@@ -27,12 +35,9 @@
|
|
|
27
35
|
"url": "https://github.com/Mosalah4351/COdo/issues"
|
|
28
36
|
},
|
|
29
37
|
"bin": {
|
|
30
|
-
"codo": "./bin/codo"
|
|
31
|
-
},
|
|
32
|
-
"scripts": {
|
|
33
|
-
"postinstall": "node ./postinstall.mjs"
|
|
38
|
+
"codo": "./bin/codo.js"
|
|
34
39
|
},
|
|
35
|
-
"version": "2.23.
|
|
40
|
+
"version": "2.23.14",
|
|
36
41
|
"license": "MIT",
|
|
37
42
|
"os": [
|
|
38
43
|
"darwin",
|
|
@@ -44,17 +49,17 @@
|
|
|
44
49
|
"x64"
|
|
45
50
|
],
|
|
46
51
|
"optionalDependencies": {
|
|
47
|
-
"@codo-ai/codo-windows-x64-baseline": "2.23.
|
|
48
|
-
"@codo-ai/codo-windows-x64": "2.23.
|
|
49
|
-
"@codo-ai/codo-windows-arm64": "2.23.
|
|
50
|
-
"@codo-ai/codo-linux-x64-musl": "2.23.
|
|
51
|
-
"@codo-ai/codo-linux-x64-baseline-musl": "2.23.
|
|
52
|
-
"@codo-ai/codo-linux-x64-baseline": "2.23.
|
|
53
|
-
"@codo-ai/codo-linux-x64": "2.23.
|
|
54
|
-
"@codo-ai/codo-linux-arm64-musl": "2.23.
|
|
55
|
-
"@codo-ai/codo-linux-arm64": "2.23.
|
|
56
|
-
"@codo-ai/codo-darwin-x64-baseline": "2.23.
|
|
57
|
-
"@codo-ai/codo-darwin-x64": "2.23.
|
|
58
|
-
"@codo-ai/codo-darwin-arm64": "2.23.
|
|
52
|
+
"@codo-ai/codo-windows-x64-baseline": "2.23.14",
|
|
53
|
+
"@codo-ai/codo-windows-x64": "2.23.14",
|
|
54
|
+
"@codo-ai/codo-windows-arm64": "2.23.14",
|
|
55
|
+
"@codo-ai/codo-linux-x64-musl": "2.23.14",
|
|
56
|
+
"@codo-ai/codo-linux-x64-baseline-musl": "2.23.14",
|
|
57
|
+
"@codo-ai/codo-linux-x64-baseline": "2.23.14",
|
|
58
|
+
"@codo-ai/codo-linux-x64": "2.23.14",
|
|
59
|
+
"@codo-ai/codo-linux-arm64-musl": "2.23.14",
|
|
60
|
+
"@codo-ai/codo-linux-arm64": "2.23.14",
|
|
61
|
+
"@codo-ai/codo-darwin-x64-baseline": "2.23.14",
|
|
62
|
+
"@codo-ai/codo-darwin-x64": "2.23.14",
|
|
63
|
+
"@codo-ai/codo-darwin-arm64": "2.23.14"
|
|
59
64
|
}
|
|
60
|
-
}
|
|
65
|
+
}
|
package/bin/codo
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
echo "Error: codo-ai's postinstall script was not run." >&2
|
|
2
|
-
echo "" >&2
|
|
3
|
-
echo "This occurs when using --ignore-scripts during installation, or when using a" >&2
|
|
4
|
-
echo "package manager like pnpm that does not run postinstall scripts by default." >&2
|
|
5
|
-
echo "" >&2
|
|
6
|
-
echo "To fix this, run the postinstall script manually:" >&2
|
|
7
|
-
echo " cd node_modules/codo-ai && node postinstall.mjs" >&2
|
|
8
|
-
echo "" >&2
|
|
9
|
-
echo "Or reinstall codo-ai without the --ignore-scripts flag." >&2
|
|
10
|
-
exit 1
|
package/postinstall.mjs
DELETED
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import childProcess from "child_process"
|
|
4
|
-
import fs from "fs"
|
|
5
|
-
import os from "os"
|
|
6
|
-
import path from "path"
|
|
7
|
-
import { createRequire } from "module"
|
|
8
|
-
import { fileURLToPath } from "url"
|
|
9
|
-
|
|
10
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
-
const require = createRequire(import.meta.url)
|
|
12
|
-
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
|
|
13
|
-
|
|
14
|
-
const platformMap = {
|
|
15
|
-
darwin: "darwin",
|
|
16
|
-
linux: "linux",
|
|
17
|
-
win32: "windows",
|
|
18
|
-
}
|
|
19
|
-
const archMap = {
|
|
20
|
-
x64: "x64",
|
|
21
|
-
arm64: "arm64",
|
|
22
|
-
arm: "arm",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const platform = platformMap[os.platform()] ?? os.platform()
|
|
26
|
-
const arch = archMap[os.arch()] ?? os.arch()
|
|
27
|
-
const base = `codo-${platform}-${arch}`
|
|
28
|
-
const sourceBinary = platform === "windows" ? "codo.exe" : "codo"
|
|
29
|
-
const targetBinary = path.join(__dirname, "bin", "codo.exe")
|
|
30
|
-
|
|
31
|
-
function supportsAvx2() {
|
|
32
|
-
if (arch !== "x64") return false
|
|
33
|
-
|
|
34
|
-
if (platform === "linux") {
|
|
35
|
-
try {
|
|
36
|
-
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
37
|
-
} catch {
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (platform === "darwin") {
|
|
43
|
-
try {
|
|
44
|
-
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
45
|
-
encoding: "utf8",
|
|
46
|
-
timeout: 1500,
|
|
47
|
-
})
|
|
48
|
-
if (result.status !== 0) return false
|
|
49
|
-
return (result.stdout || "").trim() === "1"
|
|
50
|
-
} catch {
|
|
51
|
-
return false
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (platform === "windows") {
|
|
56
|
-
const command =
|
|
57
|
-
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
58
|
-
|
|
59
|
-
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
60
|
-
try {
|
|
61
|
-
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
|
|
62
|
-
encoding: "utf8",
|
|
63
|
-
timeout: 3000,
|
|
64
|
-
windowsHide: true,
|
|
65
|
-
})
|
|
66
|
-
if (result.status !== 0) continue
|
|
67
|
-
const output = (result.stdout || "").trim().toLowerCase()
|
|
68
|
-
if (output === "true" || output === "1") return true
|
|
69
|
-
if (output === "false" || output === "0") return false
|
|
70
|
-
} catch {
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isMusl() {
|
|
80
|
-
if (platform !== "linux") return false
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
if (fs.existsSync("/etc/alpine-release")) return true
|
|
84
|
-
} catch {
|
|
85
|
-
// Ignore filesystem probes that are blocked by the host.
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
90
|
-
return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
|
|
91
|
-
} catch {
|
|
92
|
-
return false
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function packageNames() {
|
|
97
|
-
const baseline = arch === "x64" && !supportsAvx2()
|
|
98
|
-
|
|
99
|
-
if (platform === "linux") {
|
|
100
|
-
if (isMusl()) {
|
|
101
|
-
if (arch === "x64")
|
|
102
|
-
return baseline
|
|
103
|
-
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
104
|
-
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
105
|
-
return [`${base}-musl`, base]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (arch === "x64")
|
|
109
|
-
return baseline
|
|
110
|
-
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
111
|
-
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
112
|
-
return [base, `${base}-musl`]
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
|
|
116
|
-
return [base]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Published packages may name the binary exactly ("codo.exe" / "codo") or with
|
|
120
|
-
// a version suffix ("codo-2.23.5.exe"), so resolve by pattern rather than by
|
|
121
|
-
// a single hardcoded filename.
|
|
122
|
-
function findBinary(dir) {
|
|
123
|
-
const entries = fs.readdirSync(path.join(dir, "bin"))
|
|
124
|
-
const match =
|
|
125
|
-
entries.find((entry) => entry === sourceBinary) ??
|
|
126
|
-
(platform === "windows"
|
|
127
|
-
? entries.find((entry) => entry.startsWith("codo") && entry.endsWith(".exe"))
|
|
128
|
-
: undefined) ??
|
|
129
|
-
entries.find((entry) => entry.startsWith("codo"))
|
|
130
|
-
if (!match) throw new Error(`Binary not found in ${path.join(dir, "bin")}`)
|
|
131
|
-
return path.join(dir, "bin", match)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Platform binaries live in scoped packages (@codo-ai/codo-<platform>-<arch>),
|
|
135
|
-
// while packageNames() works with the unscoped suffix.
|
|
136
|
-
const scope = "@codo-ai/"
|
|
137
|
-
|
|
138
|
-
function resolveBinary(name) {
|
|
139
|
-
return findBinary(path.dirname(require.resolve(`${scope}${name}/package.json`)))
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function installPackage(name) {
|
|
143
|
-
const version = packageJson.optionalDependencies?.[`${scope}${name}`]
|
|
144
|
-
if (!version) return
|
|
145
|
-
|
|
146
|
-
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "codo-install-"))
|
|
147
|
-
try {
|
|
148
|
-
const result = childProcess.spawnSync(
|
|
149
|
-
"npm",
|
|
150
|
-
["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${scope}${name}@${version}`],
|
|
151
|
-
{ stdio: "inherit", windowsHide: true },
|
|
152
|
-
)
|
|
153
|
-
if (result.status !== 0) return
|
|
154
|
-
const packageDir = path.join(temp, "node_modules", scope, name)
|
|
155
|
-
copyBinary(findBinary(packageDir), targetBinary)
|
|
156
|
-
return true
|
|
157
|
-
} finally {
|
|
158
|
-
fs.rmSync(temp, { recursive: true, force: true })
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function copyBinary(source, target) {
|
|
163
|
-
if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
|
|
164
|
-
fs.mkdirSync(path.dirname(target), { recursive: true })
|
|
165
|
-
if (fs.existsSync(target)) fs.unlinkSync(target)
|
|
166
|
-
try {
|
|
167
|
-
fs.linkSync(source, target)
|
|
168
|
-
} catch {
|
|
169
|
-
fs.copyFileSync(source, target)
|
|
170
|
-
}
|
|
171
|
-
fs.chmodSync(target, 0o755)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function verifyBinary() {
|
|
175
|
-
const result = childProcess.spawnSync(targetBinary, ["--version"], {
|
|
176
|
-
encoding: "utf8",
|
|
177
|
-
stdio: "ignore",
|
|
178
|
-
windowsHide: true,
|
|
179
|
-
})
|
|
180
|
-
return result.status === 0
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function main() {
|
|
184
|
-
for (const name of packageNames()) {
|
|
185
|
-
try {
|
|
186
|
-
copyBinary(resolveBinary(name), targetBinary)
|
|
187
|
-
if (verifyBinary()) return
|
|
188
|
-
} catch {
|
|
189
|
-
if (installPackage(name) && verifyBinary()) return
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
throw new Error(
|
|
194
|
-
`It seems your package manager failed to install the right codo CLI package. Try manually installing ${packageNames()
|
|
195
|
-
.map((name) => JSON.stringify(`@codo-ai/${name}`))
|
|
196
|
-
.join(" or ")}.`,
|
|
197
|
-
)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
main()
|
|
202
|
-
} catch (error) {
|
|
203
|
-
console.error(error.message)
|
|
204
|
-
process.exit(1)
|
|
205
|
-
}
|