lucentracode 0.2.5 → 0.2.9

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 (2) hide show
  1. package/bin/lucentracode.js +227 -227
  2. package/package.json +13 -13
@@ -1,227 +1,227 @@
1
- #!/usr/bin/env node
2
- "use strict"
3
-
4
- // Shipped as `bin/lucentracode.js` inside the published `lucentracode` package, and it
5
- // is the package's only `bin` entry.
6
- //
7
- // WHY A LAUNCHER INSTEAD OF A POSTINSTALL
8
- //
9
- // The first release used the conventional trick: ship a placeholder at the `bin` path
10
- // and have a postinstall script overwrite it with the real platform binary. That is
11
- // broken on current npm and cannot be fixed from the package side.
12
- //
13
- // npm made install scripts opt-in (npm 11.10) and off by default (npm 12), so
14
- // `postinstall` simply does not run. The package then presents a placeholder as its
15
- // executable. Ours began `#!/bin/sh`, so npm generated a Windows shim that invoked
16
- // `/bin/sh` and users got:
17
- //
18
- // The term '/bin/sh.exe' is not recognized...
19
- //
20
- // And there is no recovery path for a global install: the warning npm prints tells the
21
- // user to run `npm approve-scripts`, which refuses global installs with EGLOBAL
22
- // (npm/cli#9463).
23
- //
24
- // So resolution moved from install time to run time. This file is plain CommonJS with a
25
- // node shebang, which means npm generates an ordinary `node`-invoking shim on every
26
- // platform, and the package declares no install scripts at all -- nothing to approve,
27
- // nothing to block, no warning.
28
- //
29
- // The cost is one Node process in front of the binary. That is the price of an install
30
- // that works, and it is what esbuild and friends settled on for the same reason.
31
-
32
- const { spawnSync } = require("child_process")
33
- const fs = require("fs")
34
- const os = require("os")
35
- const path = require("path")
36
-
37
- const PRODUCT = "lucentracode"
38
-
39
- const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
40
- const archMap = { x64: "x64", arm64: "arm64" }
41
-
42
- const platform = platformMap[os.platform()] || os.platform()
43
- const arch = archMap[os.arch()] || os.arch()
44
- const base = `${PRODUCT}-${platform}-${arch}`
45
- const binaryName = platform === "windows" ? `${PRODUCT}.exe` : PRODUCT
46
-
47
- // Bun's default x64 build assumes AVX2. On a CPU without it the binary dies with an
48
- // illegal instruction and no explanation, so pre-~2013 hardware needs `-baseline`.
49
- //
50
- // This detection is why the choice cannot be left to npm: `package.json` has no field
51
- // meaning "requires AVX2" -- only `os` and `cpu`, which both x64 variants declare
52
- // identically. npm therefore installs both and the decision lands here.
53
- function supportsAvx2() {
54
- if (arch !== "x64") return false
55
-
56
- try {
57
- if (platform === "linux") {
58
- return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
59
- }
60
-
61
- if (platform === "darwin") {
62
- const r = spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], { encoding: "utf8", timeout: 1500 })
63
- return r.status === 0 && (r.stdout || "").trim() === "1"
64
- }
65
-
66
- if (platform === "windows") {
67
- // PF_AVX2_INSTRUCTIONS_AVAILABLE == 40
68
- const command =
69
- '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name K32 -Namespace W32 -PassThru)::IsProcessorFeaturePresent(40)'
70
- for (const exe of ["powershell.exe", "pwsh.exe"]) {
71
- const r = spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", command], {
72
- encoding: "utf8",
73
- timeout: 3000,
74
- windowsHide: true,
75
- })
76
- if (r.status !== 0) continue
77
- const out = (r.stdout || "").trim().toLowerCase()
78
- if (out === "true") return true
79
- if (out === "false") return false
80
- }
81
- }
82
- } catch {
83
- // Detection is best-effort; a failure falls through to the safe answer below.
84
- }
85
-
86
- // Unknown means "assume the older CPU": a baseline binary runs everywhere, while an
87
- // AVX2 binary on a pre-AVX2 chip crashes with no usable message.
88
- return false
89
- }
90
-
91
- // Alpine and other musl distros need a musl-linked build; a glibc one fails at load
92
- // with an error naming neither libc nor the product.
93
- function isMusl() {
94
- if (platform !== "linux") return false
95
- try {
96
- if (fs.existsSync("/etc/alpine-release")) return true
97
- } catch {
98
- /* probing may be blocked; fall through */
99
- }
100
- try {
101
- const r = spawnSync("ldd", ["--version"], { encoding: "utf8" })
102
- return `${r.stdout || ""}${r.stderr || ""}`.toLowerCase().includes("musl")
103
- } catch {
104
- return false
105
- }
106
- }
107
-
108
- // Ordered best-first. Detection can be wrong -- a container may hide /proc/cpuinfo,
109
- // `ldd` may be absent -- so a bad guess falls through to the next candidate instead of
110
- // failing outright.
111
- function candidates() {
112
- const baseline = arch === "x64" && !supportsAvx2()
113
-
114
- if (platform === "linux") {
115
- if (isMusl()) {
116
- if (arch === "x64") {
117
- return baseline
118
- ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
119
- : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
120
- }
121
- return [`${base}-musl`, base]
122
- }
123
- if (arch === "x64") {
124
- return baseline
125
- ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
126
- : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
127
- }
128
- return [base, `${base}-musl`]
129
- }
130
-
131
- if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
132
- return [base]
133
- }
134
-
135
- function resolveBinary() {
136
- const tried = []
137
- for (const name of candidates()) {
138
- try {
139
- const pkgJson = require.resolve(`${name}/package.json`)
140
- const candidate = path.join(path.dirname(pkgJson), "bin", binaryName)
141
- if (fs.existsSync(candidate)) return candidate
142
- tried.push(`${name} (installed, but ${binaryName} missing)`)
143
- } catch {
144
- tried.push(`${name} (not installed)`)
145
- }
146
- }
147
- return { error: tried }
148
- }
149
-
150
- const resolved = resolveBinary()
151
-
152
- if (typeof resolved !== "string") {
153
- const lines = [
154
- `${PRODUCT}: no binary for your platform (${os.platform()} ${os.arch()}).`,
155
- "",
156
- "Looked for:",
157
- ...resolved.error.map((t) => ` - ${t}`),
158
- "",
159
- "This usually means the install was partial. Try:",
160
- ` npm install -g ${PRODUCT} --force`,
161
- "",
162
- `If it persists, report it with your OS and CPU at`,
163
- ` https://github.com/aryanbains/lucencode-cli/issues`,
164
- ]
165
- process.stderr.write(lines.join("\n") + "\n")
166
- process.exit(1)
167
- }
168
-
169
- // Make sure the binary is actually executable before trying to run it.
170
- //
171
- // It frequently is not. These packages are built and published from Windows, which has
172
- // no POSIX permission bits, so npm records mode 0644 in the tar header and every macOS
173
- // and Linux install extracts a binary it is not allowed to execute:
174
- //
175
- // spawnSync .../bin/lucentracode EACCES
176
- //
177
- // Fixing it at pack time would mean the release only ever being publishable from a
178
- // POSIX machine -- a rule that holds until the day someone publishes from a laptop.
179
- // Fixing it here makes the tar mode irrelevant, which is the property worth having.
180
- function ensureExecutable(file) {
181
- if (platform === "windows") return null
182
- try {
183
- const mode = fs.statSync(file).mode
184
- if (mode & 0o111) return null
185
- fs.chmodSync(file, (mode & 0o7777) | 0o755)
186
- return null
187
- } catch (err) {
188
- // A read-only or root-owned install directory. Report it rather than failing with
189
- // a bare EACCES, because the fix is one command and the user cannot guess it.
190
- return err
191
- }
192
- }
193
-
194
- const chmodError = ensureExecutable(resolved)
195
-
196
- // `stdio: "inherit"` hands the real terminal to the child, which the TUI requires: it
197
- // needs a genuine TTY for raw mode, resize events and colour. It also means the
198
- // terminal delivers Ctrl+C to the foreground process group, so the child sees the
199
- // signal directly rather than depending on the parent to relay it.
200
- const result = spawnSync(resolved, process.argv.slice(2), { stdio: "inherit", windowsHide: false })
201
-
202
- if (result.error) {
203
- const lines = [`${PRODUCT}: could not start the binary.`, ` ${resolved}`, ``, `${result.error.message}`]
204
- if (result.error.code === "EACCES") {
205
- lines.push(
206
- ``,
207
- `The binary is not marked executable.` +
208
- (chmodError ? ` Making it executable failed: ${chmodError.message}` : ``),
209
- ``,
210
- `Fix it with:`,
211
- ` chmod +x ${resolved}`,
212
- ``,
213
- `If that is denied, reinstall somewhere you own, or use sudo for the chmod.`,
214
- )
215
- }
216
- process.stderr.write(lines.join("\n") + "\n")
217
- process.exit(1)
218
- }
219
-
220
- // Report a signal death as a signal death (128+n), the way a shell does, so wrappers
221
- // and CI can tell "interrupted" from "exited non-zero".
222
- if (result.signal) {
223
- const signals = { SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15, SIGHUP: 1 }
224
- process.exit(128 + (signals[result.signal] || 0))
225
- }
226
-
227
- process.exit(result.status === null ? 1 : result.status)
1
+ #!/usr/bin/env node
2
+ "use strict"
3
+
4
+ // Shipped as `bin/lucentracode.js` inside the published `lucentracode` package, and it
5
+ // is the package's only `bin` entry.
6
+ //
7
+ // WHY A LAUNCHER INSTEAD OF A POSTINSTALL
8
+ //
9
+ // The first release used the conventional trick: ship a placeholder at the `bin` path
10
+ // and have a postinstall script overwrite it with the real platform binary. That is
11
+ // broken on current npm and cannot be fixed from the package side.
12
+ //
13
+ // npm made install scripts opt-in (npm 11.10) and off by default (npm 12), so
14
+ // `postinstall` simply does not run. The package then presents a placeholder as its
15
+ // executable. Ours began `#!/bin/sh`, so npm generated a Windows shim that invoked
16
+ // `/bin/sh` and users got:
17
+ //
18
+ // The term '/bin/sh.exe' is not recognized...
19
+ //
20
+ // And there is no recovery path for a global install: the warning npm prints tells the
21
+ // user to run `npm approve-scripts`, which refuses global installs with EGLOBAL
22
+ // (npm/cli#9463).
23
+ //
24
+ // So resolution moved from install time to run time. This file is plain CommonJS with a
25
+ // node shebang, which means npm generates an ordinary `node`-invoking shim on every
26
+ // platform, and the package declares no install scripts at all -- nothing to approve,
27
+ // nothing to block, no warning.
28
+ //
29
+ // The cost is one Node process in front of the binary. That is the price of an install
30
+ // that works, and it is what esbuild and friends settled on for the same reason.
31
+
32
+ const { spawnSync } = require("child_process")
33
+ const fs = require("fs")
34
+ const os = require("os")
35
+ const path = require("path")
36
+
37
+ const PRODUCT = "lucentracode"
38
+
39
+ const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" }
40
+ const archMap = { x64: "x64", arm64: "arm64" }
41
+
42
+ const platform = platformMap[os.platform()] || os.platform()
43
+ const arch = archMap[os.arch()] || os.arch()
44
+ const base = `${PRODUCT}-${platform}-${arch}`
45
+ const binaryName = platform === "windows" ? `${PRODUCT}.exe` : PRODUCT
46
+
47
+ // Bun's default x64 build assumes AVX2. On a CPU without it the binary dies with an
48
+ // illegal instruction and no explanation, so pre-~2013 hardware needs `-baseline`.
49
+ //
50
+ // This detection is why the choice cannot be left to npm: `package.json` has no field
51
+ // meaning "requires AVX2" -- only `os` and `cpu`, which both x64 variants declare
52
+ // identically. npm therefore installs both and the decision lands here.
53
+ function supportsAvx2() {
54
+ if (arch !== "x64") return false
55
+
56
+ try {
57
+ if (platform === "linux") {
58
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
59
+ }
60
+
61
+ if (platform === "darwin") {
62
+ const r = spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], { encoding: "utf8", timeout: 1500 })
63
+ return r.status === 0 && (r.stdout || "").trim() === "1"
64
+ }
65
+
66
+ if (platform === "windows") {
67
+ // PF_AVX2_INSTRUCTIONS_AVAILABLE == 40
68
+ const command =
69
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name K32 -Namespace W32 -PassThru)::IsProcessorFeaturePresent(40)'
70
+ for (const exe of ["powershell.exe", "pwsh.exe"]) {
71
+ const r = spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", command], {
72
+ encoding: "utf8",
73
+ timeout: 3000,
74
+ windowsHide: true,
75
+ })
76
+ if (r.status !== 0) continue
77
+ const out = (r.stdout || "").trim().toLowerCase()
78
+ if (out === "true") return true
79
+ if (out === "false") return false
80
+ }
81
+ }
82
+ } catch {
83
+ // Detection is best-effort; a failure falls through to the safe answer below.
84
+ }
85
+
86
+ // Unknown means "assume the older CPU": a baseline binary runs everywhere, while an
87
+ // AVX2 binary on a pre-AVX2 chip crashes with no usable message.
88
+ return false
89
+ }
90
+
91
+ // Alpine and other musl distros need a musl-linked build; a glibc one fails at load
92
+ // with an error naming neither libc nor the product.
93
+ function isMusl() {
94
+ if (platform !== "linux") return false
95
+ try {
96
+ if (fs.existsSync("/etc/alpine-release")) return true
97
+ } catch {
98
+ /* probing may be blocked; fall through */
99
+ }
100
+ try {
101
+ const r = spawnSync("ldd", ["--version"], { encoding: "utf8" })
102
+ return `${r.stdout || ""}${r.stderr || ""}`.toLowerCase().includes("musl")
103
+ } catch {
104
+ return false
105
+ }
106
+ }
107
+
108
+ // Ordered best-first. Detection can be wrong -- a container may hide /proc/cpuinfo,
109
+ // `ldd` may be absent -- so a bad guess falls through to the next candidate instead of
110
+ // failing outright.
111
+ function candidates() {
112
+ const baseline = arch === "x64" && !supportsAvx2()
113
+
114
+ if (platform === "linux") {
115
+ if (isMusl()) {
116
+ if (arch === "x64") {
117
+ return baseline
118
+ ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
119
+ : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
120
+ }
121
+ return [`${base}-musl`, base]
122
+ }
123
+ if (arch === "x64") {
124
+ return baseline
125
+ ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
126
+ : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
127
+ }
128
+ return [base, `${base}-musl`]
129
+ }
130
+
131
+ if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
132
+ return [base]
133
+ }
134
+
135
+ function resolveBinary() {
136
+ const tried = []
137
+ for (const name of candidates()) {
138
+ try {
139
+ const pkgJson = require.resolve(`${name}/package.json`)
140
+ const candidate = path.join(path.dirname(pkgJson), "bin", binaryName)
141
+ if (fs.existsSync(candidate)) return candidate
142
+ tried.push(`${name} (installed, but ${binaryName} missing)`)
143
+ } catch {
144
+ tried.push(`${name} (not installed)`)
145
+ }
146
+ }
147
+ return { error: tried }
148
+ }
149
+
150
+ const resolved = resolveBinary()
151
+
152
+ if (typeof resolved !== "string") {
153
+ const lines = [
154
+ `${PRODUCT}: no binary for your platform (${os.platform()} ${os.arch()}).`,
155
+ "",
156
+ "Looked for:",
157
+ ...resolved.error.map((t) => ` - ${t}`),
158
+ "",
159
+ "This usually means the install was partial. Try:",
160
+ ` npm install -g ${PRODUCT} --force`,
161
+ "",
162
+ `If it persists, report it with your OS and CPU at`,
163
+ ` https://github.com/aryanbains/lucencode-cli/issues`,
164
+ ]
165
+ process.stderr.write(lines.join("\n") + "\n")
166
+ process.exit(1)
167
+ }
168
+
169
+ // Make sure the binary is actually executable before trying to run it.
170
+ //
171
+ // It frequently is not. These packages are built and published from Windows, which has
172
+ // no POSIX permission bits, so npm records mode 0644 in the tar header and every macOS
173
+ // and Linux install extracts a binary it is not allowed to execute:
174
+ //
175
+ // spawnSync .../bin/lucentracode EACCES
176
+ //
177
+ // Fixing it at pack time would mean the release only ever being publishable from a
178
+ // POSIX machine -- a rule that holds until the day someone publishes from a laptop.
179
+ // Fixing it here makes the tar mode irrelevant, which is the property worth having.
180
+ function ensureExecutable(file) {
181
+ if (platform === "windows") return null
182
+ try {
183
+ const mode = fs.statSync(file).mode
184
+ if (mode & 0o111) return null
185
+ fs.chmodSync(file, (mode & 0o7777) | 0o755)
186
+ return null
187
+ } catch (err) {
188
+ // A read-only or root-owned install directory. Report it rather than failing with
189
+ // a bare EACCES, because the fix is one command and the user cannot guess it.
190
+ return err
191
+ }
192
+ }
193
+
194
+ const chmodError = ensureExecutable(resolved)
195
+
196
+ // `stdio: "inherit"` hands the real terminal to the child, which the TUI requires: it
197
+ // needs a genuine TTY for raw mode, resize events and colour. It also means the
198
+ // terminal delivers Ctrl+C to the foreground process group, so the child sees the
199
+ // signal directly rather than depending on the parent to relay it.
200
+ const result = spawnSync(resolved, process.argv.slice(2), { stdio: "inherit", windowsHide: false })
201
+
202
+ if (result.error) {
203
+ const lines = [`${PRODUCT}: could not start the binary.`, ` ${resolved}`, ``, `${result.error.message}`]
204
+ if (result.error.code === "EACCES") {
205
+ lines.push(
206
+ ``,
207
+ `The binary is not marked executable.` +
208
+ (chmodError ? ` Making it executable failed: ${chmodError.message}` : ``),
209
+ ``,
210
+ `Fix it with:`,
211
+ ` chmod +x ${resolved}`,
212
+ ``,
213
+ `If that is denied, reinstall somewhere you own, or use sudo for the chmod.`,
214
+ )
215
+ }
216
+ process.stderr.write(lines.join("\n") + "\n")
217
+ process.exit(1)
218
+ }
219
+
220
+ // Report a signal death as a signal death (128+n), the way a shell does, so wrappers
221
+ // and CI can tell "interrupted" from "exited non-zero".
222
+ if (result.signal) {
223
+ const signals = { SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15, SIGHUP: 1 }
224
+ process.exit(128 + (signals[result.signal] || 0))
225
+ }
226
+
227
+ process.exit(result.status === null ? 1 : result.status)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucentracode",
3
- "version": "0.2.5",
3
+ "version": "0.2.9",
4
4
  "description": "AI coding agent for the terminal, powered by the LucentraCode gateway.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -36,17 +36,17 @@
