lucentracode 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 opencode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # LucentraCode
2
+
3
+ AI coding agent for the terminal, powered by the LucentraCode gateway.
4
+
5
+ ```bash
6
+ npm install -g lucentracode
7
+ lucentracode login # opens your browser to authorise this terminal
8
+ cd my-project && lucentracode
9
+ ```
10
+
11
+ `login` opens the [LucentraCode dashboard](https://lucencode-dashboard.azurewebsites.net),
12
+ you click **Authorize**, and the CLI receives its own API key. You never type or
13
+ paste a credential.
14
+
15
+ ## What you get
16
+
17
+ A terminal coding agent: repository exploration, grep and glob, file reads, edits
18
+ and patches, shell execution, test runs, tool calling with a permission prompt,
19
+ plan mode, subagents, context compaction, and MCP.
20
+
21
+ The default model is **Smart Auto**, which routes each request to a model chosen
22
+ for the task. `lucentracode models` lists the catalogue if you want to pin one.
23
+
24
+ ## Usage and limits
25
+
26
+ ```bash
27
+ lucentracode usage # allowance used, as a percentage
28
+ lucentracode status # account, gateway, plan
29
+ lucentracode dashboard # open the dashboard
30
+ lucentracode logout
31
+ ```
32
+
33
+ ## Install notes
34
+
35
+ This package contains no binary. On install it pulls the one
36
+ `lucentracode-<os>-<arch>` package that matches your machine, so you download one
37
+ platform's worth of bytes rather than all of them.
38
+
39
+ If you install with `--ignore-scripts` (or with pnpm, which defaults to that),
40
+ run the postinstall by hand:
41
+
42
+ ```bash
43
+ cd node_modules/lucentracode && node postinstall.mjs
44
+ ```
45
+
46
+ ## Licence and attribution
47
+
48
+ MIT. LucentraCode is a fork of [OpenCode](https://github.com/anomalyco/opencode).
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+ echo "Error: lucentracode's postinstall script did not run." >&2
3
+ echo "" >&2
4
+ echo "This happens with --ignore-scripts, and with package managers such as pnpm" >&2
5
+ echo "that do not run postinstall scripts by default." >&2
6
+ echo "" >&2
7
+ echo "Fix it by running:" >&2
8
+ echo " cd node_modules/lucentracode && node postinstall.mjs" >&2
9
+ echo "" >&2
10
+ echo "Or reinstall without --ignore-scripts." >&2
11
+ exit 1
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "lucentracode",
3
+ "version": "0.1.0",
4
+ "description": "AI coding agent for the terminal, powered by the LucentraCode gateway.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/aryanbains/lucencode-cli.git"
9
+ },
10
+ "homepage": "https://github.com/aryanbains/lucencode-cli",
11
+ "bugs": {
12
+ "url": "https://github.com/aryanbains/lucencode-cli/issues"
13
+ },
14
+ "keywords": [
15
+ "ai",
16
+ "cli",
17
+ "coding-agent",
18
+ "terminal",
19
+ "tui",
20
+ "llm",
21
+ "lucentracode"
22
+ ],
23
+ "bin": {
24
+ "lucentracode": "./bin/lucentracode.exe"
25
+ },
26
+ "scripts": {
27
+ "postinstall": "node ./postinstall.mjs"
28
+ },
29
+ "os": [
30
+ "darwin",
31
+ "linux",
32
+ "win32"
33
+ ],
34
+ "cpu": [
35
+ "arm64",
36
+ "x64"
37
+ ],
38
+ "optionalDependencies": {
39
+ "lucentracode-windows-x64-baseline": "0.1.0",
40
+ "lucentracode-windows-x64": "0.1.0",
41
+ "lucentracode-windows-arm64": "0.1.0",
42
+ "lucentracode-linux-x64-musl": "0.1.0",
43
+ "lucentracode-linux-x64-baseline-musl": "0.1.0",
44
+ "lucentracode-linux-x64-baseline": "0.1.0",
45
+ "lucentracode-linux-x64": "0.1.0",
46
+ "lucentracode-linux-arm64-musl": "0.1.0",
47
+ "lucentracode-linux-arm64": "0.1.0",
48
+ "lucentracode-darwin-x64-baseline": "0.1.0",
49
+ "lucentracode-darwin-x64": "0.1.0",
50
+ "lucentracode-darwin-arm64": "0.1.0"
51
+ }
52
+ }
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Installed as `postinstall.mjs` inside the published `lucentracode` package.
4
+ //
5
+ // LucentraCode fork of script/postinstall.mjs. It is a separate file rather than an
6
+ // edit because the upstream one is still used by upstream's own release path, and
7
+ // because every identifier in here is a published package name -- a merge that
8
+ // silently reverted `lucentracode-linux-x64` to `opencode-linux-x64` would make our
9
+ // installer pull a different product's binary. Keeping them apart makes that
10
+ // impossible rather than merely unlikely.
11
+ //
12
+ // What it does: npm has already installed whichever `lucentracode-<platform>-<arch>`
13
+ // optional dependency matches this machine. This finds it and hard-links (or
14
+ // copies) the real binary over the placeholder shim at bin/lucentracode.exe.
15
+
16
+ import childProcess from "child_process"
17
+ import fs from "fs"
18
+ import os from "os"
19
+ import path from "path"
20
+ import { createRequire } from "module"
21
+ import { fileURLToPath } from "url"
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
24
+ const require = createRequire(import.meta.url)
25
+ const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"))
26
+
27
+ const PRODUCT = "lucentracode"
28
+
29
+ const platformMap = {
30
+ darwin: "darwin",
31
+ linux: "linux",
32
+ win32: "windows",
33
+ }
34
+ const archMap = {
35
+ x64: "x64",
36
+ arm64: "arm64",
37
+ arm: "arm",
38
+ }
39
+
40
+ const platform = platformMap[os.platform()] ?? os.platform()
41
+ const arch = archMap[os.arch()] ?? os.arch()
42
+ const base = `${PRODUCT}-${platform}-${arch}`
43
+ const sourceBinary = platform === "windows" ? `${PRODUCT}.exe` : PRODUCT
44
+ // Always `.exe`, on every platform. The published `bin` entry has to point at a
45
+ // path that exists before this script runs, and the same path afterwards; using one
46
+ // name everywhere means there is exactly one thing to replace. npm sets the
47
+ // executable bit from the bin field regardless of the extension.
48
+ const targetBinary = path.join(__dirname, "bin", `${PRODUCT}.exe`)
49
+
50
+ // AVX2 detection. Bun's default x64 build assumes AVX2; on a CPU without it the
51
+ // binary dies with an illegal instruction and no useful message, so pre-~2013
52
+ // hardware needs the `-baseline` variant instead.
53
+ function supportsAvx2() {
54
+ if (arch !== "x64") return false
55
+
56
+ if (platform === "linux") {
57
+ try {
58
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
59
+ } catch {
60
+ return false
61
+ }
62
+ }
63
+
64
+ if (platform === "darwin") {
65
+ try {
66
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
67
+ encoding: "utf8",
68
+ timeout: 1500,
69
+ })
70
+ if (result.status !== 0) return false
71
+ return (result.stdout || "").trim() === "1"
72
+ } catch {
73
+ return false
74
+ }
75
+ }
76
+
77
+ if (platform === "windows") {
78
+ const command =
79
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
80
+
81
+ for (const executable of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
82
+ try {
83
+ const result = childProcess.spawnSync(executable, ["-NoProfile", "-NonInteractive", "-Command", command], {
84
+ encoding: "utf8",
85
+ timeout: 3000,
86
+ windowsHide: true,
87
+ })
88
+ if (result.status !== 0) continue
89
+ const output = (result.stdout || "").trim().toLowerCase()
90
+ if (output === "true" || output === "1") return true
91
+ if (output === "false" || output === "0") return false
92
+ } catch {
93
+ continue
94
+ }
95
+ }
96
+ }
97
+
98
+ return false
99
+ }
100
+
101
+ // Alpine and other musl distros need a musl-linked binary; a glibc one fails at
102
+ // load time with an error that mentions neither libc nor LucentraCode.
103
+ function isMusl() {
104
+ if (platform !== "linux") return false
105
+
106
+ try {
107
+ if (fs.existsSync("/etc/alpine-release")) return true
108
+ } catch {
109
+ // Ignore filesystem probes that are blocked by the host.
110
+ }
111
+
112
+ try {
113
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
114
+ return `${result.stdout || ""}${result.stderr || ""}`.toLowerCase().includes("musl")
115
+ } catch {
116
+ return false
117
+ }
118
+ }
119
+
120
+ // Ordered best-first, with fallbacks. Detection can be wrong -- a container may
121
+ // hide /proc/cpuinfo, `ldd` may be absent -- so a wrong guess degrades to trying
122
+ // the next candidate instead of failing the install.
123
+ function packageNames() {
124
+ const baseline = arch === "x64" && !supportsAvx2()
125
+
126
+ if (platform === "linux") {
127
+ if (isMusl()) {
128
+ if (arch === "x64")
129
+ return baseline
130
+ ? [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
131
+ : [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
132
+ return [`${base}-musl`, base]
133
+ }
134
+
135
+ if (arch === "x64")
136
+ return baseline
137
+ ? [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
138
+ : [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
139
+ return [base, `${base}-musl`]
140
+ }
141
+
142
+ if (arch === "x64") return baseline ? [`${base}-baseline`, base] : [base, `${base}-baseline`]
143
+ return [base]
144
+ }
145
+
146
+ function resolveBinary(name) {
147
+ const packageJsonPath = require.resolve(`${name}/package.json`)
148
+ const binaryPath = path.join(path.dirname(packageJsonPath), "bin", sourceBinary)
149
+ if (!fs.existsSync(binaryPath)) throw new Error(`Binary not found at ${binaryPath}`)
150
+ return binaryPath
151
+ }
152
+
153
+ // pnpm and yarn PnP sometimes do not place optional dependencies where
154
+ // require.resolve can see them. Rather than fail, fetch the one package we need
155
+ // into a temp prefix and take the binary out of it.
156
+ function installPackage(name) {
157
+ const version = packageJson.optionalDependencies?.[name]
158
+ if (!version) return
159
+
160
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), `${PRODUCT}-install-`))
161
+ try {
162
+ const result = childProcess.spawnSync(
163
+ "npm",
164
+ ["install", "--ignore-scripts", "--no-save", "--loglevel=error", "--prefix", temp, `${name}@${version}`],
165
+ { stdio: "inherit", windowsHide: true },
166
+ )
167
+ if (result.status !== 0) return
168
+ const packageDir = path.join(temp, "node_modules", name)
169
+ copyBinary(path.join(packageDir, "bin", sourceBinary), targetBinary)
170
+ return true
171
+ } finally {
172
+ fs.rmSync(temp, { recursive: true, force: true })
173
+ }
174
+ }
175
+
176
+ function copyBinary(source, target) {
177
+ if (!fs.existsSync(source)) throw new Error(`Binary not found at ${source}`)
178
+ fs.mkdirSync(path.dirname(target), { recursive: true })
179
+ if (fs.existsSync(target)) fs.unlinkSync(target)
180
+ try {
181
+ // A hard link avoids a second ~140 MB on disk. Falls back to a copy when the
182
+ // store and the project are on different filesystems.
183
+ fs.linkSync(source, target)
184
+ } catch {
185
+ fs.copyFileSync(source, target)
186
+ }
187
+ fs.chmodSync(target, 0o755)
188
+ }
189
+
190
+ // Actually run it. A binary that is present but cannot execute -- wrong libc,
191
+ // wrong instruction set, truncated download -- must fall through to the next
192
+ // candidate rather than be declared installed.
193
+ function verifyBinary() {
194
+ const result = childProcess.spawnSync(targetBinary, ["--version"], {
195
+ encoding: "utf8",
196
+ stdio: "ignore",
197
+ windowsHide: true,
198
+ })
199
+ return result.status === 0
200
+ }
201
+
202
+ function main() {
203
+ for (const name of packageNames()) {
204
+ try {
205
+ copyBinary(resolveBinary(name), targetBinary)
206
+ if (verifyBinary()) return
207
+ } catch {
208
+ if (installPackage(name) && verifyBinary()) return
209
+ }
210
+ }
211
+
212
+ throw new Error(
213
+ `Your package manager did not install a matching LucentraCode binary. Try installing ${packageNames()
214
+ .map((name) => JSON.stringify(name))
215
+ .join(" or ")} manually, or report this at https://github.com/aryanbains/lucencode-cli/issues with your OS and CPU architecture.`,
216
+ )
217
+ }
218
+
219
+ try {
220
+ main()
221
+ } catch (error) {
222
+ console.error(error.message)
223
+ process.exit(1)
224
+ }