@showlotus/dsterm 0.0.0-stage → 0.1.0-alpha.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/bin/dsterm.exe +5 -0
- package/package.json +21 -3
- package/postinstall.mjs +193 -0
- package/README.md +0 -3
package/bin/dsterm.exe
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@showlotus/dsterm",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
"bin": {
|
|
4
|
+
"dsterm": "./bin/dsterm.exe",
|
|
5
|
+
"dst": "./bin/dsterm.exe"
|
|
6
|
+
},
|
|
7
|
+
"scripts": {
|
|
8
|
+
"postinstall": "node ./postinstall.mjs"
|
|
9
|
+
},
|
|
10
|
+
"version": "0.1.0-alpha.2",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"os": [
|
|
13
|
+
"darwin",
|
|
14
|
+
"linux",
|
|
15
|
+
"win32"
|
|
16
|
+
],
|
|
17
|
+
"cpu": [
|
|
18
|
+
"arm64",
|
|
19
|
+
"x64"
|
|
20
|
+
],
|
|
21
|
+
"optionalDependencies": {
|
|
22
|
+
"dsterm-darwin-arm64": "0.1.0-alpha.2"
|
|
23
|
+
}
|
|
6
24
|
}
|
package/postinstall.mjs
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import childProcess from "node:child_process"
|
|
4
|
+
import fs from "node:fs"
|
|
5
|
+
import os from "node:os"
|
|
6
|
+
import path from "node:path"
|
|
7
|
+
import { createRequire } from "node:module"
|
|
8
|
+
import { fileURLToPath } from "node:url"
|
|
9
|
+
|
|
10
|
+
const directory = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const require = createRequire(import.meta.url)
|
|
12
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(directory, "package.json"), "utf8"))
|
|
13
|
+
const command = Object.keys(packageJson.bin ?? {})[0]
|
|
14
|
+
if (!command) throw new Error("dsterm package does not declare a binary")
|
|
15
|
+
const sourceCommand = packageJson.opencodeSourceBinary ?? command
|
|
16
|
+
|
|
17
|
+
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[os.platform()] ?? os.platform()
|
|
18
|
+
const nodeArch = { x64: "x64", arm64: "arm64", arm: "arm" }[os.arch()] ?? os.arch()
|
|
19
|
+
// x64 Node runs emulated on Windows ARM64, but PROCESSOR_IDENTIFIER still names the host CPU.
|
|
20
|
+
const arch =
|
|
21
|
+
platform === "windows" && nodeArch === "x64" && process.env.PROCESSOR_IDENTIFIER?.startsWith("ARM")
|
|
22
|
+
? "arm64"
|
|
23
|
+
: nodeArch
|
|
24
|
+
// Windows cannot spawn npm's .cmd shim directly, so reuse the npm CLI that runs this script.
|
|
25
|
+
const npm = process.env.npm_execpath?.endsWith("npm-cli.js") ? [process.execPath, process.env.npm_execpath] : ["npm"]
|
|
26
|
+
const sourceBinary = platform === "windows" ? `${sourceCommand}.exe` : sourceCommand
|
|
27
|
+
const targetBinary = path.resolve(directory, packageJson.bin[command])
|
|
28
|
+
const dependencies = packageJson.optionalDependencies ?? {}
|
|
29
|
+
const base = Object.keys(dependencies).find((name) => name.endsWith(`-${platform}-${arch}`))
|
|
30
|
+
if (!base) throw new Error(`dsterm does not provide a binary for ${platform}-${arch}`)
|
|
31
|
+
|
|
32
|
+
function supportsAvx2() {
|
|
33
|
+
if (arch !== "x64") return false
|
|
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
|
+
if (platform === "darwin") {
|
|
42
|
+
try {
|
|
43
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
44
|
+
encoding: "utf8",
|
|
45
|
+
timeout: 1500,
|
|
46
|
+
})
|
|
47
|
+
return result.status === 0 && (result.stdout || "").trim() === "1"
|
|
48
|
+
} catch {
|
|
49
|
+
return false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (platform === "windows") {
|
|
53
|
+
const script =
|
|
54
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
55
|
+
for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
56
|
+
try {
|
|
57
|
+
const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
58
|
+
encoding: "utf8",
|
|
59
|
+
timeout: 3000,
|
|
60
|
+
windowsHide: true,
|
|
61
|
+
})
|
|
62
|
+
if (result.status !== 0) continue
|
|
63
|
+
const output = (result.stdout || "").trim().toLowerCase()
|
|
64
|
+
if (output === "true" || output === "1") return true
|
|
65
|
+
if (output === "false" || output === "0") return false
|
|
66
|
+
} catch {
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isMusl() {
|
|
75
|
+
if (platform !== "linux") return false
|
|
76
|
+
try {
|
|
77
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
78
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
79
|
+
return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
|
|
80
|
+
} catch {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function packageNames() {
|
|
86
|
+
const baseline = arch === "x64" && !supportsAvx2()
|
|
87
|
+
const names =
|
|
88
|
+
platform === "linux"
|
|
89
|
+
? isMusl()
|
|
90
|
+
? arch === "x64"
|
|
91
|
+
? baseline
|
|
92
|
+
? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
93
|
+
: [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
94
|
+
: [`${base}-musl`, base]
|
|
95
|
+
: arch === "x64"
|
|
96
|
+
? baseline
|
|
97
|
+
? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
98
|
+
: [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
99
|
+
: [base, `${base}-musl`]
|
|
100
|
+
: arch === "x64"
|
|
101
|
+
? baseline
|
|
102
|
+
? [`${base}-baseline`, base]
|
|
103
|
+
: [base, `${base}-baseline`]
|
|
104
|
+
: [base]
|
|
105
|
+
// Windows 11 on ARM64 can still run the x64 binary under emulation when the native one fails.
|
|
106
|
+
const x64 = base.replace(/-arm64$/, "-x64")
|
|
107
|
+
const emulated = platform === "windows" && arch === "arm64" ? [`${x64}-baseline`, x64] : []
|
|
108
|
+
return [...names, ...emulated].filter((name) => dependencies[name])
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function copyBinary(source) {
|
|
112
|
+
if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
|
|
113
|
+
fs.mkdirSync(path.dirname(targetBinary), { recursive: true })
|
|
114
|
+
if (fs.existsSync(targetBinary)) {
|
|
115
|
+
try {
|
|
116
|
+
fs.unlinkSync(targetBinary)
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
fs.linkSync(source, targetBinary)
|
|
121
|
+
} catch {
|
|
122
|
+
fs.copyFileSync(source, targetBinary)
|
|
123
|
+
}
|
|
124
|
+
fs.chmodSync(targetBinary, 0o755)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function resolveBinary(name) {
|
|
128
|
+
const packagePath = require.resolve(`${name}/package.json`)
|
|
129
|
+
// Package managers keep an older platform package when the matching version is not yet on the registry,
|
|
130
|
+
// which would silently install the previous release under the new launcher.
|
|
131
|
+
const version = JSON.parse(fs.readFileSync(packagePath, "utf8")).version
|
|
132
|
+
if (version !== dependencies[name]) throw new Error(`${name} is ${version}, expected ${dependencies[name]}`)
|
|
133
|
+
return path.join(path.dirname(packagePath), "bin", sourceBinary)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function installPackage(name) {
|
|
137
|
+
const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
|
|
138
|
+
try {
|
|
139
|
+
const result = childProcess.spawnSync(
|
|
140
|
+
npm[0],
|
|
141
|
+
[
|
|
142
|
+
...npm.slice(1),
|
|
143
|
+
"install",
|
|
144
|
+
"--ignore-scripts",
|
|
145
|
+
"--no-save",
|
|
146
|
+
"--loglevel=error",
|
|
147
|
+
// npm rejects a package built for another CPU, such as arm64 under emulated x64 Node, unless forced.
|
|
148
|
+
...(name.includes(`-${platform}-${nodeArch}`) ? [] : ["--force"]),
|
|
149
|
+
"--prefix",
|
|
150
|
+
temp,
|
|
151
|
+
`${name}@${dependencies[name]}`,
|
|
152
|
+
],
|
|
153
|
+
{ stdio: "inherit", windowsHide: true },
|
|
154
|
+
)
|
|
155
|
+
if (result.status !== 0) return false
|
|
156
|
+
copyBinary(path.join(temp, "node_modules", name, "bin", sourceBinary))
|
|
157
|
+
return true
|
|
158
|
+
} finally {
|
|
159
|
+
fs.rmSync(temp, { recursive: true, force: true })
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function verifyBinary() {
|
|
164
|
+
return (
|
|
165
|
+
childProcess.spawnSync(targetBinary, ["--version"], {
|
|
166
|
+
stdio: "ignore",
|
|
167
|
+
windowsHide: true,
|
|
168
|
+
}).status === 0
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function main() {
|
|
173
|
+
const names = packageNames()
|
|
174
|
+
for (const name of names) {
|
|
175
|
+
try {
|
|
176
|
+
copyBinary(resolveBinary(name))
|
|
177
|
+
if (verifyBinary()) return
|
|
178
|
+
} catch {
|
|
179
|
+
if (installPackage(name) && verifyBinary()) return
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Failed to install dsterm. Try manually installing ${names.map((name) => JSON.stringify(name)).join(" or ")}.`,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
main()
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
192
|
+
process.exit(1)
|
|
193
|
+
}
|
package/README.md
DELETED