voyageai-cli 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +21 -0
- package/CHANGELOG.md +50 -0
- package/CONTRIBUTING.md +81 -0
- package/README.md +51 -2
- package/package.json +9 -2
- package/src/cli.js +18 -1
- package/src/commands/config.js +157 -0
- package/src/commands/demo.js +353 -0
- package/src/commands/embed.js +22 -8
- package/src/commands/index.js +54 -23
- package/src/commands/models.js +15 -7
- package/src/commands/ping.js +169 -0
- package/src/commands/rerank.js +21 -7
- package/src/commands/search.js +23 -10
- package/src/commands/store.js +45 -27
- package/src/lib/api.js +9 -5
- package/src/lib/banner.js +55 -0
- package/src/lib/catalog.js +20 -0
- package/src/lib/config.js +107 -0
- package/src/lib/mongo.js +6 -4
- package/src/lib/ui.js +47 -0
- package/test/commands/config.test.js +35 -0
- package/test/commands/demo.test.js +46 -0
- package/test/commands/models.test.js +89 -0
- package/test/commands/ping.test.js +155 -0
- package/test/lib/api.test.js +125 -0
- package/test/lib/banner.test.js +44 -0
- package/test/lib/catalog.test.js +67 -0
- package/test/lib/config.test.js +124 -0
- package/test/lib/format.test.js +75 -0
- package/test/lib/input.test.js +48 -0
- package/test/lib/ui.test.js +79 -0
- package/voyageai-cli-1.1.0.tgz +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
node-version: [18, 20, 22]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: ${{ matrix.node-version }}
|
|
20
|
+
- run: npm ci
|
|
21
|
+
- run: npm test
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to voyageai-cli are documented here.
|
|
4
|
+
|
|
5
|
+
Format based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `vai demo` — Interactive guided walkthrough of all features
|
|
11
|
+
- ASCII banner when running `vai` with no arguments
|
|
12
|
+
- CONTRIBUTING.md for open-source contributors
|
|
13
|
+
- This changelog
|
|
14
|
+
|
|
15
|
+
## [1.1.0] - 2026-02-03
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- `vai config` — Persistent config management (`~/.vai/config.json`)
|
|
19
|
+
- `set`, `get`, `delete`, `path`, `reset` subcommands
|
|
20
|
+
- Secrets masked in output, config file chmod 600
|
|
21
|
+
- `--stdin` flag for secure key input (avoids shell history)
|
|
22
|
+
- `vai ping` — Test API and MongoDB connectivity
|
|
23
|
+
- `.env` file support via dotenv
|
|
24
|
+
- Colored output with picocolors (green ✓, red ✗, score-based colors)
|
|
25
|
+
- Animated spinners on all network operations
|
|
26
|
+
- npm update notifier (checks daily, non-blocking)
|
|
27
|
+
- GitHub Actions CI (Node 18, 20, 22)
|
|
28
|
+
- README badges (CI, npm, license, node version)
|
|
29
|
+
- Credential priority chain: env var → .env → config file
|
|
30
|
+
- Security documentation in README
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
- `ping` command now falls back to config file for API key and MongoDB URI
|
|
34
|
+
- `rerank` endpoint corrected from `/v1/reranking` to `/v1/rerank`
|
|
35
|
+
- `index create` parseInt handling for dimensions (was producing NaN)
|
|
36
|
+
|
|
37
|
+
## [1.0.0] - 2026-02-03
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- `vai embed` — Generate embeddings (text, file, stdin, bulk)
|
|
41
|
+
- `vai rerank` — Rerank documents with relevance scoring
|
|
42
|
+
- `vai store` — Embed and insert into MongoDB Atlas (single + batch JSONL)
|
|
43
|
+
- `vai search` — $vectorSearch with pre-filter support
|
|
44
|
+
- `vai index` — Create, list, delete Atlas Vector Search indexes
|
|
45
|
+
- `vai models` — List available Voyage AI models with pricing
|
|
46
|
+
- REST API integration with `https://ai.mongodb.com/v1/`
|
|
47
|
+
- MongoDB Atlas Vector Search integration
|
|
48
|
+
- API retry on 429 with exponential backoff
|
|
49
|
+
- `--json` and `--quiet` flags on all commands
|
|
50
|
+
- 50+ unit tests
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Contributing to voyageai-cli
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! Here's how to get started.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/mrlynn/voyageai-cli.git
|
|
9
|
+
cd voyageai-cli
|
|
10
|
+
npm install
|
|
11
|
+
npm link # makes `vai` available globally for testing
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Running Tests
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm test
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Tests use Node.js built-in test runner (`node:test`). No external test framework needed.
|
|
21
|
+
|
|
22
|
+
## Project Structure
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
src/
|
|
26
|
+
├── cli.js # Entry point
|
|
27
|
+
├── commands/ # One file per command
|
|
28
|
+
│ ├── embed.js
|
|
29
|
+
│ ├── rerank.js
|
|
30
|
+
│ ├── store.js
|
|
31
|
+
│ ├── search.js
|
|
32
|
+
│ ├── index.js
|
|
33
|
+
│ ├── models.js
|
|
34
|
+
│ ├── ping.js
|
|
35
|
+
│ ├── config.js
|
|
36
|
+
│ └── demo.js
|
|
37
|
+
└── lib/ # Shared utilities
|
|
38
|
+
├── api.js # Voyage AI API client
|
|
39
|
+
├── mongo.js # MongoDB connection
|
|
40
|
+
├── catalog.js # Model catalog
|
|
41
|
+
├── config.js # Config file management
|
|
42
|
+
├── format.js # Table formatting
|
|
43
|
+
├── input.js # Text input resolution
|
|
44
|
+
├── ui.js # Colors, spinners, output helpers
|
|
45
|
+
└── banner.js # ASCII banner
|
|
46
|
+
test/
|
|
47
|
+
├── commands/ # Command tests
|
|
48
|
+
└── lib/ # Library tests
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Adding a New Command
|
|
52
|
+
|
|
53
|
+
1. Create `src/commands/mycommand.js` exporting a `registerMyCommand(program)` function
|
|
54
|
+
2. Register it in `src/cli.js`
|
|
55
|
+
3. Add tests in `test/commands/mycommand.test.js`
|
|
56
|
+
4. Update README.md with usage examples
|
|
57
|
+
|
|
58
|
+
## Code Style
|
|
59
|
+
|
|
60
|
+
- CommonJS (`require`/`module.exports`)
|
|
61
|
+
- `'use strict';` at the top of every file
|
|
62
|
+
- JSDoc comments on exported functions
|
|
63
|
+
- `parseInt(x, 10)` — always include radix
|
|
64
|
+
- Errors go to stderr (`console.error`)
|
|
65
|
+
- Support `--json` and `--quiet` flags on all commands
|
|
66
|
+
- No colors or spinners in `--json` mode
|
|
67
|
+
|
|
68
|
+
## Pull Requests
|
|
69
|
+
|
|
70
|
+
- Create a feature branch from `main`
|
|
71
|
+
- Include tests for new functionality
|
|
72
|
+
- Run `npm test` before submitting
|
|
73
|
+
- Write clear commit messages
|
|
74
|
+
|
|
75
|
+
## Reporting Issues
|
|
76
|
+
|
|
77
|
+
Open an issue at https://github.com/mrlynn/voyageai-cli/issues with:
|
|
78
|
+
- Node.js version (`node --version`)
|
|
79
|
+
- OS and version
|
|
80
|
+
- Steps to reproduce
|
|
81
|
+
- Expected vs actual behavior
|
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# voyageai-cli
|
|
2
2
|
|
|
3
|
+
[](https://github.com/mrlynn/voyageai-cli/actions/workflows/ci.yml) [](https://www.npmjs.com/package/voyageai-cli) [](https://opensource.org/licenses/MIT) [](https://nodejs.org)
|
|
4
|
+
|
|
3
5
|
CLI for [Voyage AI](https://www.mongodb.com/docs/voyageai/) embeddings, reranking, and [MongoDB Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/). Pure Node.js — no Python required.
|
|
4
6
|
|
|
5
7
|
Generate embeddings, rerank search results, store vectors in Atlas, and run semantic search — all from the command line.
|
|
@@ -110,6 +112,20 @@ vai index list --db myapp --collection docs
|
|
|
110
112
|
vai index delete --db myapp --collection docs --index-name my_index
|
|
111
113
|
```
|
|
112
114
|
|
|
115
|
+
### `vai ping` — Test API connectivity
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Test Voyage AI API
|
|
119
|
+
vai ping
|
|
120
|
+
|
|
121
|
+
# Also tests MongoDB if MONGODB_URI is set
|
|
122
|
+
export MONGODB_URI="mongodb+srv://user:pass@cluster.mongodb.net/"
|
|
123
|
+
vai ping
|
|
124
|
+
|
|
125
|
+
# JSON output
|
|
126
|
+
vai ping --json
|
|
127
|
+
```
|
|
128
|
+
|
|
113
129
|
### `vai models` — List available models
|
|
114
130
|
|
|
115
131
|
```bash
|
|
@@ -154,8 +170,41 @@ vai rerank --query "how does cloud database work" \
|
|
|
154
170
|
|
|
155
171
|
| Variable | Required For | Description |
|
|
156
172
|
|----------|-------------|-------------|
|
|
157
|
-
| `VOYAGE_API_KEY` | embed, rerank, store, search | [Model API key](https://www.mongodb.com/docs/voyageai/management/api-keys/) from MongoDB Atlas |
|
|
158
|
-
| `MONGODB_URI` | store, search, index | MongoDB Atlas connection string |
|
|
173
|
+
| `VOYAGE_API_KEY` | embed, rerank, store, search, ping | [Model API key](https://www.mongodb.com/docs/voyageai/management/api-keys/) from MongoDB Atlas |
|
|
174
|
+
| `MONGODB_URI` | store, search, index, ping (optional) | MongoDB Atlas connection string |
|
|
175
|
+
|
|
176
|
+
Credentials are resolved in this order (highest priority first):
|
|
177
|
+
|
|
178
|
+
1. **Environment variables** (`export VOYAGE_API_KEY=...`)
|
|
179
|
+
2. **`.env` file** in your working directory
|
|
180
|
+
3. **Config file** (`~/.vai/config.json` via `vai config set`)
|
|
181
|
+
|
|
182
|
+
You can also create a `.env` file in your project directory instead of exporting variables:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
VOYAGE_API_KEY=your-key
|
|
186
|
+
MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
> ⚠️ **Add `.env` to your `.gitignore`** to avoid accidentally committing secrets.
|
|
190
|
+
|
|
191
|
+
Or use the built-in config store:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Pipe to avoid key appearing in shell history
|
|
195
|
+
echo "your-key" | vai config set api-key --stdin
|
|
196
|
+
vai config set mongodb-uri "mongodb+srv://user:pass@cluster.mongodb.net/"
|
|
197
|
+
|
|
198
|
+
# Verify (secrets are masked)
|
|
199
|
+
vai config get
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Security
|
|
203
|
+
|
|
204
|
+
- Config file (`~/.vai/config.json`) is created with `600` permissions (owner read/write only)
|
|
205
|
+
- Secrets are always masked in `vai config get` output
|
|
206
|
+
- Use `echo "key" | vai config set api-key --stdin` or `vai config set api-key --stdin < keyfile` to avoid shell history exposure
|
|
207
|
+
- The config file stores credentials in plaintext (similar to `~/.aws/credentials` and `~/.npmrc`) — protect your home directory accordingly
|
|
159
208
|
|
|
160
209
|
## Global Flags
|
|
161
210
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voyageai-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "CLI for Voyage AI embeddings, reranking, and MongoDB Atlas Vector Search",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vai": "./src/cli.js"
|
|
@@ -27,11 +27,18 @@
|
|
|
27
27
|
"bugs": {
|
|
28
28
|
"url": "https://github.com/mrlynn/voyageai-cli/issues"
|
|
29
29
|
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test": "node --test test/**/*.test.js"
|
|
32
|
+
},
|
|
30
33
|
"engines": {
|
|
31
34
|
"node": ">=18.0.0"
|
|
32
35
|
},
|
|
33
36
|
"dependencies": {
|
|
34
37
|
"commander": "^12.0.0",
|
|
35
|
-
"
|
|
38
|
+
"dotenv": "^17.2.3",
|
|
39
|
+
"mongodb": "^6.0.0",
|
|
40
|
+
"ora": "^9.1.0",
|
|
41
|
+
"picocolors": "^1.1.1",
|
|
42
|
+
"update-notifier": "^7.3.1"
|
|
36
43
|
}
|
|
37
44
|
}
|
package/src/cli.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
require('dotenv').config({ quiet: true });
|
|
5
|
+
|
|
4
6
|
const { program } = require('commander');
|
|
5
7
|
const { registerEmbed } = require('./commands/embed');
|
|
6
8
|
const { registerRerank } = require('./commands/rerank');
|
|
@@ -8,11 +10,15 @@ const { registerStore } = require('./commands/store');
|
|
|
8
10
|
const { registerSearch } = require('./commands/search');
|
|
9
11
|
const { registerIndex } = require('./commands/index');
|
|
10
12
|
const { registerModels } = require('./commands/models');
|
|
13
|
+
const { registerPing } = require('./commands/ping');
|
|
14
|
+
const { registerConfig } = require('./commands/config');
|
|
15
|
+
const { registerDemo } = require('./commands/demo');
|
|
16
|
+
const { showBanner, showQuickStart } = require('./lib/banner');
|
|
11
17
|
|
|
12
18
|
program
|
|
13
19
|
.name('vai')
|
|
14
20
|
.description('Voyage AI embeddings, reranking, and Atlas Vector Search CLI')
|
|
15
|
-
.version('1.
|
|
21
|
+
.version('1.1.0');
|
|
16
22
|
|
|
17
23
|
registerEmbed(program);
|
|
18
24
|
registerRerank(program);
|
|
@@ -20,5 +26,16 @@ registerStore(program);
|
|
|
20
26
|
registerSearch(program);
|
|
21
27
|
registerIndex(program);
|
|
22
28
|
registerModels(program);
|
|
29
|
+
registerPing(program);
|
|
30
|
+
registerConfig(program);
|
|
31
|
+
registerDemo(program);
|
|
32
|
+
|
|
33
|
+
// If no args (just `vai`), show banner + quick start + help
|
|
34
|
+
if (process.argv.length <= 2) {
|
|
35
|
+
showBanner();
|
|
36
|
+
showQuickStart();
|
|
37
|
+
program.outputHelp();
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
23
40
|
|
|
24
41
|
program.parse();
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const {
|
|
5
|
+
CONFIG_PATH,
|
|
6
|
+
KEY_MAP,
|
|
7
|
+
SECRET_KEYS,
|
|
8
|
+
loadConfig,
|
|
9
|
+
saveConfig,
|
|
10
|
+
getConfigValue,
|
|
11
|
+
setConfigValue,
|
|
12
|
+
deleteConfigValue,
|
|
13
|
+
maskSecret,
|
|
14
|
+
} = require('../lib/config');
|
|
15
|
+
const ui = require('../lib/ui');
|
|
16
|
+
|
|
17
|
+
const VALID_KEYS = Object.keys(KEY_MAP);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register the config command on a Commander program.
|
|
21
|
+
* @param {import('commander').Command} program
|
|
22
|
+
*/
|
|
23
|
+
function registerConfig(program) {
|
|
24
|
+
const configCmd = program
|
|
25
|
+
.command('config')
|
|
26
|
+
.description('Manage persistent configuration (~/.vai/config.json)');
|
|
27
|
+
|
|
28
|
+
// ── config set <key> [value] ──
|
|
29
|
+
configCmd
|
|
30
|
+
.command('set <key> [value]')
|
|
31
|
+
.description('Set a config value (omit value to read from stdin)')
|
|
32
|
+
.option('--stdin', 'Read value from stdin (avoids shell history exposure)')
|
|
33
|
+
.action(async (key, value, opts) => {
|
|
34
|
+
const internalKey = KEY_MAP[key];
|
|
35
|
+
if (!internalKey) {
|
|
36
|
+
console.error(ui.error(`Unknown config key "${ui.cyan(key)}".`));
|
|
37
|
+
console.error(`Valid keys: ${VALID_KEYS.join(', ')}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Read from stdin if no value provided or --stdin flag
|
|
42
|
+
if (!value || opts.stdin) {
|
|
43
|
+
if (process.stdin.isTTY && !value) {
|
|
44
|
+
// Interactive: prompt without echo for secrets
|
|
45
|
+
const isSecret = SECRET_KEYS.has(internalKey);
|
|
46
|
+
if (isSecret) {
|
|
47
|
+
process.stderr.write(`Enter ${key}: `);
|
|
48
|
+
} else {
|
|
49
|
+
process.stderr.write(`Enter ${key}: `);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!value) {
|
|
53
|
+
const chunks = [];
|
|
54
|
+
for await (const chunk of process.stdin) {
|
|
55
|
+
chunks.push(chunk);
|
|
56
|
+
}
|
|
57
|
+
value = Buffer.concat(chunks).toString('utf-8').trim();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!value) {
|
|
62
|
+
console.error(ui.error('No value provided.'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Parse numeric values for dimensions
|
|
67
|
+
const storedValue = key === 'default-dimensions' ? parseInt(value, 10) : value;
|
|
68
|
+
setConfigValue(internalKey, storedValue);
|
|
69
|
+
console.log(ui.success(`Set ${ui.cyan(key)} = ${SECRET_KEYS.has(internalKey) ? ui.dim(maskSecret(String(storedValue))) : storedValue}`));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// ── config get [key] ──
|
|
73
|
+
configCmd
|
|
74
|
+
.command('get [key]')
|
|
75
|
+
.description('Get a config value (or all if no key)')
|
|
76
|
+
.action((key) => {
|
|
77
|
+
if (key) {
|
|
78
|
+
const internalKey = KEY_MAP[key];
|
|
79
|
+
if (!internalKey) {
|
|
80
|
+
console.error(ui.error(`Unknown config key "${ui.cyan(key)}".`));
|
|
81
|
+
console.error(`Valid keys: ${VALID_KEYS.join(', ')}`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const value = getConfigValue(internalKey);
|
|
86
|
+
if (value === undefined) {
|
|
87
|
+
console.log(`${ui.cyan(key)}: ${ui.dim('(not set)')}`);
|
|
88
|
+
} else {
|
|
89
|
+
const display = SECRET_KEYS.has(internalKey) ? ui.dim(maskSecret(String(value))) : value;
|
|
90
|
+
console.log(`${ui.cyan(key)}: ${display}`);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
// Show all config
|
|
94
|
+
const config = loadConfig();
|
|
95
|
+
if (Object.keys(config).length === 0) {
|
|
96
|
+
console.log(ui.dim('No configuration set.'));
|
|
97
|
+
console.log(`Run: ${ui.cyan('vai config set <key> <value>')}`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build a reverse map: internalKey → cliKey
|
|
102
|
+
const reverseMap = {};
|
|
103
|
+
for (const [cliKey, intKey] of Object.entries(KEY_MAP)) {
|
|
104
|
+
reverseMap[intKey] = cliKey;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
for (const [intKey, value] of Object.entries(config)) {
|
|
108
|
+
const cliKey = reverseMap[intKey] || intKey;
|
|
109
|
+
const display = SECRET_KEYS.has(intKey) ? ui.dim(maskSecret(String(value))) : value;
|
|
110
|
+
console.log(`${ui.cyan(cliKey)}: ${display}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ── config delete <key> ──
|
|
116
|
+
configCmd
|
|
117
|
+
.command('delete <key>')
|
|
118
|
+
.description('Remove a config value')
|
|
119
|
+
.action((key) => {
|
|
120
|
+
const internalKey = KEY_MAP[key];
|
|
121
|
+
if (!internalKey) {
|
|
122
|
+
console.error(ui.error(`Unknown config key "${ui.cyan(key)}".`));
|
|
123
|
+
console.error(`Valid keys: ${VALID_KEYS.join(', ')}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
deleteConfigValue(internalKey);
|
|
128
|
+
console.log(ui.success(`Deleted ${ui.cyan(key)}`));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ── config path ──
|
|
132
|
+
configCmd
|
|
133
|
+
.command('path')
|
|
134
|
+
.description('Print the config file path')
|
|
135
|
+
.action(() => {
|
|
136
|
+
console.log(CONFIG_PATH);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ── config reset ──
|
|
140
|
+
configCmd
|
|
141
|
+
.command('reset')
|
|
142
|
+
.description('Delete the entire config file')
|
|
143
|
+
.action(() => {
|
|
144
|
+
try {
|
|
145
|
+
fs.unlinkSync(CONFIG_PATH);
|
|
146
|
+
console.log(ui.success(`Config file deleted: ${ui.dim(CONFIG_PATH)}`));
|
|
147
|
+
} catch (err) {
|
|
148
|
+
if (err.code === 'ENOENT') {
|
|
149
|
+
console.log(ui.dim('No config file found. Nothing to reset.'));
|
|
150
|
+
} else {
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
module.exports = { registerConfig };
|