xyteeecode 1.0.22 → 1.0.24
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/xyteeecode +157 -66
- package/package.json +166 -19
- package/README.md +0 -127
package/bin/xyteeecode
CHANGED
|
@@ -7,13 +7,126 @@ const os = require("os")
|
|
|
7
7
|
|
|
8
8
|
const forwardedSignals = ["SIGINT", "SIGTERM", "SIGHUP"]
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
// The musl/arm64 standalone is a fixed-address (non-PIE) ELF, so it can only
|
|
11
|
+
// start when the kernel execs it with an absolute PT_INTERP loader. On stock
|
|
12
|
+
// Termux the shipped slot ("/lib/ld-musl-aarch64.so.1") does not exist, and
|
|
13
|
+
// spawning the bundled loader by hand cannot map the non-PIE image either
|
|
14
|
+
// ("Could not find a PHDR: broken executable?" / "Not a valid dynamic
|
|
15
|
+
// program"). The working shape is the same as on Alpine: PT_INTERP resolves to
|
|
16
|
+
// the bundled loader's absolute path. The package postinstall performs that
|
|
17
|
+
// rewrite when it runs (npm 11 skips it unless the package is trusted); this
|
|
18
|
+
// helper re-runs it from the launcher at startup so an interrupted install can
|
|
19
|
+
// never leave the CLI unusable.
|
|
20
|
+
function ensureLoaderInterp(binaryPath, loaderPath) {
|
|
21
|
+
const header = Buffer.alloc(0x40)
|
|
22
|
+
let fd = null
|
|
23
|
+
try {
|
|
24
|
+
fd = fs.openSync(binaryPath, "r+")
|
|
25
|
+
} catch {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
fs.readSync(fd, header, 0, header.length, 0)
|
|
30
|
+
if (
|
|
31
|
+
header.readUInt8(0) !== 0x7f ||
|
|
32
|
+
header.toString("ascii", 1, 4) !== "ELF" ||
|
|
33
|
+
header.readUInt8(4) !== 2
|
|
34
|
+
) {
|
|
35
|
+
return false
|
|
36
|
+
}
|
|
37
|
+
const little = header.readUInt8(5) === 1
|
|
38
|
+
const u16 = (o) => (little ? header.readUInt16LE(o) : header.readUInt16BE(o))
|
|
39
|
+
const u32 = (o) => (little ? header.readUInt32LE(o) : header.readUInt32BE(o))
|
|
40
|
+
const u64 = (o) => (little ? header.readBigUInt64LE(o) : header.readBigUInt64BE(o))
|
|
41
|
+
|
|
42
|
+
const readElf = (pos, len) => {
|
|
43
|
+
const buf = Buffer.alloc(len)
|
|
44
|
+
let off = 0
|
|
45
|
+
while (off < len) {
|
|
46
|
+
const read = fs.readSync(fd, buf, off, len - off, pos + off)
|
|
47
|
+
if (read <= 0) throw new Error("short read")
|
|
48
|
+
off += read
|
|
49
|
+
}
|
|
50
|
+
return buf
|
|
51
|
+
}
|
|
15
52
|
|
|
16
|
-
|
|
53
|
+
const ePhoff = Number(u64(0x20))
|
|
54
|
+
const ePhentsize = u16(0x36)
|
|
55
|
+
const ePhnum = u16(0x38)
|
|
56
|
+
const eShoff = Number(u64(0x28))
|
|
57
|
+
const eShentsize = u16(0x3a)
|
|
58
|
+
const eShnum = u16(0x3c)
|
|
59
|
+
const size = fs.fstatSync(fd).size
|
|
60
|
+
|
|
61
|
+
let interpPhdr = -1
|
|
62
|
+
let interpOffset = -1
|
|
63
|
+
const phdrs = readElf(ePhoff, ePhnum * ePhentsize)
|
|
64
|
+
for (let i = 0; i < ePhnum; i++) {
|
|
65
|
+
const ph = ePhoff + i * ePhentsize
|
|
66
|
+
if (phdrs.readUInt32LE(i * ePhentsize) === 3) {
|
|
67
|
+
interpPhdr = ph
|
|
68
|
+
interpOffset = Number(
|
|
69
|
+
little
|
|
70
|
+
? phdrs.readBigUInt64LE(i * ePhentsize + 8)
|
|
71
|
+
: phdrs.readBigUInt64BE(i * ePhentsize + 8),
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (interpPhdr < 0) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let existing = ""
|
|
80
|
+
if (interpOffset + 1 <= size) {
|
|
81
|
+
const buf = readElf(interpOffset, Math.min(4096, size - interpOffset))
|
|
82
|
+
const end = buf.indexOf(0)
|
|
83
|
+
existing = buf.toString("utf8", 0, end === -1 ? buf.length : end)
|
|
84
|
+
}
|
|
85
|
+
if (existing === loaderPath) {
|
|
86
|
+
return true
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newPath = Buffer.from(loaderPath + "\0", "utf8")
|
|
90
|
+
|
|
91
|
+
// The kernel reads at most PT_INTERP.p_filesz bytes of the interpreter
|
|
92
|
+
// path, so it cannot grow in place (the shipped slot is 24 bytes). Append
|
|
93
|
+
// the full path to the file and retarget the program header at it.
|
|
94
|
+
const newOffset = size
|
|
95
|
+
const buf = Buffer.concat([readElf(0, size), newPath])
|
|
96
|
+
buf.writeBigUInt64LE(BigInt(newOffset), interpPhdr + 8)
|
|
97
|
+
buf.writeBigUInt64LE(BigInt(newPath.length), interpPhdr + 32)
|
|
98
|
+
|
|
99
|
+
// Keep the .interp section header consistent for tools (readelf, etc.).
|
|
100
|
+
for (let i = 0; i < eShnum; i++) {
|
|
101
|
+
const sh = eShoff + i * eShentsize
|
|
102
|
+
const shType = little ? buf.readUInt32LE(sh) : buf.readUInt32BE(sh)
|
|
103
|
+
const shOffset = little
|
|
104
|
+
? Number(buf.readBigUInt64LE(sh + 24))
|
|
105
|
+
: Number(buf.readBigUInt64BE(sh + 24))
|
|
106
|
+
if (shType === 1 && shOffset === interpOffset) {
|
|
107
|
+
buf.writeBigUInt64LE(BigInt(newOffset), sh + 24)
|
|
108
|
+
buf.writeBigUInt64LE(BigInt(newPath.length), sh + 32)
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
fs.writeFileSync(binaryPath, buf)
|
|
114
|
+
fs.fsyncSync(fd)
|
|
115
|
+
return true
|
|
116
|
+
} catch {
|
|
117
|
+
return false
|
|
118
|
+
} finally {
|
|
119
|
+
if (fd !== null) {
|
|
120
|
+
try {
|
|
121
|
+
fs.closeSync(fd)
|
|
122
|
+
} catch {
|
|
123
|
+
// ignore
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function run(target, inheritedEnv) {
|
|
17
130
|
return new Promise((resolve) => {
|
|
18
131
|
const binDir = path.dirname(target)
|
|
19
132
|
// The candidate path looks like ".../xyteeecode-linux-arm64-musl/bin/xyteeecode".
|
|
@@ -30,11 +143,19 @@ function run(target, inheritedEnv, bypassLoader) {
|
|
|
30
143
|
: binDir
|
|
31
144
|
}
|
|
32
145
|
|
|
146
|
+
// process.platform/arch mirror os.platform()/os.arch(); both are checked so
|
|
147
|
+
// the launcher stays scriptable (os is monkeypatchable in node, process
|
|
148
|
+
// fields are monkeypatchable in bundlers like bun).
|
|
149
|
+
const termuxish =
|
|
150
|
+
isTermux() &&
|
|
151
|
+
(os.platform() === "android" || process.platform === "android") &&
|
|
152
|
+
(os.arch() === "arm64" || process.arch === "arm64")
|
|
153
|
+
|
|
33
154
|
// Bun ≥1.4 on Termux/Android aarch64 segfaults in the HTTP event loop
|
|
34
155
|
// because epoll_pwait2() trips Android's seccomp policy (faults instead of
|
|
35
156
|
// returning errno). Disable the syscall there; Bun falls back to
|
|
36
157
|
// epoll_pwait. See oven-sh/bun#32489/#32632.
|
|
37
|
-
if (
|
|
158
|
+
if (termuxish) env.BUN_FEATURE_FLAG_DISABLE_EPOLL_PWAIT2 = "1"
|
|
38
159
|
|
|
39
160
|
// The bundled musl libc uses a stub resolver that reads /etc/resolv.conf
|
|
40
161
|
// and speaks raw UDP to its nameservers. Stock Termux/Android has no
|
|
@@ -46,69 +167,53 @@ function run(target, inheritedEnv, bypassLoader) {
|
|
|
46
167
|
const useDnsShim = !!dnsShim && fs.existsSync(dnsShim)
|
|
47
168
|
|
|
48
169
|
// Stock Termux injects libtermux-exec-ld-preload.so through LD_PRELOAD,
|
|
49
|
-
// which the bundled musl loader cannot load. Only on Termux/Android/arm64
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
// on bionic's exec for the musl PT_INTERP.
|
|
54
|
-
//
|
|
55
|
-
// process.platform/arch mirror os.platform()/os.arch(); both are checked so
|
|
56
|
-
// the launcher stays scriptable (os is monkeypatchable in node, process
|
|
57
|
-
// fields are monkeypatchable in bundlers like bun).
|
|
58
|
-
const loader = isMusl ? path.join(binDir, "ld-musl-aarch64.so.1") : null
|
|
59
|
-
const useLoader =
|
|
60
|
-
!bypassLoader &&
|
|
61
|
-
loader !== null &&
|
|
62
|
-
isTermux() &&
|
|
63
|
-
(os.platform() === "android" || process.platform === "android") &&
|
|
64
|
-
(os.arch() === "arm64" || process.arch === "arm64") &&
|
|
65
|
-
fs.existsSync(loader)
|
|
66
|
-
if (useLoader) {
|
|
170
|
+
// which the bundled musl loader cannot load. Only on Termux/Android/arm64,
|
|
171
|
+
// drop the preload variables (this touches the child environment only,
|
|
172
|
+
// never the user's shell).
|
|
173
|
+
if (termuxish) {
|
|
67
174
|
delete env.LD_PRELOAD
|
|
68
175
|
delete env.LD_PRELOAD_64
|
|
69
176
|
env.LD_LIBRARY_PATH = binDir
|
|
70
177
|
if (useDnsShim) env.LD_PRELOAD = dnsShim
|
|
178
|
+
|
|
179
|
+
// Wire the bundled loader into PT_INTERP and exec the target directly.
|
|
180
|
+
// Stock Termux's /lib does not exist and spawning the loader by hand
|
|
181
|
+
// cannot start the non-PIE image, so this is the only launch path.
|
|
182
|
+
const loader = isMusl ? path.join(binDir, "ld-musl-aarch64.so.1") : null
|
|
183
|
+
if (loader && fs.existsSync(loader) && !ensureLoaderInterp(target, loader)) {
|
|
184
|
+
console.error(
|
|
185
|
+
"xyteeecode: could not wire the bundled musl loader into " +
|
|
186
|
+
target +
|
|
187
|
+
". Reinstall with `npm install -g xyteeecode --allow-scripts` " +
|
|
188
|
+
"and make sure the package directory is writable.",
|
|
189
|
+
)
|
|
190
|
+
process.exit(1)
|
|
191
|
+
}
|
|
71
192
|
} else if (useDnsShim) {
|
|
72
193
|
env.LD_PRELOAD = env.LD_PRELOAD
|
|
73
194
|
? dnsShim + ":" + env.LD_PRELOAD
|
|
74
195
|
: dnsShim
|
|
75
196
|
}
|
|
76
197
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const child = childProcess.spawn(command, args, {
|
|
81
|
-
stdio: ["inherit", "inherit", useLoader ? "pipe" : "inherit"],
|
|
198
|
+
const child = childProcess.spawn(target, process.argv.slice(2), {
|
|
199
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
82
200
|
env,
|
|
83
201
|
})
|
|
84
202
|
|
|
85
|
-
// Keep the loader's diagnostics visible while mirroring them to a buffer:
|
|
86
|
-
// a loader that refuses to start the program (e.g. the fixed load address
|
|
87
|
-
// of the non-PIE build is already taken by the loader's own mapping on
|
|
88
|
-
// some kernels) must trigger a PT_INTERP retry instead of a hard exit.
|
|
89
|
-
let loaderStderr = ""
|
|
90
|
-
if (useLoader && child.stderr) {
|
|
91
|
-
child.stderr.on("data", (chunk) => {
|
|
92
|
-
loaderStderr += chunk
|
|
93
|
-
process.stderr.write(chunk)
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
|
|
97
203
|
let spawned = false
|
|
98
204
|
let exited = false
|
|
99
205
|
|
|
100
206
|
child.on("error", (error) => {
|
|
101
|
-
// exec/execvp can't find the interpreter or the executable itself
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
// loader and libraries for Termux).
|
|
207
|
+
// exec/execvp can't find the interpreter or the executable itself.
|
|
208
|
+
// On Termux this usually means the kernel could not resolve PT_INTERP;
|
|
209
|
+
// surface the real reason and let the caller try the next candidate.
|
|
105
210
|
if (error.code === "ENOENT" && !spawned && !exited) {
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
211
|
+
if (termuxish) {
|
|
212
|
+
console.error(
|
|
213
|
+
"xyteeecode: could not exec " + target + " (missing interpreter " +
|
|
214
|
+
"after wiring the bundled loader). Reinstall with " +
|
|
215
|
+
"`npm install -g xyteeecode --allow-scripts`.",
|
|
216
|
+
)
|
|
112
217
|
}
|
|
113
218
|
resolve(false)
|
|
114
219
|
return
|
|
@@ -145,20 +250,6 @@ function run(target, inheritedEnv, bypassLoader) {
|
|
|
145
250
|
return
|
|
146
251
|
}
|
|
147
252
|
|
|
148
|
-
if (
|
|
149
|
-
!bypassLoader &&
|
|
150
|
-
useLoader &&
|
|
151
|
-
typeof code === "number" &&
|
|
152
|
-
code !== 0 &&
|
|
153
|
-
loaderFatal.test(loaderStderr)
|
|
154
|
-
) {
|
|
155
|
-
// The bundled loader could not start the binary in this environment.
|
|
156
|
-
// Retry the same candidate through its (postinstall-rewritten) PT_INTERP
|
|
157
|
-
// with the same sanitized child environment.
|
|
158
|
-
run(target, env, true)
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
253
|
process.exit(typeof code === "number" ? code : 0)
|
|
163
254
|
})
|
|
164
255
|
})
|
package/package.json
CHANGED
|
@@ -1,29 +1,176 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"version": "1.0.24",
|
|
2
4
|
"name": "xyteeecode",
|
|
3
|
-
"
|
|
4
|
-
"description": "xyteeecode - AI coding agent CLI",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"license": "MIT",
|
|
6
|
-
"homepage": "https://xyteee.com",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"ai",
|
|
9
|
-
"coding",
|
|
10
|
-
"agent",
|
|
11
|
-
"cli",
|
|
12
|
-
"terminal",
|
|
13
|
-
"xyteeecode",
|
|
14
|
-
"llm"
|
|
15
|
-
],
|
|
16
7
|
"files": [
|
|
17
|
-
"bin"
|
|
18
|
-
"README.md"
|
|
8
|
+
"bin"
|
|
19
9
|
],
|
|
20
|
-
"bin": {
|
|
21
|
-
"xyteeecode": "bin/xyteeecode"
|
|
22
|
-
},
|
|
23
10
|
"engines": {
|
|
24
11
|
"node": ">=18"
|
|
25
12
|
},
|
|
26
13
|
"optionalDependencies": {
|
|
27
|
-
"xyteeecode-linux-arm64
|
|
14
|
+
"xyteeecode-linux-arm64": "1.0.14",
|
|
15
|
+
"xyteeecode-linux-x64": "1.0.14",
|
|
16
|
+
"xyteeecode-linux-arm64-musl": "1.0.23",
|
|
17
|
+
"xyteeecode-linux-x64-musl": "1.0.14"
|
|
18
|
+
},
|
|
19
|
+
"trustedDependencies": [
|
|
20
|
+
"xyteeecode-linux-arm64",
|
|
21
|
+
"xyteeecode-linux-x64",
|
|
22
|
+
"xyteeecode-linux-arm64-musl",
|
|
23
|
+
"xyteeecode-linux-x64-musl"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"typecheck": "tsgo --noEmit",
|
|
27
|
+
"test": "bun test --timeout 30000 --only-failures",
|
|
28
|
+
"test:httpapi": "bun run script/httpapi-exercise.ts --mode coverage --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode auth --fail-on-missing --fail-on-skip && bun run script/httpapi-exercise.ts --mode effect --fail-on-missing --fail-on-skip",
|
|
29
|
+
"bench:test": "bun run script/bench-test-suite.ts",
|
|
30
|
+
"profile:test": "bun run script/profile-test-files.ts",
|
|
31
|
+
"build": "bun run script/build.ts",
|
|
32
|
+
"dev": "bun run ./src/index.ts",
|
|
33
|
+
"dev:temporary": "bun run ./src/temporary.ts",
|
|
34
|
+
"test:termux-launcher": "node script/test-termux-launcher.cjs"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"xyteeecode": "./bin/xyteeecode"
|
|
38
|
+
},
|
|
39
|
+
"exports": {
|
|
40
|
+
"./*": "./src/*.ts"
|
|
41
|
+
},
|
|
42
|
+
"imports": {
|
|
43
|
+
"#db": {
|
|
44
|
+
"bun": "./src/storage/db.bun.ts",
|
|
45
|
+
"node": "./src/storage/db.node.ts",
|
|
46
|
+
"default": "./src/storage/db.bun.ts"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@babel/core": "7.28.4",
|
|
51
|
+
"@octokit/webhooks-types": "7.6.1",
|
|
52
|
+
"@opencode-ai/core": "workspace:*",
|
|
53
|
+
"@opencode-ai/http-recorder": "workspace:*",
|
|
54
|
+
"@opencode-ai/script": "workspace:*",
|
|
55
|
+
"@standard-schema/spec": "1.0.0",
|
|
56
|
+
"@tsconfig/bun": "catalog:",
|
|
57
|
+
"@types/babel__core": "7.20.5",
|
|
58
|
+
"@types/bun": "catalog:",
|
|
59
|
+
"@types/cross-spawn": "catalog:",
|
|
60
|
+
"@types/mime-types": "3.0.1",
|
|
61
|
+
"@types/npm-package-arg": "6.1.4",
|
|
62
|
+
"@types/semver": "^7.5.8",
|
|
63
|
+
"@types/turndown": "5.0.5",
|
|
64
|
+
"@types/yargs": "17.0.33",
|
|
65
|
+
"@typescript/native-preview": "catalog:",
|
|
66
|
+
"drizzle-orm": "catalog:",
|
|
67
|
+
"prettier": "3.6.2",
|
|
68
|
+
"typescript": "catalog:",
|
|
69
|
+
"vscode-languageserver-types": "3.17.5",
|
|
70
|
+
"why-is-node-running": "3.2.2"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@actions/core": "1.11.1",
|
|
74
|
+
"@actions/github": "6.0.1",
|
|
75
|
+
"@agentclientprotocol/sdk": "0.21.0",
|
|
76
|
+
"@ai-sdk/alibaba": "1.0.17",
|
|
77
|
+
"@ai-sdk/amazon-bedrock": "4.0.166",
|
|
78
|
+
"@ai-sdk/anthropic": "3.0.111",
|
|
79
|
+
"@ai-sdk/azure": "3.0.93",
|
|
80
|
+
"@ai-sdk/cerebras": "2.0.60",
|
|
81
|
+
"@ai-sdk/cohere": "3.0.27",
|
|
82
|
+
"@ai-sdk/deepinfra": "2.0.41",
|
|
83
|
+
"@ai-sdk/gateway": "3.0.104",
|
|
84
|
+
"@ai-sdk/google": "3.0.73",
|
|
85
|
+
"@ai-sdk/google-vertex": "4.0.181",
|
|
86
|
+
"@ai-sdk/groq": "3.0.31",
|
|
87
|
+
"@ai-sdk/mistral": "3.0.51",
|
|
88
|
+
"@ai-sdk/openai": "3.0.88",
|
|
89
|
+
"@ai-sdk/openai-compatible": "2.0.41",
|
|
90
|
+
"@ai-sdk/perplexity": "3.0.26",
|
|
91
|
+
"@ai-sdk/provider": "3.0.8",
|
|
92
|
+
"@ai-sdk/togetherai": "2.0.41",
|
|
93
|
+
"@ai-sdk/vercel": "2.0.39",
|
|
94
|
+
"@ai-sdk/xai": "3.0.102",
|
|
95
|
+
"@aws-sdk/credential-providers": "3.1057.0",
|
|
96
|
+
"@clack/prompts": "1.0.0-alpha.1",
|
|
97
|
+
"@effect/opentelemetry": "catalog:",
|
|
98
|
+
"@effect/platform-node": "catalog:",
|
|
99
|
+
"@ff-labs/fff-bun": "0.9.4",
|
|
100
|
+
"@gitlab/opencode-gitlab-auth": "1.3.3",
|
|
101
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
102
|
+
"@octokit/graphql": "9.0.2",
|
|
103
|
+
"@octokit/rest": "catalog:",
|
|
104
|
+
"@openauthjs/openauth": "catalog:",
|
|
105
|
+
"@opencode-ai/codemode": "workspace:*",
|
|
106
|
+
"@opencode-ai/llm": "workspace:*",
|
|
107
|
+
"@opencode-ai/plugin": "workspace:*",
|
|
108
|
+
"@opencode-ai/protocol": "workspace:*",
|
|
109
|
+
"@opencode-ai/schema": "workspace:*",
|
|
110
|
+
"@opencode-ai/script": "workspace:*",
|
|
111
|
+
"@opencode-ai/sdk": "workspace:*",
|
|
112
|
+
"@opencode-ai/server": "workspace:*",
|
|
113
|
+
"@opencode-ai/tui": "workspace:*",
|
|
114
|
+
"@openrouter/ai-sdk-provider": "2.9.0",
|
|
115
|
+
"@opentelemetry/api": "1.9.0",
|
|
116
|
+
"@opentelemetry/context-async-hooks": "2.6.1",
|
|
117
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
|
|
118
|
+
"@opentelemetry/sdk-trace-base": "2.6.1",
|
|
119
|
+
"@opentelemetry/sdk-trace-node": "2.6.1",
|
|
120
|
+
"@opentui/core": "catalog:",
|
|
121
|
+
"@opentui/keymap": "catalog:",
|
|
122
|
+
"@opentui/solid": "catalog:",
|
|
123
|
+
"@parcel/watcher": "2.5.1",
|
|
124
|
+
"@pierre/diffs": "catalog:",
|
|
125
|
+
"@silvia-odwyer/photon-node": "0.3.4",
|
|
126
|
+
"@solid-primitives/event-bus": "1.1.2",
|
|
127
|
+
"@solid-primitives/scheduled": "1.5.2",
|
|
128
|
+
"@standard-schema/spec": "1.0.0",
|
|
129
|
+
"@types/ws": "8.18.1",
|
|
130
|
+
"@zip.js/zip.js": "2.7.62",
|
|
131
|
+
"ai": "catalog:",
|
|
132
|
+
"ai-gateway-provider": "3.2.0",
|
|
133
|
+
"bonjour-service": "1.3.0",
|
|
134
|
+
"chokidar": "4.0.3",
|
|
135
|
+
"cross-spawn": "catalog:",
|
|
136
|
+
"decimal.js": "10.5.0",
|
|
137
|
+
"diff": "catalog:",
|
|
138
|
+
"drizzle-orm": "catalog:",
|
|
139
|
+
"effect": "catalog:",
|
|
140
|
+
"fuzzysort": "3.1.0",
|
|
141
|
+
"gitlab-ai-provider": "6.15.0",
|
|
142
|
+
"glob": "13.0.5",
|
|
143
|
+
"google-auth-library": "10.5.0",
|
|
144
|
+
"gray-matter": "4.0.3",
|
|
145
|
+
"htmlparser2": "8.0.2",
|
|
146
|
+
"ignore": "7.0.5",
|
|
147
|
+
"immer": "11.1.4",
|
|
148
|
+
"jsonc-parser": "3.3.1",
|
|
149
|
+
"mime-types": "3.0.2",
|
|
150
|
+
"minimatch": "10.0.3",
|
|
151
|
+
"npm-package-arg": "13.0.2",
|
|
152
|
+
"open": "10.1.2",
|
|
153
|
+
"opencode-gitlab-auth": "2.1.0",
|
|
154
|
+
"opencode-poe-auth": "0.0.1",
|
|
155
|
+
"opentui-spinner": "catalog:",
|
|
156
|
+
"partial-json": "0.1.7",
|
|
157
|
+
"remeda": "catalog:",
|
|
158
|
+
"semver": "^7.6.3",
|
|
159
|
+
"solid-js": "catalog:",
|
|
160
|
+
"strip-ansi": "7.1.2",
|
|
161
|
+
"tree-sitter-bash": "0.25.0",
|
|
162
|
+
"tree-sitter-powershell": "0.25.10",
|
|
163
|
+
"turndown": "7.2.0",
|
|
164
|
+
"ulid": "catalog:",
|
|
165
|
+
"venice-ai-sdk-provider": "2.1.1",
|
|
166
|
+
"vscode-jsonrpc": "8.2.1",
|
|
167
|
+
"web-tree-sitter": "0.25.10",
|
|
168
|
+
"ws": "8.21.0",
|
|
169
|
+
"xdg-basedir": "5.1.0",
|
|
170
|
+
"yargs": "18.0.0",
|
|
171
|
+
"zod": "catalog:"
|
|
172
|
+
},
|
|
173
|
+
"overrides": {
|
|
174
|
+
"drizzle-orm": "catalog:"
|
|
28
175
|
}
|
|
29
|
-
}
|
|
176
|
+
}
|
package/README.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# xyteeecode
|
|
2
|
-
|
|
3
|
-
xyteeecode is an AI coding agent that runs in your terminal — powered by open models, with a clean TUI, agentic tool use, and full session history.
|
|
4
|
-
|
|
5
|
-
It is the rebranded fork of [opencode](https://opencode.ai), distributed as a single self-contained binary.
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g xyteeecode
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
The package automatically installs the matching binary for your platform (arm64/x64, Linux/macOS/Windows).
|
|
14
|
-
|
|
15
|
-
## Quick start
|
|
16
|
-
|
|
17
|
-
### With Kira free models (no API key setup required after signup)
|
|
18
|
-
|
|
19
|
-
1. Sign up for a free key at [kira](https://kiraai.vn) (the gateway used in this project).
|
|
20
|
-
2. Place your key in your global config:
|
|
21
|
-
|
|
22
|
-
`~/.config/opencode/opencode.jsonc`
|
|
23
|
-
|
|
24
|
-
```jsonc
|
|
25
|
-
{
|
|
26
|
-
"provider": {
|
|
27
|
-
"kira": {
|
|
28
|
-
"npm": "@ai-sdk/openai-compatible",
|
|
29
|
-
"name": "Kira",
|
|
30
|
-
"options": {
|
|
31
|
-
"baseURL": "https://kiraai.vn/api/v1",
|
|
32
|
-
"apiKey": "{env:KIRA_API_KEY}"
|
|
33
|
-
},
|
|
34
|
-
"models": {
|
|
35
|
-
"qwen3.8-flash-free": {
|
|
36
|
-
"name": "Qwen 3.8 Flash (free)"
|
|
37
|
-
},
|
|
38
|
-
"hy3-free": {
|
|
39
|
-
"name": "HY3 (free)"
|
|
40
|
-
},
|
|
41
|
-
"mimo-v2.5-free": {
|
|
42
|
-
"name": "Mimo 2.5 (free)"
|
|
43
|
-
},
|
|
44
|
-
"glm-5.3-free": {
|
|
45
|
-
"name": "GLM 5.3 (free)"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
"model": "kira/qwen3.8-flash-free"
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
3. Run:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
xyteeecode
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Or run a one-off prompt without opening the TUI:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
xyteeecode run "explain this codebase" --model kira/qwen3.8-flash-free
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### With other providers
|
|
67
|
-
|
|
68
|
-
Authenticate with any provider the CLI supports (Anthropic, OpenAI, Groq, and hundreds more via models.dev), either through the built-in `/login` flow or by adding provider config the same way as above.
|
|
69
|
-
|
|
70
|
-
### With Connect (AgentRouter)
|
|
71
|
-
|
|
72
|
-
[AgentRouter](https://agentrouter.org) is a free AI coding gateway with OpenAI-compatible and Anthropic-compatible endpoints. Add one or both gateways to your global config:
|
|
73
|
-
|
|
74
|
-
`~/.config/opencode/opencode.jsonc`
|
|
75
|
-
|
|
76
|
-
```jsonc
|
|
77
|
-
{
|
|
78
|
-
"provider": {
|
|
79
|
-
"connect": {
|
|
80
|
-
"npm": "@ai-sdk/openai-compatible",
|
|
81
|
-
"name": "Connect (OpenAI gateway)",
|
|
82
|
-
"options": {
|
|
83
|
-
"baseURL": "https://agentrouter.org/v1",
|
|
84
|
-
"apiKey": "{env:AGENTROUTER_API_KEY}"
|
|
85
|
-
},
|
|
86
|
-
"models": {
|
|
87
|
-
"deepseek-v4-flash": { "name": "DeepSeek V4 Flash" },
|
|
88
|
-
"glm-5.3": { "name": "GLM 5.3" },
|
|
89
|
-
"gpt-5.6-sol": { "name": "GPT 5.6 SOL" }
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
"connect-anthropic": {
|
|
93
|
-
"npm": "@ai-sdk/anthropic",
|
|
94
|
-
"name": "Connect (Anthropic gateway)",
|
|
95
|
-
"options": {
|
|
96
|
-
"baseURL": "https://agentrouter.org",
|
|
97
|
-
"apiKey": "{env:AGENTROUTER_API_KEY}"
|
|
98
|
-
},
|
|
99
|
-
"models": {
|
|
100
|
-
"claude-opus-5": { "name": "Claude Opus 5" },
|
|
101
|
-
"claude-opus-4-8": { "name": "Claude Opus 4-8" }
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
"model": "connect/deepseek-v4-flash"
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
Note: for the Anthropic gateway the base URL must **not** include `/v1`. The model list is dynamic — always check the latest models at [https://ps.air-outer.com/console/personal](https://ps.air-outer.com/console/personal).
|
|
110
|
-
|
|
111
|
-
## Commands
|
|
112
|
-
|
|
113
|
-
- `xyteeecode` — launch the interactive terminal UI
|
|
114
|
-
- `xyteeecode run "<prompt>"` — run a single prompt in the current directory
|
|
115
|
-
- `xyteeecode models <provider>` — list available models for a provider
|
|
116
|
-
- `xyteeecode agent list` — list agents
|
|
117
|
-
- `xyteeecode mcp list` — list MCP servers
|
|
118
|
-
- `xyteeecode session list` — list past sessions
|
|
119
|
-
- `xyteeecode --help` — all commands and flags
|
|
120
|
-
|
|
121
|
-
## Config
|
|
122
|
-
|
|
123
|
-
Global config lives at `~/.config/opencode/opencode.jsonc`. Project config lives in `.opencode/opencode.json` at your project root.
|
|
124
|
-
|
|
125
|
-
## License
|
|
126
|
-
|
|
127
|
-
MIT
|