@keelcode-ai/keelcode 0.1.0 → 0.1.3-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/keelcode ADDED
Binary file
package/bin/rg ADDED
Binary file
package/package.json CHANGED
@@ -1,49 +1,21 @@
1
1
  {
2
2
  "name": "@keelcode-ai/keelcode",
3
- "version": "0.1.0",
4
- "description": "The hosted Keelcode coding agent CLI.",
5
- "type": "commonjs",
3
+ "version": "0.1.3-darwin-x64",
4
+ "description": "Native Keelcode executable for darwin-x64. Install the keelcode package instead.",
6
5
  "license": "SEE LICENSE IN LICENSE",
7
6
  "homepage": "https://keelcode.ai",
8
7
  "publishConfig": {
9
8
  "access": "public"
10
9
  },
11
- "bin": {
12
- "keelcode": "bin/keelcode.cjs",
13
- "kc": "bin/kc.cjs",
14
- "kcode": "bin/kcode.cjs",
15
- "keel": "bin/keel.cjs"
16
- },
17
- "files": [
18
- "bin/keelcode.cjs",
19
- "bin/kc.cjs",
20
- "bin/kcode.cjs",
21
- "bin/keel.cjs",
22
- "README.md",
23
- "LICENSE",
24
- "CHANGELOG.md",
25
- "SECURITY.md"
10
+ "os": [
11
+ "darwin"
26
12
  ],
27
- "engines": {
28
- "node": ">=20"
29
- },
30
- "keywords": [
31
- "cli",
32
- "agent",
33
- "ai",
34
- "hosted-ai",
35
- "coding-agent",
36
- "tui",
37
- "ink"
13
+ "cpu": [
14
+ "x64"
38
15
  ],
39
- "optionalDependencies": {
40
- "@keelcode-ai/keelcode-darwin-arm64": "npm:@keelcode-ai/keelcode@0.1.0-darwin-arm64",
41
- "@keelcode-ai/keelcode-darwin-x64": "npm:@keelcode-ai/keelcode@0.1.0-darwin-x64",
42
- "@keelcode-ai/keelcode-linux-arm64": "npm:@keelcode-ai/keelcode@0.1.0-linux-arm64",
43
- "@keelcode-ai/keelcode-linux-arm64-musl": "npm:@keelcode-ai/keelcode@0.1.0-linux-arm64-musl",
44
- "@keelcode-ai/keelcode-linux-x64": "npm:@keelcode-ai/keelcode@0.1.0-linux-x64",
45
- "@keelcode-ai/keelcode-linux-x64-musl": "npm:@keelcode-ai/keelcode@0.1.0-linux-x64-musl",
46
- "@keelcode-ai/keelcode-win32-arm64": "npm:@keelcode-ai/keelcode@0.1.0-win32-arm64",
47
- "@keelcode-ai/keelcode-win32-x64": "npm:@keelcode-ai/keelcode@0.1.0-win32-x64"
48
- }
16
+ "files": [
17
+ "bin/keelcode",
18
+ "bin/rg",
19
+ "LICENSE"
20
+ ]
49
21
  }
package/CHANGELOG.md DELETED
@@ -1,66 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to Keelcode will be documented in this file.
4
-
5
- The format is based on Keep a Changelog, and this project follows Semantic
6
- Versioning.
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
-
12
- - Add `kc`, `kcode`, and `keel` as packaged aliases for the `keelcode` command.
13
- - Add safe custom command aliases with `keelcode alias setup|add|list|remove`.
14
- - Show client-observed TTFT and provider-token TPS in interactive and headless
15
- output without mixing tool time into model throughput; keep interactive
16
- context and performance telemetry immediately above the input box.
17
- - Make the CLI hosted-only: `keelcode login` now owns the API origin and bearer
18
- session, while customer provider keys, custom endpoints, and `ANTHROPIC_*`
19
- transport configuration are ignored.
20
- - Add `/ship`, an objective-bound deliverable workflow whose runtime withholds
21
- completion until a persisted passing `Verify` receipt, a read-only final
22
- review, the cited receipt ID, and a stabilized Git fingerprint all agree.
23
- - Discover layered `AGENTS.md` and `KEELCODE.md` instructions from the Git root
24
- to the active directory with source provenance and bounded, symlink-safe reads.
25
- - Add stable `json` and streaming `jsonl` headless output formats with explicit
26
- terminal outcomes and automation-friendly exit codes.
27
- - Add lease-checked detached Git worktree primitives for repository-state
28
- isolation without claiming operating-system sandboxing.
29
- - Add standalone `proof list/show` and `worktree create/status/cleanup` commands
30
- so automation can inspect receipts and manage isolated runs without an API key.
31
- - Add an opt-in-aware World Cup match surface with a startup Match Centre,
32
- compact in-session scores, scorer-specific goal takeovers, and `/football`
33
- controls. Live provider traffic stays in the Keelcode backend.
34
-
35
- ### Security
36
-
37
- - Redact and cap persisted verification output, store receipts and worktree
38
- leases with owner-only POSIX permissions, and bound gate count and execution time.
39
- - Make Verify approvals fully scrollable and auditable, hard-limit observed
40
- output, show exact executable command text, reject destructive checks and
41
- common background syntax, detect residual children, and anchor local receipt
42
- bytes per ship run.
43
- - Hash actual tracked/untracked worktree bytes and submodules independently of
44
- Git stat-cache, filter, assume-unchanged, and skip-worktree behavior; isolate
45
- Git subprocesses from ambient `GIT_*` injection.
46
- - Reject symlinked private receipt roots and revalidate directory/file identity
47
- across receipt publication and reads.
48
- - Block WebFetch access to unsafe URL schemes, credentials, local/private
49
- networks, and unsafe redirect targets.
50
- - Store user transcripts, mission artifacts, caches, and crash logs with
51
- owner-only POSIX permissions.
52
- - Clarify that `bypassPermissions` is an explicit no-prompt mode while deny
53
- rules and tool hard denials remain enforced.
54
-
55
- ### Fixed
56
-
57
- - Reject Windows UNC paths before POSIX normalization can hide their form.
58
-
59
- ### Build
60
-
61
- - Standardize development, security auditing, packing, and CI on Bun.
62
- - Replace the unpublished JavaScript npm artifact with a small launcher and
63
- exact platform-suffixed versions of the single `keelcode` package name for
64
- macOS, Linux, and Windows on x64/arm64.
65
- - Fail release packing when source files, source maps, private metadata,
66
- upstream endpoints, or secret-shaped credentials appear in an npm artifact.
package/README.md DELETED
@@ -1,216 +0,0 @@
1
- # keelcode
2
-
3
- Keelcode is a hosted coding agent for your terminal. It can inspect a project,
4
- edit files, run commands, search the web, use MCP servers, and verify its work.
5
-
6
- ## Install
7
-
8
- Keelcode requires Node.js 20 or newer. Install it globally with Bun:
9
-
10
- ```bash
11
- bun add --global @keelcode-ai/keelcode
12
- ```
13
-
14
- The package provides four equivalent commands:
15
-
16
- ```text
17
- keelcode
18
- kc
19
- kcode
20
- keel
21
- ```
22
-
23
- To add your own command name after installation, run the guided setup or add
24
- one or more aliases directly:
25
-
26
- ```bash
27
- keelcode alias setup
28
- keelcode alias add mycode kk
29
- keelcode alias list
30
- keelcode alias remove kk
31
- ```
32
-
33
- Custom aliases are created beside the package-manager shims. Keelcode refuses
34
- to overwrite an existing command and never edits shell startup files. Package
35
- installation stays non-interactive so it remains reliable in terminals, CI,
36
- containers, and package managers that disable lifecycle scripts.
37
-
38
- The `@keelcode-ai/keelcode` npm package is a small launcher that installs the matching
39
- platform-suffixed version of that same package name for the current operating
40
- system, CPU, and Linux libc. Keelcode's
41
- application JavaScript, TypeScript, source maps, tests, and build configuration
42
- are not included in the public package.
43
-
44
- ## Sign in and start
45
-
46
- ```bash
47
- keelcode login
48
- keelcode
49
- ```
50
-
51
- If the machine cannot open a browser:
52
-
53
- ```bash
54
- keelcode login --no-browser
55
- ```
56
-
57
- Keelcode will also start sign-in automatically when an interactive session has
58
- no usable account. Authentication uses a short-lived device approval; provider
59
- credentials are never stored in the CLI.
60
-
61
- Useful account commands:
62
-
63
- ```bash
64
- keelcode whoami
65
- keelcode usage
66
- keelcode logout
67
- ```
68
-
69
- ## Everyday use
70
-
71
- Start in the current project:
72
-
73
- ```bash
74
- keelcode
75
- ```
76
-
77
- Run one prompt without opening the TUI:
78
-
79
- ```bash
80
- keelcode -p "find and fix the failing test"
81
- git diff | keelcode -p "review this diff"
82
- ```
83
-
84
- Resume work:
85
-
86
- ```bash
87
- keelcode -c
88
- keelcode sessions
89
- keelcode --resume 2
90
- ```
91
-
92
- Choose a model at launch:
93
-
94
- ```bash
95
- keelcode --model <model-alias>
96
- ```
97
-
98
- Inside the TUI, use `/models` to open the current model picker and `/usage` to
99
- see the remaining hosted allowance. Run `/help` for the complete command list.
100
- The footer reports client-observed `ttft` and `tps` for the latest model turn.
101
- TTFT includes network and gateway latency; TPS uses provider-reported output
102
- tokens and excludes tool execution. A dash is shown when the stream does not
103
- contain enough timing or usage information for an honest measurement.
104
-
105
- Measure local launcher startup:
106
-
107
- ```bash
108
- keelcode bench
109
- keelcode bench --json
110
- ```
111
-
112
- The benchmark runs the installed launcher repeatedly, reports median/p90/min/max
113
- latency, and is useful for comparing terminals, package managers, and releases.
114
-
115
- ## Common options
116
-
117
- ```text
118
- -m, --model <alias> choose a Keelcode model
119
- --permission-mode <m> default | plan | acceptEdits | bypassPermissions
120
- --yolo bypass permission prompts in trusted environments
121
- --cwd <dir> set the working directory
122
- --icons <set> unicode | nerd | ascii | auto
123
- --no-alt-screen keep output in the main terminal buffer
124
- -c, --continue resume the newest session in this directory
125
- --resume [id] resume by id/index; no argument lists sessions
126
- -p, --print [prompt] run one headless prompt
127
- --output-format <f> text | json | jsonl
128
- -h, --help show help
129
- -v, --version show the installed version
130
- ```
131
-
132
- `bypassPermissions` and `--yolo` remove confirmation prompts. Only use them in
133
- an environment where every repository instruction and command is trusted.
134
-
135
- ## Configuration
136
-
137
- Settings merge in this order, with later files winning:
138
-
139
- 1. `~/.keelcode/settings.json`
140
- 2. `<project>/.keelcode/settings.json`
141
- 3. `<project>/.keelcode/settings.local.json`
142
- 4. command-line flags
143
-
144
- Example project configuration:
145
-
146
- ```json
147
- {
148
- "model": "<model-alias>",
149
- "permissionMode": "default",
150
- "maxTurns": 100,
151
- "timeoutMs": 600000,
152
- "permissions": {
153
- "allow": ["Read", "Grep", "Glob"],
154
- "ask": ["Bash", "Write", "Edit"],
155
- "deny": ["Write(/etc/**)"]
156
- }
157
- }
158
- ```
159
-
160
- Use `.keelcode/settings.local.json` for personal overrides and keep it out of
161
- version control. Keelcode does not support bring-your-own-provider keys.
162
-
163
- ## MCP and skills
164
-
165
- Inspect extension health:
166
-
167
- ```bash
168
- keelcode doctor
169
- keelcode mcp list
170
- keelcode skills list
171
- keelcode import list
172
- ```
173
-
174
- Use `keelcode mcp --help` and `keelcode skills --help` for management commands.
175
- MCP tools pass through the same permission checks as built-in tools.
176
-
177
- ## Automation
178
-
179
- For scripts and CI, prefer structured headless output:
180
-
181
- ```bash
182
- keelcode -p "run the tests and summarize failures" --output-format json
183
- keelcode -p "review this repository" --output-format jsonl
184
- ```
185
-
186
- Human progress is written to stderr. Machine-readable results are written to
187
- stdout, so redirecting stdout does not mix logs into the protocol.
188
- Model performance is written to stderr in text mode and included as structured
189
- `performance` data in JSON/JSONL output.
190
-
191
- ## Local data and privacy
192
-
193
- Keelcode stores account sessions, settings, conversations, caches, and local
194
- receipts under `~/.keelcode`. Sensitive state uses owner-only permissions on
195
- supported POSIX systems.
196
-
197
- Anonymous product analytics are opt-in and can be controlled at any time:
198
-
199
- ```bash
200
- keelcode telemetry status
201
- keelcode telemetry enable
202
- keelcode telemetry disable
203
- ```
204
-
205
- Do not paste production secrets into prompts or commit `.keelcode` personal
206
- state to a repository.
207
-
208
- ## Security
209
-
210
- Report suspected vulnerabilities privately to `security@keelcode.ai`. Do not
211
- include real credentials or unrelated private data in a report.
212
-
213
- ## License
214
-
215
- Keelcode is proprietary software. Installation and use are governed by the
216
- license included with this package and the applicable Keelcode service terms.
package/SECURITY.md DELETED
@@ -1,23 +0,0 @@
1
- # Security Policy
2
-
3
- ## Supported versions
4
-
5
- Security fixes are provided for the latest published version of Keelcode.
6
-
7
- ## Reporting a vulnerability
8
-
9
- Please do not disclose an unpatched vulnerability publicly. Email
10
- `security@keelcode.ai` with the affected version, reproduction steps, impact,
11
- and any suggested mitigation.
12
-
13
- Avoid including real API keys, proprietary source code, or other sensitive data
14
- in a report. We will acknowledge a complete report as soon as practical and
15
- coordinate disclosure after a fix is available.
16
-
17
- ## Local data
18
-
19
- Keelcode persists conversations, mission records, downloaded skills, model
20
- metadata, and crash diagnostics under `~/.keelcode` by default. On POSIX systems,
21
- Keelcode creates its private state directories with mode `0700` and sensitive
22
- files with mode `0600`. Users remain responsible for securing backups and any
23
- custom path supplied through `KEELCODE_CONFIG_DIR`.
package/bin/kc.cjs DELETED
@@ -1,325 +0,0 @@
1
- #!/usr/bin/env node
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.0"
19
- const TARGETS = {
20
- "darwin-arm64": {
21
- "packageName": "@keelcode-ai/keelcode-darwin-arm64",
22
- "packageVersion": "0.1.0-darwin-arm64",
23
- "executableName": "keelcode",
24
- "ripgrepExecutableName": "rg"
25
- },
26
- "darwin-x64": {
27
- "packageName": "@keelcode-ai/keelcode-darwin-x64",
28
- "packageVersion": "0.1.0-darwin-x64",
29
- "executableName": "keelcode",
30
- "ripgrepExecutableName": "rg"
31
- },
32
- "linux-arm64": {
33
- "packageName": "@keelcode-ai/keelcode-linux-arm64",
34
- "packageVersion": "0.1.0-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.0-linux-arm64-musl",
41
- "executableName": "keelcode",
42
- "ripgrepExecutableName": "rg"
43
- },
44
- "linux-x64": {
45
- "packageName": "@keelcode-ai/keelcode-linux-x64",
46
- "packageVersion": "0.1.0-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.0-linux-x64-musl",
53
- "executableName": "keelcode",
54
- "ripgrepExecutableName": "rg"
55
- },
56
- "win32-arm64": {
57
- "packageName": "@keelcode-ai/keelcode-win32-arm64",
58
- "packageVersion": "0.1.0-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.0-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)))