36
36
  "x64"
37
37
  ],
38
38
  "optionalDependencies": {
39
- "lucentracode-windows-x64-baseline": "0.2.5",
40
- "lucentracode-windows-x64": "0.2.5",
41
- "lucentracode-windows-arm64": "0.2.5",
42
- "lucentracode-linux-x64-musl": "0.2.5",
43
- "lucentracode-linux-x64-baseline-musl": "0.2.5",
44
- "lucentracode-linux-x64-baseline": "0.2.5",
45
- "lucentracode-linux-x64": "0.2.5",
46
- "lucentracode-linux-arm64-musl": "0.2.5",
47
- "lucentracode-linux-arm64": "0.2.5",
48
- "lucentracode-darwin-x64-baseline": "0.2.5",
49
- "lucentracode-darwin-x64": "0.2.5",
50
- "lucentracode-darwin-arm64": "0.2.5"
39
+ "lucentracode-windows-x64-baseline": "0.2.9",
40
+ "lucentracode-windows-x64": "0.2.9",
41
+ "lucentracode-windows-arm64": "0.2.9",
42
+ "lucentracode-linux-x64-musl": "0.2.9",
43
+ "lucentracode-linux-x64-baseline-musl": "0.2.9",
44
+ "lucentracode-linux-x64-baseline": "0.2.9",
45
+ "lucentracode-linux-x64": "0.2.9",
46
+ "lucentracode-linux-arm64-musl": "0.2.9",
47
+ "lucentracode-linux-arm64": "0.2.9",
48
+ "lucentracode-darwin-x64-baseline": "0.2.9",
49
+ "lucentracode-darwin-x64": "0.2.9",
50
+ "lucentracode-darwin-arm64": "0.2.9"
51
51
  }
52
52
  }