@jo.cs98/opencode-plus 1.3.0-plus.2

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 ADDED
@@ -0,0 +1,15 @@
1
+ # js
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.2.12. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ // postinstall: downloads the pre-built opencode-plus binary from GitHub Releases
3
+
4
+ const https = require("https")
5
+ const http = require("http")
6
+ const fs = require("fs")
7
+ const path = require("path")
8
+ const os = require("os")
9
+ const { execFileSync } = require("child_process")
10
+
11
+ const REPO = "joaquincabrerasimoes/opencode-plus"
12
+ const NPM_PKG = "@jo.cs98/opencode-plus"
13
+
14
+ // Resolve the directory containing this script (bin/)
15
+ const binDir = path.dirname(fs.realpathSync(__filename))
16
+ const dest = path.join(binDir, ".opencode" + (os.platform() === "win32" ? ".exe" : ""))
17
+
18
+ // Skip if already present (e.g. re-running postinstall after an install)
19
+ if (fs.existsSync(dest)) {
20
+ process.exit(0)
21
+ }
22
+
23
+ const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
24
+ const archMap = { x64: "x64", arm64: "arm64" }
25
+
26
+ const platform = platformMap[os.platform()]
27
+ const arch = archMap[os.arch()]
28
+
29
+ if (!platform || !arch) {
30
+ console.warn(`[opencode-plus] Unsupported platform: ${os.platform()} ${os.arch()} — skipping binary download`)
31
+ process.exit(0)
32
+ }
33
+
34
+ function needsBaseline() {
35
+ if (arch !== "x64") return false
36
+ if (platform === "linux") {
37
+ try {
38
+ return !/(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
39
+ } catch {
40
+ return false
41
+ }
42
+ }
43
+ return false
44
+ }
45
+
46
+ const base = `opencode-plus-${platform}-${arch}`
47
+ const candidates = needsBaseline() ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
48
+
49
+ // Asset name on GitHub Releases: opencode-plus-windows-x64.zip / opencode-plus-linux-x64.tar.gz
50
+ const ext = platform === "linux" ? ".tar.gz" : ".zip"
51
+ const binName = platform === "windows" ? "opencode.exe" : "opencode"
52
+
53
+ function fetch(url, redirect = 0) {
54
+ if (redirect > 5) throw new Error("Too many redirects")
55
+ return new Promise((resolve, reject) => {
56
+ const mod = url.startsWith("https") ? https : http
57
+ mod
58
+ .get(url, { headers: { "User-Agent": "opencode-plus-installer" } }, (res) => {
59
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
60
+ resolve(fetch(res.headers.location, redirect + 1))
61
+ return
62
+ }
63
+ if (res.statusCode !== 200) {
64
+ reject(new Error(`HTTP ${res.statusCode} for ${url}`))
65
+ return
66
+ }
67
+ const chunks = []
68
+ res.on("data", (c) => chunks.push(c))
69
+ res.on("end", () => resolve(Buffer.concat(chunks)))
70
+ res.on("error", reject)
71
+ })
72
+ .on("error", reject)
73
+ })
74
+ }
75
+
76
+ async function getTag() {
77
+ // First try: find a release whose tag matches our package version
78
+ const ver = require(path.join(binDir, "..", "package.json")).version
79
+ const data = await fetch(`https://api.github.com/repos/${REPO}/releases?per_page=20`)
80
+ const releases = JSON.parse(data.toString())
81
+ const match = releases.find((r) => r.tag_name.includes(ver))
82
+ if (match) return match.tag_name
83
+ // Fallback: find any release that has our platform asset
84
+ const asset = `opencode-plus-${platform}-${arch}${ext}`
85
+ const withAsset = releases.find((r) => r.assets && r.assets.some((a) => a.name === asset))
86
+ if (withAsset) return withAsset.tag_name
87
+ // Last resort: latest
88
+ return releases[0].tag_name
89
+ }
90
+
91
+ async function tryDownload(tag, assetName) {
92
+ const url = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`
93
+ try {
94
+ const buf = await fetch(url)
95
+ return buf
96
+ } catch {
97
+ return null
98
+ }
99
+ }
100
+
101
+ async function extractBinary(buf, assetName) {
102
+ const tmp = path.join(os.tmpdir(), `opencode-plus-${Date.now()}`)
103
+ fs.mkdirSync(tmp, { recursive: true })
104
+ const archive = path.join(tmp, assetName)
105
+ fs.writeFileSync(archive, buf)
106
+
107
+ if (assetName.endsWith(".zip")) {
108
+ // Use PowerShell on Windows, unzip on others
109
+ if (process.platform === "win32") {
110
+ execFileSync("powershell.exe", [
111
+ "-NoProfile",
112
+ "-NonInteractive",
113
+ "-Command",
114
+ `Expand-Archive -Path '${archive}' -DestinationPath '${tmp}' -Force`,
115
+ ])
116
+ } else {
117
+ execFileSync("unzip", ["-q", "-o", archive, "-d", tmp])
118
+ }
119
+ } else {
120
+ execFileSync("tar", ["-xzf", archive, "-C", tmp])
121
+ }
122
+
123
+ const extracted = path.join(tmp, binName)
124
+ if (!fs.existsSync(extracted)) {
125
+ throw new Error(`Binary not found in archive at ${extracted}`)
126
+ }
127
+ return extracted
128
+ }
129
+
130
+ async function main() {
131
+ let tag
132
+ try {
133
+ tag = await getTag()
134
+ } catch (e) {
135
+ console.warn(`[opencode-plus] Could not fetch release tag: ${e.message} — skipping`)
136
+ process.exit(0)
137
+ }
138
+
139
+ console.log(`[opencode-plus] Downloading binary for ${platform}-${arch} from release ${tag}`)
140
+
141
+ for (const name of candidates) {
142
+ const assetName = name + ext
143
+ const buf = await tryDownload(tag, assetName)
144
+ if (!buf) continue
145
+
146
+ let extracted
147
+ try {
148
+ extracted = await extractBinary(buf, assetName)
149
+ } catch (e) {
150
+ console.warn(`[opencode-plus] Failed to extract ${assetName}: ${e.message}`)
151
+ continue
152
+ }
153
+
154
+ fs.copyFileSync(extracted, dest)
155
+ if (platform !== "windows") fs.chmodSync(dest, 0o755)
156
+ console.log(`[opencode-plus] Installed binary to ${dest}`)
157
+ return
158
+ }
159
+
160
+ console.warn(
161
+ `[opencode-plus] No pre-built binary found for ${platform}-${arch} in release ${tag}.\n` +
162
+ ` Tried: ${candidates.map((n) => n + ext).join(", ")}\n` +
163
+ ` You may need to build from source.`,
164
+ )
165
+ // non-fatal: bin/opencode will give a helpful error at runtime
166
+ }
167
+
168
+ main().catch((e) => {
169
+ console.warn(`[opencode-plus] Install script failed: ${e.message}`)
170
+ // non-fatal
171
+ })
@@ -0,0 +1,179 @@
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
+ function run(target) {
9
+ const result = childProcess.spawnSync(target, process.argv.slice(2), {
10
+ stdio: "inherit",
11
+ })
12
+ if (result.error) {
13
+ console.error(result.error.message)
14
+ process.exit(1)
15
+ }
16
+ const code = typeof result.status === "number" ? result.status : 0
17
+ process.exit(code)
18
+ }
19
+
20
+ const envPath = process.env.OPENCODE_BIN_PATH
21
+ if (envPath) {
22
+ run(envPath)
23
+ }
24
+
25
+ const scriptPath = fs.realpathSync(__filename)
26
+ const scriptDir = path.dirname(scriptPath)
27
+
28
+ //
29
+ const cached = path.join(scriptDir, ".opencode" + (os.platform() === "win32" ? ".exe" : ""))
30
+ if (fs.existsSync(cached)) {
31
+ run(cached)
32
+ }
33
+
34
+ const platformMap = {
35
+ darwin: "darwin",
36
+ linux: "linux",
37
+ win32: "windows",
38
+ }
39
+ const archMap = {
40
+ x64: "x64",
41
+ arm64: "arm64",
42
+ arm: "arm",
43
+ }
44
+
45
+ let platform = platformMap[os.platform()]
46
+ if (!platform) {
47
+ platform = os.platform()
48
+ }
49
+ let arch = archMap[os.arch()]
50
+ if (!arch) {
51
+ arch = os.arch()
52
+ }
53
+ const base = "opencode-plus-" + platform + "-" + arch
54
+ const binary = platform === "windows" ? "opencode.exe" : "opencode"
55
+
56
+ function supportsAvx2() {
57
+ if (arch !== "x64") return false
58
+
59
+ if (platform === "linux") {
60
+ try {
61
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
62
+ } catch {
63
+ return false
64
+ }
65
+ }
66
+
67
+ if (platform === "darwin") {
68
+ try {
69
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
70
+ encoding: "utf8",
71
+ timeout: 1500,
72
+ })
73
+ if (result.status !== 0) return false
74
+ return (result.stdout || "").trim() === "1"
75
+ } catch {
76
+ return false
77
+ }
78
+ }
79
+
80
+ if (platform === "windows") {
81
+ const cmd =
82
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
83
+
84
+ for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
85
+ try {
86
+ const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
87
+ encoding: "utf8",
88
+ timeout: 3000,
89
+ windowsHide: true,
90
+ })
91
+ if (result.status !== 0) continue
92
+ const out = (result.stdout || "").trim().toLowerCase()
93
+ if (out === "true" || out === "1") return true
94
+ if (out === "false" || out === "0") return false
95
+ } catch {
96
+ continue
97
+ }
98
+ }
99
+
100
+ return false
101
+ }
102
+
103
+ return false
104
+ }
105
+
106
+ const names = (() => {
107
+ const avx2 = supportsAvx2()
108
+ const baseline = arch === "x64" && !avx2
109
+
110
+ if (platform === "linux") {
111
+ const musl = (() => {
112
+ try {
113
+ if (fs.existsSync("/etc/alpine-release")) return true
114
+ } catch {
115
+ // ignore
116
+ }
117
+
118
+ try {
119
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
120
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
121
+ if (text.includes("musl")) return true
122
+ } catch {
123
+ // ignore
124
+ }
125
+
126
+ return false
127
+ })()
128
+
129
+ if (musl) {
130
+ if (arch === "x64") {
131
+ if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
132
+ return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
133
+ }
134
+ return [`${base}-musl`, base]
135
+ }
136
+
137
+ if (arch === "x64") {
138
+ if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
139
+ return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
140
+ }
141
+ return [base, `${base}-musl`]
142
+ }
143
+
144
+ if (arch === "x64") {
145
+ if (baseline) return [`${base}-baseline`, base]
146
+ return [base, `${base}-baseline`]
147
+ }
148
+ return [base]
149
+ })()
150
+
151
+ function findBinary(startDir) {
152
+ let current = startDir
153
+ for (;;) {
154
+ const modules = path.join(current, "node_modules")
155
+ if (fs.existsSync(modules)) {
156
+ for (const name of names) {
157
+ const candidate = path.join(modules, name, "bin", binary)
158
+ if (fs.existsSync(candidate)) return candidate
159
+ }
160
+ }
161
+ const parent = path.dirname(current)
162
+ if (parent === current) {
163
+ return
164
+ }
165
+ current = parent
166
+ }
167
+ }
168
+
169
+ const resolved = findBinary(scriptDir)
170
+ if (!resolved) {
171
+ console.error(
172
+ "It seems that your package manager failed to install the right version of the opencode CLI for your platform. You can try manually installing " +
173
+ names.map((n) => `\"${n}\"`).join(" or ") +
174
+ " package",
175
+ )
176
+ process.exit(1)
177
+ }
178
+
179
+ run(resolved)
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "version": "1.3.0-plus.2",
3
+ "name": "@jo.cs98/opencode-plus",
4
+ "description": "OpenCode Plus - AI coding agent CLI",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node ./bin/install.cjs"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "README.md"
16
+ ],
17
+ "bin": {
18
+ "opencodeplus": "./bin/opencodeplus.cjs"
19
+ }
20
+ }