@nemoobc/opencode-termux 1.18.21
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 +39 -0
- package/bin/opencode.js +17 -0
- package/install.mjs +78 -0
- package/package.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @nemoobc/opencode-termux
|
|
2
|
+
|
|
3
|
+
**opencode CLI native di Termux/Android — TANPA proot.**
|
|
4
|
+
|
|
5
|
+
Paket ini menjembatani masalah: `opencode-ai` resmi tidak punya target `android`,
|
|
6
|
+
sehingga postinstall gagal di Termux. Solusinya: paket ini mengunduh binary
|
|
7
|
+
resmi `opencode-linux-arm64-musl` + **loader musl & libstdc++/libgcc dari Alpine**,
|
|
8
|
+
lalu menjalankannya lewat loader tersebut — murni userspace.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pkg update && pkg install nodejs-lts
|
|
14
|
+
npm i -g @nemoobc/opencode-termux
|
|
15
|
+
opencode-termux --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Alias biar terasa asli:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
ln -sf $PREFIX/bin/opencode-termux $PREFIX/bin/opencode
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Default model gratis: `opencode/x-preview-f-free` (Ox Alpha Free).
|
|
25
|
+
|
|
26
|
+
## Cara kerja
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
opencode-termux → ld-musl-aarch64.so.1 (dibundel) → opencode (musl, dibundel)
|
|
30
|
+
↑ LD_LIBRARY_PATH: libstdc++/libgcc (dibundel)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Tidak ada file sistem Android yang disentuh. Semua ada di `$PREFIX/lib/node_modules/@nemoobc/opencode-termux/vendor`.
|
|
34
|
+
|
|
35
|
+
## Batasan
|
|
36
|
+
|
|
37
|
+
- Arsitektur: **arm64** (hampir semua HP sekarang). x86_64 bisa dipaksa utk uji: `OCX_ARCH=x64 OCX_FORCE=1 npm rebuild ...`
|
|
38
|
+
- Butuh koneksi internet saat `npm install` (mengunduh ~200 MB binary)
|
|
39
|
+
- Jika upstream opencode rilis versi baru, paket ini perlu bump versi mengikuti
|
package/bin/opencode.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawnSync } = require("child_process")
|
|
3
|
+
const fs = require("fs")
|
|
4
|
+
const path = require("path")
|
|
5
|
+
const vendor = path.join(__dirname, "..", "vendor")
|
|
6
|
+
const loader = path.join(vendor, "ld-musl.so")
|
|
7
|
+
const bin = path.join(vendor, "opencode")
|
|
8
|
+
if (!fs.existsSync(loader) || !fs.existsSync(bin)) {
|
|
9
|
+
console.error("[opencode-termux] vendor belum terpasang. Jalankan ulang:")
|
|
10
|
+
console.error(" npm rebuild -g @nemoobc/opencode-termux")
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
const r = spawnSync(loader, [bin, ...process.argv.slice(2)], {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
env: { ...process.env, LD_LIBRARY_PATH: vendor },
|
|
16
|
+
})
|
|
17
|
+
process.exit(r.status ?? 1)
|
package/install.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* postinstall untuk @nemoobc/opencode-termux
|
|
4
|
+
* Menyusun bundle native: loader musl + libgcc/libstdc++ + binary opencode
|
|
5
|
+
* Target: Termux (android/arm64). Override uji: OCX_ARCH=x64 OCX_FORCE=1
|
|
6
|
+
*/
|
|
7
|
+
import fs from "fs"
|
|
8
|
+
import path from "path"
|
|
9
|
+
import { execFileSync } from "child_process"
|
|
10
|
+
import { fileURLToPath } from "url"
|
|
11
|
+
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
const V = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8")).version
|
|
14
|
+
const ARCH = process.env.OCX_ARCH || "arm64"
|
|
15
|
+
const FORCE = !!process.env.OCX_FORCE
|
|
16
|
+
const IS_ANDROID = process.platform === "android"
|
|
17
|
+
const IS_ARM64 = process.arch === "arm64"
|
|
18
|
+
|
|
19
|
+
if (!IS_ANDROID && !FORCE) {
|
|
20
|
+
console.log("[opencode-termux] Bukan Termux/Android — instalasi dilewati (pakai opencode-ai resmi).")
|
|
21
|
+
process.exit(0)
|
|
22
|
+
}
|
|
23
|
+
if (!FORCE && !IS_ARM64 && ARCH !== "x64") {
|
|
24
|
+
console.log(`[opencode-termux] arsitektur ${process.arch} belum didukung.`)
|
|
25
|
+
process.exit(0)
|
|
26
|
+
}
|
|
27
|
+
const A = ARCH === "x64" ? "x86_64" : "aarch64"
|
|
28
|
+
|
|
29
|
+
const dl = (url, dest) => {
|
|
30
|
+
console.log(`[opencode-termux] download ${url.split("/").pop()}`)
|
|
31
|
+
execFileSync("curl", ["-sL", "--retry", "3", "-o", dest, url], { stdio: "inherit" })
|
|
32
|
+
}
|
|
33
|
+
const untar = (tgz, dest, members = []) => {
|
|
34
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
35
|
+
const args = ["xzf", tgz, "-C", dest, ...members]
|
|
36
|
+
try { execFileSync("tar", args) }
|
|
37
|
+
catch { execFileSync("tar", args.map(a => a.startsWith("./") ? a.slice(2) : a)) }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const work = path.join(__dirname, ".build")
|
|
41
|
+
fs.rmSync(work, { recursive: true, force: true })
|
|
42
|
+
fs.mkdirSync(work, { recursive: true })
|
|
43
|
+
|
|
44
|
+
// 1) binary opencode (musl) dari npm resmi
|
|
45
|
+
dl(`https://registry.npmjs.org/opencode-linux-${ARCH}-musl/-/opencode-linux-${ARCH}-musl-${V}.tgz`, `${work}/oc.tgz`)
|
|
46
|
+
untar(`${work}/oc.tgz`, `${work}/oc`)
|
|
47
|
+
|
|
48
|
+
// 2) loader+libc musl dari Alpine minirootfs
|
|
49
|
+
const AV = "v3.21", AL = "3.21.3"
|
|
50
|
+
dl(`https://dl-cdn.alpinelinux.org/alpine/${AV}/releases/${A}/alpine-minirootfs-${AL}-${A}.tar.gz`, `${work}/ap.tgz`)
|
|
51
|
+
untar(`${work}/ap.tgz`, `${work}/ap`, ["./lib"])
|
|
52
|
+
|
|
53
|
+
// 3) libgcc + libstdc++
|
|
54
|
+
const apkDir = `${work}/apk`; fs.mkdirSync(apkDir, { recursive: true })
|
|
55
|
+
for (const f of [`libgcc-14.2.0-r4.apk`, `libstdc%2B%2B-14.2.0-r4.apk`]) {
|
|
56
|
+
dl(`https://dl-cdn.alpinelinux.org/alpine/${AV}/main/${A}/${f}`, `${apkDir}/${f}`)
|
|
57
|
+
untar(`${apkDir}/${f}`, apkDir)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 4) rakit vendor/
|
|
61
|
+
const vendor = path.join(__dirname, "vendor")
|
|
62
|
+
fs.rmSync(vendor, { recursive: true, force: true }); fs.mkdirSync(vendor)
|
|
63
|
+
const cp = (from, name) => fs.copyFileSync(from, path.join(vendor, name))
|
|
64
|
+
cp(`${work}/ap/lib/ld-musl-${A}.so.1`, "ld-musl.so")
|
|
65
|
+
cp(`${work}/oc/package/bin/opencode`, "opencode")
|
|
66
|
+
for (const f of fs.readdirSync(`${apkDir}/usr/lib`)) {
|
|
67
|
+
if (/^libstdc\+\+\.so|^libgcc_s\.so/.test(f)) cp(`${apkDir}/usr/lib/${f}`, f)
|
|
68
|
+
}
|
|
69
|
+
for (const f of fs.readdirSync(vendor)) fs.chmodSync(path.join(vendor, f), 0o755)
|
|
70
|
+
|
|
71
|
+
// 5) smoke test
|
|
72
|
+
console.log("[opencode-termux] smoke test…")
|
|
73
|
+
execFileSync(path.join(vendor, "ld-musl.so"),
|
|
74
|
+
[path.join(vendor, "opencode"), "--version"],
|
|
75
|
+
{ stdio: "inherit", env: { ...process.env, LD_LIBRARY_PATH: vendor } })
|
|
76
|
+
|
|
77
|
+
fs.rmSync(work, { recursive: true, force: true })
|
|
78
|
+
console.log(`[opencode-termux] ✅ siap! Jalankan dengan: opencode-termux`)
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nemoobc/opencode-termux",
|
|
3
|
+
"version": "1.18.21",
|
|
4
|
+
"description": "opencode CLI native untuk Termux/Android tanpa proot — membundel loader musl + binary opencode resmi (upstream opencode-ai)",
|
|
5
|
+
"bin": {
|
|
6
|
+
"opencode-termux": "./bin/opencode.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node install.mjs"
|
|
10
|
+
},
|
|
11
|
+
"keywords": ["opencode", "termux", "android", "cli", "ai"],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"engines": { "node": ">=18" },
|
|
14
|
+
"files": ["bin", "install.mjs", "README.md"]
|
|
15
|
+
}
|