@keelcode-ai/keelcode 0.1.6 → 0.1.7-darwin-x64

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