@deveco-test/deveco-code 0.0.0-test → 0.0.0-test-harness.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.
Files changed (6) hide show
  1. package/CHANGELOG.md +394 -178
  2. package/LICENSE +21 -21
  3. package/README.md +333 -328
  4. package/bin/deveco +206 -206
  5. package/package.json +6 -5
  6. package/postinstall.mjs +316 -217
package/postinstall.mjs CHANGED
@@ -1,217 +1,316 @@
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 scope = packageJson.name && packageJson.name.includes("/") ? packageJson.name.split("/")[0] : "@deveco"
28
- const base = `${scope}/deveco-code-${platform}-${arch}`
29
- const sourceBinary = platform === "windows" ? "deveco.exe" : "deveco"
30
- const targetBinary = path.join(__dirname, "bin", "deveco.exe")
31
-
32
- function supportsAvx2() {
33
- if (arch !== "x64") return false
34
-
35
- if (platform === "linux") {
36
- try {
37
- return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
38
- } catch {
39
- return false
40
- }
41
- }
42
-
43
- if (platform === "darwin") {
44
- try {
45
- const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
46
- encoding: "utf8",
47
- timeout: 1500,
48
- })
49
- if (result.status !== 0) return false
50
- return (result.stdout || "").trim() === "1"
51
- } catch {
52
- return false
53
- }
54
- }
55
-
56
- if (platform === "windows") {
57
- const command =
58
- '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
59
-
60
- for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
61
- try {
62
- const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
63
- encoding: "utf8",
64
- timeout: 3000,
65
- windowsHide: true,
66
- })
67
- if (result.status !== 0) continue
68
- const output = (result.stdout || "").trim().toLowerCase()
69
- if (output === "true" || output === "1") return true
70
- if (output === "false" || output === "0") return false
71
- } catch {
72
- continue
73
- }
74
- }
75
- }
76
-
77
- return false
78
- }
79
-
80
- function isMusl() {
81
- if (platform !== "linux") return false
82
-
83
- try {
84
- if (fs.existsSync("/etc/alpine-release")) return true
85
- } catch {
86
- // Ignore filesystem probes that are blocked by the host.
87
- }
88
-
89
- try {
90
- const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
91
- return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
92
- } catch {
93
- return false
94
- }
95
- }
96
-
97
- function packageNames() {
98
- const baseline = arch === "x64" && !supportsAvx2()
99
-
100
- if (platform === "linux") {
101
- if (isMusl()) {
102
- if (arch === "x64")
103
- return baseline
104
- ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
105
- : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
106
- return [`${base}-musl`, base]
107
- }
108
-
109
- if (arch === "x64")
110
- return baseline
111
- ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
112
- : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
113
- return [base, `${base}-musl`]
114
- }
115
-
116
- if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
117
- return [base]
118
- }
119
-
120
- function resolvePackageDir(name) {
121
- const packageJsonPath = require.resolve(`${name}/package.json`)
122
- return path.dirname(packageJsonPath)
123
- }
124
-
125
- function resolveBinary(name) {
126
- const binaryPath = path.join(resolvePackageDir(name), "bin", sourceBinary)
127
- if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
128
- return binaryPath
129
- }
130
-
131
- function copyDir(src, dst) {
132
- if (!fs.existsSync(dst)) fs.mkdirSync(dst, { recursive: true })
133
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
134
- const srcPath = path.join(src, entry.name)
135
- const dstPath = path.join(dst, entry.name)
136
- if (entry.isDirectory()) {
137
- copyDir(srcPath, dstPath)
138
- } else {
139
- fs.copyFileSync(srcPath, dstPath)
140
- }
141
- }
142
- }
143
-
144
- function copyVendor(packageDir) {
145
- const vendorSrc = path.join(packageDir, "vendor")
146
- const vendorDst = path.join(__dirname, "vendor")
147
- if (fs.existsSync(vendorSrc)) {
148
- copyDir(vendorSrc, vendorDst)
149
- }
150
- }
151
-
152
- function installPackage(name) {
153
- const version = packageJson.optionalDependencies?.[name]
154
- if (!version) return
155
-
156
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
157
- try {
158
- const result = childProcess.spawnSync(
159
- "npm",
160
- ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
161
- { stdio: "inherit", windowsHide: true },
162
- )
163
- if (result.status !== 0) return
164
- const packageDir = path.join(temp, "node_modules", name)
165
- copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
166
- copyVendor(packageDir)
167
- return true
168
- } finally {
169
- fs.rmSync(temp, { recursive: true, force: true })
170
- }
171
- }
172
-
173
- function copyBinary(source, target) {
174
- if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
175
- fs.mkdirSync(path.dirname(target), { recursive: true })
176
- if (fs.existsSync(target)) fs.unlinkSync(target)
177
- try {
178
- fs.linkSync(source, target)
179
- } catch {
180
- fs.copyFileSync(source, target)
181
- }
182
- fs.chmodSync(target, 0o755)
183
- }
184
-
185
- function verifyBinary() {
186
- const result = childProcess.spawnSync(targetBinary, ["--version"], {
187
- encoding: "utf8",
188
- stdio: "ignore",
189
- windowsHide: true,
190
- })
191
- return result.status === 0
192
- }
193
-
194
- function main() {
195
- for (const name of packageNames()) {
196
- try {
197
- copyBinary(resolveBinary(name), targetBinary)
198
- copyVendor(resolvePackageDir(name))
199
- if (verifyBinary()) return
200
- } catch {
201
- if (installPackage(name) && verifyBinary()) return
202
- }
203
- }
204
-
205
- throw new Error(
206
- `It seems your package manager failed to install the right deveco-code package. Try manually installing ${packageNames()
207
- .map((name) => JSON.stringify(name))
208
- .join(" or ")}.`,
209
- )
210
- }
211
-
212
- try {
213
- main()
214
- } catch (error) {
215
- console.error(error.message)
216
- process.exit(1)
217
- }
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 scope = packageJson.name && packageJson.name.includes("/") ? packageJson.name.split("/")[0] : "@deveco-test"
28
+ const base = `${scope}/deveco-code-${platform}-${arch}`
29
+ const sourceBinary = platform === "windows" ? "deveco.exe" : "deveco"
30
+ const targetBinary = path.join(__dirname, "bin", "deveco.exe")
31
+ const devecoHarnessPackageName = "@deveco-test/deveco-harness"
32
+ const homegraphPackageName = "homegraph"
33
+ const HOMEGRAPH_ENTRY_REL = path.join("dist", "bin", "homegraph.js")
34
+
35
+ function resolveVendoredCliEntryInsideHarness(harnessRoot) {
36
+ const cliRoot = path.join(harnessRoot, "vendor", "deveco-cli", "node_modules", "@deveco", "deveco-cli")
37
+ const pkgPath = path.join(cliRoot, "package.json")
38
+ let binEntry
39
+ if (fs.existsSync(pkgPath)) {
40
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"))
41
+ binEntry = pkg.bin?.devecocli
42
+ }
43
+ const candidates = [binEntry, "dist/cli.js", "cli.js"].filter(Boolean)
44
+ for (const rel of candidates) {
45
+ const entry = path.join(cliRoot, rel)
46
+ if (fs.existsSync(entry)) return entry
47
+ }
48
+ return undefined
49
+ }
50
+
51
+ function resolveLocalDevecoCliEntry() {
52
+ const harnessPackageJsonPath = require.resolve(`${devecoHarnessPackageName}/package.json`)
53
+ const harnessRoot = path.dirname(harnessPackageJsonPath)
54
+ const entry = resolveVendoredCliEntryInsideHarness(harnessRoot)
55
+ if (entry) return entry
56
+ throw new Error(
57
+ `Failed to resolve the vendored deveco-cli entry inside "${devecoHarnessPackageName}".`,
58
+ )
59
+ }
60
+
61
+ function writeDevecoCliEntryMarker(installRoot) {
62
+ const marker = path.join(installRoot, "vendor", ".deveco-cli-entry")
63
+ fs.mkdirSync(path.dirname(marker), { recursive: true })
64
+ fs.writeFileSync(marker, `${resolveLocalDevecoCliEntry()}\n`, "utf8")
65
+ }
66
+
67
+ function resolveLocalHomegraphEntry() {
68
+ const packageJsonPath = require.resolve(`${homegraphPackageName}/package.json`)
69
+ const entry = path.join(path.dirname(packageJsonPath), HOMEGRAPH_ENTRY_REL)
70
+ if (fs.existsSync(entry)) return entry
71
+ throw new Error(`Local dependency "${homegraphPackageName}" has no entry at ${entry}.`)
72
+ }
73
+
74
+ function writeHomegraphEntryMarker(installRoot) {
75
+ try {
76
+ const marker = path.join(installRoot, "vendor", ".homegraph-entry")
77
+ fs.mkdirSync(path.dirname(marker), { recursive: true })
78
+ fs.writeFileSync(marker, `${resolveLocalHomegraphEntry()}\n`, "utf8")
79
+ } catch (error) {
80
+ console.warn(`[homegraph] postinstall: ${error instanceof Error ? error.message : String(error)}`)
81
+ }
82
+ }
83
+
84
+ function supportsAvx2() {
85
+ if (arch !== "x64") return false
86
+
87
+ if (platform === "linux") {
88
+ try {
89
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
90
+ } catch {
91
+ return false
92
+ }
93
+ }
94
+
95
+ if (platform === "darwin") {
96
+ try {
97
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
98
+ encoding: "utf8",
99
+ timeout: 1500,
100
+ })
101
+ if (result.status !== 0) return false
102
+ return (result.stdout || "").trim() === "1"
103
+ } catch {
104
+ return false
105
+ }
106
+ }
107
+
108
+ if (platform === "windows") {
109
+ const command =
110
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
111
+
112
+ for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
113
+ try {
114
+ const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
115
+ encoding: "utf8",
116
+ timeout: 3000,
117
+ windowsHide: true,
118
+ })
119
+ if (result.status !== 0) continue
120
+ const output = (result.stdout || "").trim().toLowerCase()
121
+ if (output === "true" || output === "1") return true
122
+ if (output === "false" || output === "0") return false
123
+ } catch {
124
+ continue
125
+ }
126
+ }
127
+ }
128
+
129
+ return false
130
+ }
131
+
132
+ function isMusl() {
133
+ if (platform !== "linux") return false
134
+
135
+ try {
136
+ if (fs.existsSync("/etc/alpine-release")) return true
137
+ } catch {
138
+ // Ignore filesystem probes that are blocked by the host.
139
+ }
140
+
141
+ try {
142
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
143
+ return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
144
+ } catch {
145
+ return false
146
+ }
147
+ }
148
+
149
+ function packageNames() {
150
+ const baseline = arch === "x64" && !supportsAvx2()
151
+
152
+ if (platform === "linux") {
153
+ if (isMusl()) {
154
+ if (arch === "x64")
155
+ return baseline
156
+ ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
157
+ : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
158
+ return [`${base}-musl`, base]
159
+ }
160
+
161
+ if (arch === "x64")
162
+ return baseline
163
+ ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
164
+ : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
165
+ return [base, `${base}-musl`]
166
+ }
167
+
168
+ if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
169
+ return [base]
170
+ }
171
+
172
+ function resolvePackageDir(name) {
173
+ const packageJsonPath = require.resolve(`${name}/package.json`)
174
+ return path.dirname(packageJsonPath)
175
+ }
176
+
177
+ function resolveBinary(name) {
178
+ const binaryPath = path.join(resolvePackageDir(name), "bin", sourceBinary)
179
+ if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
180
+ return binaryPath
181
+ }
182
+
183
+ function copyDir(src, dst) {
184
+ if (!fs.existsSync(dst)) fs.mkdirSync(dst, { recursive: true })
185
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
186
+ const srcPath = path.join(src, entry.name)
187
+ const dstPath = path.join(dst, entry.name)
188
+ if (entry.isDirectory()) {
189
+ copyDir(srcPath, dstPath)
190
+ } else {
191
+ fs.copyFileSync(srcPath, dstPath)
192
+ if (process.platform !== "win32") {
193
+ fs.chmodSync(dstPath, fs.statSync(srcPath).mode)
194
+ }
195
+ }
196
+ }
197
+ }
198
+
199
+ function copyVendor(packageDir) {
200
+ const vendorSrc = path.join(packageDir, "vendor")
201
+ const vendorDst = path.join(__dirname, "vendor")
202
+ if (fs.existsSync(vendorSrc)) {
203
+ copyDir(vendorSrc, vendorDst)
204
+ // Windows packs often drop Unix +x; force it back on macOS/Linux install.
205
+ ensureVendorExecutables(vendorDst)
206
+ ensureVendorExecutables(path.join(packageDir, "vendor"))
207
+ }
208
+ }
209
+
210
+ /** Restore execute bits lost when packages are built/published from Windows. */
211
+ function ensureVendorExecutables(vendorRoot) {
212
+ if (process.platform === "win32" || !fs.existsSync(vendorRoot)) return
213
+
214
+ const stack = [vendorRoot]
215
+ while (stack.length > 0) {
216
+ const dir = stack.pop()
217
+ let entries
218
+ try {
219
+ entries = fs.readdirSync(dir, { withFileTypes: true })
220
+ } catch {
221
+ continue
222
+ }
223
+ for (const entry of entries) {
224
+ const full = path.join(dir, entry.name)
225
+ if (entry.isDirectory()) {
226
+ stack.push(full)
227
+ continue
228
+ }
229
+ if (!entry.isFile()) continue
230
+ // Top-level vendor/ripgrep/rg and nested @vscode/ripgrep*/**/rg
231
+ if (entry.name === "rg") {
232
+ try {
233
+ fs.chmodSync(full, 0o755)
234
+ } catch {
235
+ // Best-effort; ignore files we cannot chmod.
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ function installPackage(name) {
243
+ const version = packageJson.optionalDependencies?.[name]
244
+ if (!version) return
245
+
246
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), "opencode-install-"))
247
+ try {
248
+ const result = childProcess.spawnSync(
249
+ "npm",
250
+ ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
251
+ { stdio: "inherit", windowsHide: true },
252
+ )
253
+ if (result.status !== 0) return
254
+ const packageDir = path.join(temp, "node_modules", name)
255
+ copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
256
+ copyVendor(packageDir)
257
+ writeDevecoCliEntryMarker(packageDir)
258
+ writeHomegraphEntryMarker(packageDir)
259
+ writeHomegraphEntryMarker(__dirname)
260
+ return true
261
+ } finally {
262
+ fs.rmSync(temp, { recursive: true, force: true })
263
+ }
264
+ }
265
+
266
+ function copyBinary(source, target) {
267
+ if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
268
+ fs.mkdirSync(path.dirname(target), { recursive: true })
269
+ if (fs.existsSync(target)) fs.unlinkSync(target)
270
+ try {
271
+ fs.linkSync(source, target)
272
+ } catch {
273
+ fs.copyFileSync(source, target)
274
+ }
275
+ fs.chmodSync(target, 0o755)
276
+ }
277
+
278
+ function verifyBinary() {
279
+ const result = childProcess.spawnSync(targetBinary, ["--version"], {
280
+ encoding: "utf8",
281
+ stdio: "ignore",
282
+ windowsHide: true,
283
+ })
284
+ return result.status === 0
285
+ }
286
+
287
+ function main() {
288
+ writeDevecoCliEntryMarker(__dirname)
289
+ writeHomegraphEntryMarker(__dirname)
290
+
291
+ for (const name of packageNames()) {
292
+ try {
293
+ const packageDir = resolvePackageDir(name)
294
+ copyBinary(resolveBinary(name), targetBinary)
295
+ copyVendor(packageDir)
296
+ writeDevecoCliEntryMarker(packageDir)
297
+ writeHomegraphEntryMarker(packageDir)
298
+ if (verifyBinary()) return
299
+ } catch {
300
+ if (installPackage(name) && verifyBinary()) return
301
+ }
302
+ }
303
+
304
+ throw new Error(
305
+ `It seems your package manager failed to install the right deveco-code package. Try manually installing ${packageNames()
306
+ .map((name) => JSON.stringify(name))
307
+ .join(" or ")}.`,
308
+ )
309
+ }
310
+
311
+ try {
312
+ main()
313
+ } catch (error) {
314
+ console.error(error.message)
315
+ process.exit(1)
316
+ }