@keelcode-ai/keelcode 0.1.5-win32-x64 → 0.1.5

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/kcode.cjs ADDED
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env bun
2
+ 'use strict'
3
+
4
+ const { spawnSync } = require('node:child_process')
5
+ const {
6
+ lstatSync,
7
+ readFileSync,
8
+ readdirSync,
9
+ realpathSync,
10
+ statSync,
11
+ symlinkSync,
12
+ unlinkSync,
13
+ writeFileSync,
14
+ } = require('node:fs')
15
+ const { createInterface } = require('node:readline')
16
+ const path = require('node:path')
17
+
18
+ const VERSION = "0.1.5"
19
+ const TARGETS = {
20
+ "darwin-arm64": {
21
+ "packageName": "@keelcode-ai/keelcode-darwin-arm64",
22
+ "packageVersion": "0.1.5-darwin-arm64",
23
+ "executableName": "keelcode",
24
+ "ripgrepExecutableName": "rg"
25
+ },
26
+ "darwin-x64": {
27
+ "packageName": "@keelcode-ai/keelcode-darwin-x64",
28
+ "packageVersion": "0.1.5-darwin-x64",
29
+ "executableName": "keelcode",
30
+ "ripgrepExecutableName": "rg"
31
+ },
32
+ "linux-arm64": {
33
+ "packageName": "@keelcode-ai/keelcode-linux-arm64",
34
+ "packageVersion": "0.1.5-linux-arm64",
35
+ "executableName": "keelcode",
36
+ "ripgrepExecutableName": "rg"
37
+ },
38
+ "linux-arm64-musl": {
39
+ "packageName": "@keelcode-ai/keelcode-linux-arm64-musl",
40
+ "packageVersion": "0.1.5-linux-arm64-musl",
41
+ "executableName": "keelcode",
42
+ "ripgrepExecutableName": "rg"
43
+ },
44
+ "linux-x64": {
45
+ "packageName": "@keelcode-ai/keelcode-linux-x64",
46
+ "packageVersion": "0.1.5-linux-x64",
47
+ "executableName": "keelcode",
48
+ "ripgrepExecutableName": "rg"
49
+ },
50
+ "linux-x64-musl": {
51
+ "packageName": "@keelcode-ai/keelcode-linux-x64-musl",
52
+ "packageVersion": "0.1.5-linux-x64-musl",
53
+ "executableName": "keelcode",
54
+ "ripgrepExecutableName": "rg"
55
+ },
56
+ "win32-arm64": {
57
+ "packageName": "@keelcode-ai/keelcode-win32-arm64",
58
+ "packageVersion": "0.1.5-win32-arm64",
59
+ "executableName": "keelcode.exe",
60
+ "ripgrepExecutableName": "rg.exe"
61
+ },
62
+ "win32-x64": {
63
+ "packageName": "@keelcode-ai/keelcode-win32-x64",
64
+ "packageVersion": "0.1.5-win32-x64",
65
+ "executableName": "keelcode.exe",
66
+ "ripgrepExecutableName": "rg.exe"
67
+ }
68
+ }
69
+ const DEFAULT_ALIASES = ['keelcode', 'kc', 'kcode', 'keel']
70
+ const ALIAS_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/u
71
+ const WINDOWS_ALIAS_MARKER = 'REM keelcode-managed-alias'
72
+
73
+ function detectTargetId() {
74
+ const platform = process.platform
75
+ const arch = process.arch
76
+ if (platform === 'linux') {
77
+ let glibc = false
78
+ try {
79
+ glibc = Boolean(process.report && process.report.getReport().header.glibcVersionRuntime)
80
+ } catch {}
81
+ return 'linux-' + arch + (glibc ? '' : '-musl')
82
+ }
83
+ return platform + '-' + arch
84
+ }
85
+
86
+ function fail(message) {
87
+ process.stderr.write('keelcode: ' + message + '\n')
88
+ process.exit(1)
89
+ }
90
+
91
+ function pathEntryExists(filename) {
92
+ try {
93
+ lstatSync(filename)
94
+ return true
95
+ } catch {
96
+ return false
97
+ }
98
+ }
99
+
100
+ function commandCandidates(directory, name) {
101
+ if (process.platform !== 'win32') return [path.join(directory, name)]
102
+ return ['.exe', '.cmd', '.ps1', ''].map((extension) => path.join(directory, name + extension))
103
+ }
104
+
105
+ function findLauncherBinDirectory() {
106
+ const launcher = realpathSync(__filename)
107
+ let windowsFallback
108
+ for (const directory of (process.env.PATH || '').split(path.delimiter).filter(Boolean)) {
109
+ for (const name of DEFAULT_ALIASES) {
110
+ for (const candidate of commandCandidates(directory, name)) {
111
+ if (!pathEntryExists(candidate)) continue
112
+ if (process.platform !== 'win32') {
113
+ try {
114
+ if (realpathSync(candidate) === launcher) return { directory, command: path.basename(candidate) }
115
+ } catch {}
116
+ continue
117
+ }
118
+
119
+ windowsFallback ||= { directory, command: path.basename(candidate) }
120
+ if (!/\.(?:cmd|ps1)$/iu.test(candidate)) continue
121
+ try {
122
+ const shim = readFileSync(candidate, 'utf8').replaceAll('\\', '/')
123
+ const expected = __filename.replaceAll('\\', '/')
124
+ if (shim.includes(expected) || shim.includes('node_modules/keelcode/bin/keelcode.cjs')) {
125
+ return { directory, command: path.basename(candidate) }
126
+ }
127
+ } catch {}
128
+ }
129
+ }
130
+ }
131
+ if (windowsFallback) return windowsFallback
132
+ fail('could not find the active package-manager bin directory on PATH')
133
+ }
134
+
135
+ function validateAliasName(name) {
136
+ if (DEFAULT_ALIASES.includes(name)) fail('"' + name + '" is a built-in alias and cannot be changed')
137
+ if (!ALIAS_PATTERN.test(name)) {
138
+ fail('alias "' + name + '" must start with a lowercase letter and contain only lowercase letters, digits, - or _ (32 characters max)')
139
+ }
140
+ }
141
+
142
+ function aliasConflicts(directory, name) {
143
+ return commandCandidates(directory, name).some(pathEntryExists)
144
+ }
145
+
146
+ function addAliases(names) {
147
+ const aliases = [...new Set(names)]
148
+ if (aliases.length === 0) fail('usage: keelcode alias add <name> [name...]')
149
+ for (const name of aliases) validateAliasName(name)
150
+
151
+ const location = findLauncherBinDirectory()
152
+ for (const name of aliases) {
153
+ if (aliasConflicts(location.directory, name)) {
154
+ fail('refusing to overwrite existing command "' + name + '" in ' + location.directory)
155
+ }
156
+ }
157
+
158
+ const created = []
159
+ try {
160
+ for (const name of aliases) {
161
+ if (process.platform === 'win32') {
162
+ const target = path.join(location.directory, location.command)
163
+ if (!/\.(?:exe|cmd)$/iu.test(target)) {
164
+ fail('the active Windows package-manager shim is not compatible with custom aliases')
165
+ }
166
+ const destination = path.join(location.directory, name + '.cmd')
167
+ const body = '@echo off\r\n' + WINDOWS_ALIAS_MARKER + '\r\n"%~dp0' + path.basename(target) + '" %*\r\n'
168
+ writeFileSync(destination, body, { flag: 'wx', mode: 0o755 })
169
+ created.push(destination)
170
+ } else {
171
+ const destination = path.join(location.directory, name)
172
+ symlinkSync(location.command, destination)
173
+ created.push(destination)
174
+ }
175
+ }
176
+ } catch (error) {
177
+ for (const filename of created.reverse()) {
178
+ try { unlinkSync(filename) } catch {}
179
+ }
180
+ fail(error instanceof Error ? error.message : String(error))
181
+ }
182
+
183
+ process.stdout.write('Added custom alias' + (aliases.length === 1 ? '' : 'es') + ': ' + aliases.join(', ') + '\n')
184
+ }
185
+
186
+ function managedAliases(location) {
187
+ const aliases = new Set()
188
+ for (const entry of readdirSync(location.directory)) {
189
+ if (process.platform === 'win32') {
190
+ if (!entry.toLowerCase().endsWith('.cmd')) continue
191
+ const name = entry.slice(0, -4)
192
+ if (DEFAULT_ALIASES.includes(name) || !ALIAS_PATTERN.test(name)) continue
193
+ try {
194
+ if (readFileSync(path.join(location.directory, entry), 'utf8').includes(WINDOWS_ALIAS_MARKER)) aliases.add(name)
195
+ } catch {}
196
+ continue
197
+ }
198
+
199
+ if (DEFAULT_ALIASES.includes(entry) || !ALIAS_PATTERN.test(entry)) continue
200
+ const filename = path.join(location.directory, entry)
201
+ try {
202
+ if (lstatSync(filename).isSymbolicLink() && realpathSync(filename) === realpathSync(__filename)) aliases.add(entry)
203
+ } catch {}
204
+ }
205
+ return [...aliases].sort()
206
+ }
207
+
208
+ function listAliases() {
209
+ const aliases = managedAliases(findLauncherBinDirectory())
210
+ process.stdout.write('Built-in aliases: ' + DEFAULT_ALIASES.join(', ') + '\n')
211
+ process.stdout.write('Custom aliases: ' + (aliases.length > 0 ? aliases.join(', ') : 'none') + '\n')
212
+ }
213
+
214
+ function removeAliases(names) {
215
+ const aliases = [...new Set(names)]
216
+ if (aliases.length === 0) fail('usage: keelcode alias remove <name> [name...]')
217
+ for (const name of aliases) validateAliasName(name)
218
+
219
+ const location = findLauncherBinDirectory()
220
+ const managed = new Set(managedAliases(location))
221
+ for (const name of aliases) {
222
+ if (!managed.has(name)) fail('"' + name + '" is not a Keelcode-managed custom alias')
223
+ }
224
+ for (const name of aliases) {
225
+ unlinkSync(path.join(location.directory, name + (process.platform === 'win32' ? '.cmd' : '')))
226
+ }
227
+ process.stdout.write('Removed custom alias' + (aliases.length === 1 ? '' : 'es') + ': ' + aliases.join(', ') + '\n')
228
+ }
229
+
230
+ function printAliasHelp() {
231
+ process.stdout.write([
232
+ 'Manage Keelcode command aliases',
233
+ '',
234
+ ' keelcode alias setup',
235
+ ' keelcode alias list',
236
+ ' keelcode alias add <name> [name...]',
237
+ ' keelcode alias remove <name> [name...]',
238
+ '',
239
+ 'Built in: ' + DEFAULT_ALIASES.join(', '),
240
+ 'Names must start with a lowercase letter and use only a-z, 0-9, - or _.',
241
+ '',
242
+ ].join('\n'))
243
+ }
244
+
245
+ async function setupAliases() {
246
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
247
+ fail('alias setup needs an interactive terminal; use keelcode alias add <name> instead')
248
+ }
249
+ process.stdout.write('Built-in aliases are already active: ' + DEFAULT_ALIASES.join(', ') + '\n')
250
+ const readline = createInterface({ input: process.stdin, output: process.stdout })
251
+ const answer = await new Promise((resolve) => {
252
+ readline.question('Custom aliases (comma or space separated; blank to skip): ', resolve)
253
+ })
254
+ readline.close()
255
+ const aliases = String(answer).trim().split(/[\s,]+/u).filter(Boolean)
256
+ if (aliases.length === 0) {
257
+ process.stdout.write('No custom aliases added.\n')
258
+ return
259
+ }
260
+ addAliases(aliases)
261
+ }
262
+
263
+ async function handleAliasCommand(args) {
264
+ const action = args[0] || 'help'
265
+ if (action === 'help' || action === '--help' || action === '-h') return printAliasHelp()
266
+ if (action === 'setup') return setupAliases()
267
+ if (action === 'list') return listAliases()
268
+ if (action === 'add') return addAliases(args.slice(1))
269
+ if (action === 'remove') return removeAliases(args.slice(1))
270
+ fail('unknown alias action "' + action + '"; use keelcode alias --help')
271
+ }
272
+
273
+ function launchNative(args) {
274
+ const targetId = detectTargetId()
275
+ const target = TARGETS[targetId]
276
+ if (!target) fail('unsupported platform ' + targetId)
277
+
278
+ let manifestPath
279
+ try {
280
+ manifestPath = require.resolve(target.packageName + '/package.json')
281
+ } catch {
282
+ fail('native package ' + target.packageName + ' is missing; reinstall keelcode@' + VERSION + ' with optional dependencies enabled')
283
+ }
284
+
285
+ let nativeManifest
286
+ try {
287
+ nativeManifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
288
+ } catch {
289
+ fail('could not read native package metadata for ' + target.packageName)
290
+ }
291
+ if (nativeManifest.name !== '@keelcode-ai/keelcode' || nativeManifest.version !== target.packageVersion) {
292
+ fail('native package version mismatch: expected @keelcode-ai/keelcode@' + target.packageVersion + ', found ' + (nativeManifest.name || 'unknown') + '@' + (nativeManifest.version || 'unknown'))
293
+ }
294
+
295
+ const packageRoot = path.dirname(manifestPath)
296
+ const executable = path.join(packageRoot, 'bin', target.executableName)
297
+ const ripgrep = path.join(packageRoot, 'bin', target.ripgrepExecutableName)
298
+ for (const [label, filename] of [['native executable', executable], ['ripgrep sidecar', ripgrep]]) {
299
+ try {
300
+ if (!statSync(filename).isFile()) throw new Error('not a file')
301
+ } catch {
302
+ fail(label + ' is missing from ' + target.packageName + '; reinstall keelcode')
303
+ }
304
+ }
305
+
306
+ const result = spawnSync(executable, args, {
307
+ stdio: 'inherit',
308
+ env: { ...process.env, KEELCODE_RG_PATH: ripgrep },
309
+ windowsHide: false,
310
+ })
311
+ if (result.error) fail(result.error.message)
312
+ if (result.signal && process.platform !== 'win32') process.kill(process.pid, result.signal)
313
+ process.exit(result.status === null ? 1 : result.status)
314
+ }
315
+
316
+ async function main() {
317
+ const args = process.argv.slice(2)
318
+ if (args[0] === 'alias') {
319
+ await handleAliasCommand(args.slice(1))
320
+ return
321
+ }
322
+ launchNative(args)
323
+ }
324
+
325
+ main().catch((error) => fail(error instanceof Error ? error.message : String(error)))
package/bin/keel.cjs ADDED
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env bun
2
+ 'use strict'
3
+
4
+ const { spawnSync } = require('node:child_process')
5
+ const {
6
+ lstatSync,
7
+ readFileSync,
8
+ readdirSync,
9
+ realpathSync,
10
+ statSync,
11
+ symlinkSync,
12
+ unlinkSync,
13
+ writeFileSync,
14
+ } = require('node:fs')
15
+ const { createInterface } = require('node:readline')
16
+ const path = require('node:path')
17
+
18
+ const VERSION = "0.1.5"
19
+ const TARGETS = {
20
+ "darwin-arm64": {
21
+ "packageName": "@keelcode-ai/keelcode-darwin-arm64",
22
+ "packageVersion": "0.1.5-darwin-arm64",
23
+ "executableName": "keelcode",
24
+ "ripgrepExecutableName": "rg"
25
+ },
26
+ "darwin-x64": {
27
+ "packageName": "@keelcode-ai/keelcode-darwin-x64",
28
+ "packageVersion": "0.1.5-darwin-x64",
29
+ "executableName": "keelcode",
30
+ "ripgrepExecutableName": "rg"
31
+ },
32
+ "linux-arm64": {
33
+ "packageName": "@keelcode-ai/keelcode-linux-arm64",
34
+ "packageVersion": "0.1.5-linux-arm64",
35
+ "executableName": "keelcode",
36
+ "ripgrepExecutableName": "rg"
37
+ },
38
+ "linux-arm64-musl": {
39
+ "packageName": "@keelcode-ai/keelcode-linux-arm64-musl",
40
+ "packageVersion": "0.1.5-linux-arm64-musl",
41
+ "executableName": "keelcode",
42
+ "ripgrepExecutableName": "rg"
43
+ },
44
+ "linux-x64": {
45
+ "packageName": "@keelcode-ai/keelcode-linux-x64",
46
+ "packageVersion": "0.1.5-linux-x64",
47
+ "executableName": "keelcode",
48
+ "ripgrepExecutableName": "rg"
49
+ },
50
+ "linux-x64-musl": {
51
+ "packageName": "@keelcode-ai/keelcode-linux-x64-musl",
52
+ "packageVersion": "0.1.5-linux-x64-musl",
53
+ "executableName": "keelcode",
54
+ "ripgrepExecutableName": "rg"
55
+ },
56
+ "win32-arm64": {
57
+ "packageName": "@keelcode-ai/keelcode-win32-arm64",
58
+ "packageVersion": "0.1.5-win32-arm64",
59
+ "executableName": "keelcode.exe",
60
+ "ripgrepExecutableName": "rg.exe"
61
+ },
62
+ "win32-x64": {
63
+ "packageName": "@keelcode-ai/keelcode-win32-x64",
64
+ "packageVersion": "0.1.5-win32-x64",
65
+ "executableName": "keelcode.exe",
66
+ "ripgrepExecutableName": "rg.exe"
67
+ }
68
+ }
69
+ const DEFAULT_ALIASES = ['keelcode', 'kc', 'kcode', 'keel']
70
+ const ALIAS_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/u
71
+ const WINDOWS_ALIAS_MARKER = 'REM keelcode-managed-alias'
72
+
73
+ function detectTargetId() {
74
+ const platform = process.platform
75
+ const arch = process.arch
76
+ if (platform === 'linux') {
77
+ let glibc = false
78
+ try {
79
+ glibc = Boolean(process.report && process.report.getReport().header.glibcVersionRuntime)
80
+ } catch {}
81
+ return 'linux-' + arch + (glibc ? '' : '-musl')
82
+ }
83
+ return platform + '-' + arch
84
+ }
85
+
86
+ function fail(message) {
87
+ process.stderr.write('keelcode: ' + message + '\n')
88
+ process.exit(1)
89
+ }
90
+
91
+ function pathEntryExists(filename) {
92
+ try {
93
+ lstatSync(filename)
94
+ return true
95
+ } catch {
96
+ return false
97
+ }
98
+ }
99
+
100
+ function commandCandidates(directory, name) {
101
+ if (process.platform !== 'win32') return [path.join(directory, name)]
102
+ return ['.exe', '.cmd', '.ps1', ''].map((extension) => path.join(directory, name + extension))
103
+ }
104
+
105
+ function findLauncherBinDirectory() {
106
+ const launcher = realpathSync(__filename)
107
+ let windowsFallback
108
+ for (const directory of (process.env.PATH || '').split(path.delimiter).filter(Boolean)) {
109
+ for (const name of DEFAULT_ALIASES) {
110
+ for (const candidate of commandCandidates(directory, name)) {
111
+ if (!pathEntryExists(candidate)) continue
112
+ if (process.platform !== 'win32') {
113
+ try {
114
+ if (realpathSync(candidate) === launcher) return { directory, command: path.basename(candidate) }
115
+ } catch {}
116
+ continue
117
+ }
118
+
119
+ windowsFallback ||= { directory, command: path.basename(candidate) }
120
+ if (!/\.(?:cmd|ps1)$/iu.test(candidate)) continue
121
+ try {
122
+ const shim = readFileSync(candidate, 'utf8').replaceAll('\\', '/')
123
+ const expected = __filename.replaceAll('\\', '/')
124
+ if (shim.includes(expected) || shim.includes('node_modules/keelcode/bin/keelcode.cjs')) {
125
+ return { directory, command: path.basename(candidate) }
126
+ }
127
+ } catch {}
128
+ }
129
+ }
130
+ }
131
+ if (windowsFallback) return windowsFallback
132
+ fail('could not find the active package-manager bin directory on PATH')
133
+ }
134
+
135
+ function validateAliasName(name) {
136
+ if (DEFAULT_ALIASES.includes(name)) fail('"' + name + '" is a built-in alias and cannot be changed')
137
+ if (!ALIAS_PATTERN.test(name)) {
138
+ fail('alias "' + name + '" must start with a lowercase letter and contain only lowercase letters, digits, - or _ (32 characters max)')
139
+ }
140
+ }
141
+
142
+ function aliasConflicts(directory, name) {
143
+ return commandCandidates(directory, name).some(pathEntryExists)
144
+ }
145
+
146
+ function addAliases(names) {
147
+ const aliases = [...new Set(names)]
148
+ if (aliases.length === 0) fail('usage: keelcode alias add <name> [name...]')
149
+ for (const name of aliases) validateAliasName(name)
150
+
151
+ const location = findLauncherBinDirectory()
152
+ for (const name of aliases) {
153
+ if (aliasConflicts(location.directory, name)) {
154
+ fail('refusing to overwrite existing command "' + name + '" in ' + location.directory)
155
+ }
156
+ }
157
+
158
+ const created = []
159
+ try {
160
+ for (const name of aliases) {
161
+ if (process.platform === 'win32') {
162
+ const target = path.join(location.directory, location.command)
163
+ if (!/\.(?:exe|cmd)$/iu.test(target)) {
164
+ fail('the active Windows package-manager shim is not compatible with custom aliases')
165
+ }
166
+ const destination = path.join(location.directory, name + '.cmd')
167
+ const body = '@echo off\r\n' + WINDOWS_ALIAS_MARKER + '\r\n"%~dp0' + path.basename(target) + '" %*\r\n'
168
+ writeFileSync(destination, body, { flag: 'wx', mode: 0o755 })
169
+ created.push(destination)
170
+ } else {
171
+ const destination = path.join(location.directory, name)
172
+ symlinkSync(location.command, destination)
173
+ created.push(destination)
174
+ }
175
+ }
176
+ } catch (error) {
177
+ for (const filename of created.reverse()) {
178
+ try { unlinkSync(filename) } catch {}
179
+ }
180
+ fail(error instanceof Error ? error.message : String(error))
181
+ }
182
+
183
+ process.stdout.write('Added custom alias' + (aliases.length === 1 ? '' : 'es') + ': ' + aliases.join(', ') + '\n')
184
+ }
185
+
186
+ function managedAliases(location) {
187
+ const aliases = new Set()
188
+ for (const entry of readdirSync(location.directory)) {
189
+ if (process.platform === 'win32') {
190
+ if (!entry.toLowerCase().endsWith('.cmd')) continue
191
+ const name = entry.slice(0, -4)
192
+ if (DEFAULT_ALIASES.includes(name) || !ALIAS_PATTERN.test(name)) continue
193
+ try {
194
+ if (readFileSync(path.join(location.directory, entry), 'utf8').includes(WINDOWS_ALIAS_MARKER)) aliases.add(name)
195
+ } catch {}
196
+ continue
197
+ }
198
+
199
+ if (DEFAULT_ALIASES.includes(entry) || !ALIAS_PATTERN.test(entry)) continue
200
+ const filename = path.join(location.directory, entry)
201
+ try {
202
+ if (lstatSync(filename).isSymbolicLink() && realpathSync(filename) === realpathSync(__filename)) aliases.add(entry)
203
+ } catch {}
204
+ }
205
+ return [...aliases].sort()
206
+ }
207
+
208
+ function listAliases() {
209
+ const aliases = managedAliases(findLauncherBinDirectory())
210
+ process.stdout.write('Built-in aliases: ' + DEFAULT_ALIASES.join(', ') + '\n')
211
+ process.stdout.write('Custom aliases: ' + (aliases.length > 0 ? aliases.join(', ') : 'none') + '\n')
212
+ }
213
+
214
+ function removeAliases(names) {
215
+ const aliases = [...new Set(names)]
216
+ if (aliases.length === 0) fail('usage: keelcode alias remove <name> [name...]')
217
+ for (const name of aliases) validateAliasName(name)
218
+
219
+ const location = findLauncherBinDirectory()
220
+ const managed = new Set(managedAliases(location))
221
+ for (const name of aliases) {
222
+ if (!managed.has(name)) fail('"' + name + '" is not a Keelcode-managed custom alias')
223
+ }
224
+ for (const name of aliases) {
225
+ unlinkSync(path.join(location.directory, name + (process.platform === 'win32' ? '.cmd' : '')))
226
+ }
227
+ process.stdout.write('Removed custom alias' + (aliases.length === 1 ? '' : 'es') + ': ' + aliases.join(', ') + '\n')
228
+ }
229
+
230
+ function printAliasHelp() {
231
+ process.stdout.write([
232
+ 'Manage Keelcode command aliases',
233
+ '',
234
+ ' keelcode alias setup',
235
+ ' keelcode alias list',
236
+ ' keelcode alias add <name> [name...]',
237
+ ' keelcode alias remove <name> [name...]',
238
+ '',
239
+ 'Built in: ' + DEFAULT_ALIASES.join(', '),
240
+ 'Names must start with a lowercase letter and use only a-z, 0-9, - or _.',
241
+ '',
242
+ ].join('\n'))
243
+ }
244
+
245
+ async function setupAliases() {
246
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
247
+ fail('alias setup needs an interactive terminal; use keelcode alias add <name> instead')
248
+ }
249
+ process.stdout.write('Built-in aliases are already active: ' + DEFAULT_ALIASES.join(', ') + '\n')
250
+ const readline = createInterface({ input: process.stdin, output: process.stdout })
251
+ const answer = await new Promise((resolve) => {
252
+ readline.question('Custom aliases (comma or space separated; blank to skip): ', resolve)
253
+ })
254
+ readline.close()
255
+ const aliases = String(answer).trim().split(/[\s,]+/u).filter(Boolean)
256
+ if (aliases.length === 0) {
257
+ process.stdout.write('No custom aliases added.\n')
258
+ return
259
+ }
260
+ addAliases(aliases)
261
+ }
262
+
263
+ async function handleAliasCommand(args) {
264
+ const action = args[0] || 'help'
265
+ if (action === 'help' || action === '--help' || action === '-h') return printAliasHelp()
266
+ if (action === 'setup') return setupAliases()
267
+ if (action === 'list') return listAliases()
268
+ if (action === 'add') return addAliases(args.slice(1))
269
+ if (action === 'remove') return removeAliases(args.slice(1))
270
+ fail('unknown alias action "' + action + '"; use keelcode alias --help')
271
+ }
272
+
273
+ function launchNative(args) {
274
+ const targetId = detectTargetId()
275
+ const target = TARGETS[targetId]
276
+ if (!target) fail('unsupported platform ' + targetId)
277
+
278
+ let manifestPath
279
+ try {
280
+ manifestPath = require.resolve(target.packageName + '/package.json')
281
+ } catch {
282
+ fail('native package ' + target.packageName + ' is missing; reinstall keelcode@' + VERSION + ' with optional dependencies enabled')
283
+ }
284
+
285
+ let nativeManifest
286
+ try {
287
+ nativeManifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
288
+ } catch {
289
+ fail('could not read native package metadata for ' + target.packageName)
290
+ }
291
+ if (nativeManifest.name !== '@keelcode-ai/keelcode' || nativeManifest.version !== target.packageVersion) {
292
+ fail('native package version mismatch: expected @keelcode-ai/keelcode@' + target.packageVersion + ', found ' + (nativeManifest.name || 'unknown') + '@' + (nativeManifest.version || 'unknown'))
293
+ }
294
+
295
+ const packageRoot = path.dirname(manifestPath)
296
+ const executable = path.join(packageRoot, 'bin', target.executableName)
297
+ const ripgrep = path.join(packageRoot, 'bin', target.ripgrepExecutableName)
298
+ for (const [label, filename] of [['native executable', executable], ['ripgrep sidecar', ripgrep]]) {
299
+ try {
300
+ if (!statSync(filename).isFile()) throw new Error('not a file')
301
+ } catch {
302
+ fail(label + ' is missing from ' + target.packageName + '; reinstall keelcode')
303
+ }
304
+ }
305
+
306
+ const result = spawnSync(executable, args, {
307
+ stdio: 'inherit',
308
+ env: { ...process.env, KEELCODE_RG_PATH: ripgrep },
309
+ windowsHide: false,
310
+ })
311
+ if (result.error) fail(result.error.message)
312
+ if (result.signal && process.platform !== 'win32') process.kill(process.pid, result.signal)
313
+ process.exit(result.status === null ? 1 : result.status)
314
+ }
315
+
316
+ async function main() {
317
+ const args = process.argv.slice(2)
318
+ if (args[0] === 'alias') {
319
+ await handleAliasCommand(args.slice(1))
320
+ return
321
+ }
322
+ launchNative(args)
323
+ }
324
+
325
+ main().catch((error) => fail(error instanceof Error ? error.message : String(error)))