voyageai-cli 1.12.0 → 1.13.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/README.md +3 -3
- package/demo-readme.gif +0 -0
- package/package.json +4 -1
- package/src/commands/models.js +3 -3
- package/src/commands/ping.js +32 -2
- package/src/commands/playground.js +1 -1
- package/src/commands/search.js +2 -2
- package/src/commands/store.js +1 -1
- package/src/lib/api.js +18 -14
- package/src/lib/catalog.js +3 -3
- package/.github/workflows/ci.yml +0 -22
- package/CONTRIBUTING.md +0 -81
- package/demo.gif +0 -0
- package/demo.tape +0 -39
- package/scripts/record-demo.sh +0 -63
- package/test/commands/about.test.js +0 -23
- package/test/commands/benchmark.test.js +0 -319
- package/test/commands/completions.test.js +0 -166
- package/test/commands/config.test.js +0 -35
- package/test/commands/demo.test.js +0 -46
- package/test/commands/embed.test.js +0 -42
- package/test/commands/explain.test.js +0 -207
- package/test/commands/ingest.test.js +0 -261
- package/test/commands/models.test.js +0 -132
- package/test/commands/ping.test.js +0 -172
- package/test/commands/playground.test.js +0 -137
- package/test/commands/rerank.test.js +0 -32
- package/test/commands/similarity.test.js +0 -79
- package/test/commands/store.test.js +0 -26
- package/test/fixtures/sample.csv +0 -6
- package/test/fixtures/sample.json +0 -7
- package/test/fixtures/sample.jsonl +0 -5
- package/test/fixtures/sample.txt +0 -5
- package/test/lib/api.test.js +0 -134
- package/test/lib/banner.test.js +0 -44
- package/test/lib/catalog.test.js +0 -99
- package/test/lib/config.test.js +0 -124
- package/test/lib/explanations.test.js +0 -141
- package/test/lib/format.test.js +0 -75
- package/test/lib/input.test.js +0 -48
- package/test/lib/math.test.js +0 -43
- package/test/lib/ui.test.js +0 -79
- package/voyageai-cli-playground.png +0 -0
- package/voyageai-cli.png +0 -0
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# voyageai-cli
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src="https://raw.githubusercontent.com/mrlynn/voyageai-cli/main/
|
|
4
|
+
<img src="https://raw.githubusercontent.com/mrlynn/voyageai-cli/main/demo-readme.gif" alt="voyageai-cli demo" width="800" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
[](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)
|
|
8
8
|
|
|
9
|
-
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.
|
|
9
|
+
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/). Embed text, benchmark models, compare quantization tradeoffs, and search — all from the terminal. Pure Node.js — no Python required.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**16 commands · 201 tests · Interactive playground · Quantization benchmarks**
|
|
12
12
|
|
|
13
13
|
> **⚠️ Disclaimer:** This is an independent, community-built tool. It is **not** an official product of MongoDB, Inc. or Voyage AI. It is not supported, endorsed, or maintained by either company. For official documentation, support, and products, visit:
|
|
14
14
|
> - **MongoDB:** [mongodb.com](https://www.mongodb.com) | [MongoDB Atlas](https://www.mongodb.com/atlas) | [Support](https://support.mongodb.com)
|
package/demo-readme.gif
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voyageai-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "CLI for Voyage AI embeddings, reranking, and MongoDB Atlas Vector Search",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vai": "./src/cli.js"
|
|
@@ -40,5 +40,8 @@
|
|
|
40
40
|
"ora": "^9.1.0",
|
|
41
41
|
"picocolors": "^1.1.1",
|
|
42
42
|
"update-notifier": "^7.3.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"playwright": "^1.58.1"
|
|
43
46
|
}
|
|
44
47
|
}
|
package/src/commands/models.js
CHANGED
|
@@ -53,7 +53,7 @@ function registerModels(program) {
|
|
|
53
53
|
const legacyModels = models.filter(m => m.legacy);
|
|
54
54
|
|
|
55
55
|
if (opts.type !== 'all') {
|
|
56
|
-
models = models.filter(m => m.type === opts.type);
|
|
56
|
+
models = models.filter(m => opts.type === 'embedding' ? m.type.startsWith('embedding') : m.type === opts.type);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
if (!showLegacy) {
|
|
@@ -84,14 +84,14 @@ function registerModels(program) {
|
|
|
84
84
|
|
|
85
85
|
const formatWideRow = (m) => {
|
|
86
86
|
const name = ui.cyan(m.name);
|
|
87
|
-
const type = m.type
|
|
87
|
+
const type = m.type.startsWith('embedding') ? ui.green(m.type) : ui.yellow(m.type);
|
|
88
88
|
const price = ui.dim(m.price);
|
|
89
89
|
return [name, type, m.context, m.dimensions, price, m.bestFor];
|
|
90
90
|
};
|
|
91
91
|
|
|
92
92
|
const formatCompactRow = (m) => {
|
|
93
93
|
const name = ui.cyan(m.name);
|
|
94
|
-
const type = m.type
|
|
94
|
+
const type = m.type.startsWith('embedding') ? ui.green(m.multimodal ? 'multi' : 'embed') : ui.yellow('rerank');
|
|
95
95
|
const dims = compactDimensions(m.dimensions);
|
|
96
96
|
const price = ui.dim(compactPrice(m.price));
|
|
97
97
|
return [name, type, dims, price, m.shortFor || m.bestFor];
|
package/src/commands/ping.js
CHANGED
|
@@ -13,7 +13,12 @@ function registerPing(program) {
|
|
|
13
13
|
.description('Test connectivity to Voyage AI API (and optionally MongoDB)')
|
|
14
14
|
.option('--json', 'Machine-readable JSON output')
|
|
15
15
|
.option('-q, --quiet', 'Suppress non-essential output')
|
|
16
|
+
.option('--mask', 'Mask sensitive info (cluster hostnames, endpoints) in output. Also enabled by VAI_MASK=1 env var.')
|
|
16
17
|
.action(async (opts) => {
|
|
18
|
+
// Support env var so all recordings are masked without remembering the flag
|
|
19
|
+
if (process.env.VAI_MASK === '1' || process.env.VAI_MASK === 'true') {
|
|
20
|
+
opts.mask = true;
|
|
21
|
+
}
|
|
17
22
|
const results = {};
|
|
18
23
|
|
|
19
24
|
// ── Voyage AI ping ──
|
|
@@ -28,6 +33,31 @@ function registerPing(program) {
|
|
|
28
33
|
const useColor = !opts.json;
|
|
29
34
|
const useSpinner = useColor && !opts.quiet;
|
|
30
35
|
|
|
36
|
+
// Masking helper: "performance.zbcul.mongodb.net" → "perfo*****.mongodb.net"
|
|
37
|
+
const PUBLIC_HOSTS = ['ai.mongodb.com', 'api.voyageai.com'];
|
|
38
|
+
const maskHost = (host) => {
|
|
39
|
+
if (!opts.mask || !host) return host;
|
|
40
|
+
if (PUBLIC_HOSTS.includes(host)) return host;
|
|
41
|
+
const parts = host.split('.');
|
|
42
|
+
if (parts.length >= 3) {
|
|
43
|
+
const name = parts[0];
|
|
44
|
+
const masked = name.slice(0, Math.min(5, name.length)) + '*****';
|
|
45
|
+
return [masked, ...parts.slice(1)].join('.');
|
|
46
|
+
}
|
|
47
|
+
return host.slice(0, 5) + '*****';
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const maskUrl = (url) => {
|
|
51
|
+
if (!opts.mask || !url) return url;
|
|
52
|
+
try {
|
|
53
|
+
const u = new URL(url);
|
|
54
|
+
u.hostname = maskHost(u.hostname);
|
|
55
|
+
return u.toString().replace(/\/$/, '');
|
|
56
|
+
} catch {
|
|
57
|
+
return url;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
31
61
|
const apiBase = getApiBase();
|
|
32
62
|
const model = 'voyage-4-lite';
|
|
33
63
|
const startTime = Date.now();
|
|
@@ -94,7 +124,7 @@ function registerPing(program) {
|
|
|
94
124
|
console.log(`ok ${elapsed}ms`);
|
|
95
125
|
} else {
|
|
96
126
|
console.log(ui.success(`Connected to Voyage AI API ${ui.dim('(' + elapsed + 'ms)')}`));
|
|
97
|
-
console.log(ui.label('Endpoint', apiBase));
|
|
127
|
+
console.log(ui.label('Endpoint', maskUrl(apiBase)));
|
|
98
128
|
console.log(ui.label('Model', model));
|
|
99
129
|
console.log(ui.label('Dimensions', String(dims)));
|
|
100
130
|
console.log(ui.label('Tokens', String(tokens)));
|
|
@@ -145,7 +175,7 @@ function registerPing(program) {
|
|
|
145
175
|
if (!opts.json && !opts.quiet) {
|
|
146
176
|
console.log('');
|
|
147
177
|
console.log(ui.success(`Connected to MongoDB Atlas ${ui.dim('(' + mongoElapsed + 'ms)')}`));
|
|
148
|
-
console.log(ui.label('Cluster', cluster));
|
|
178
|
+
console.log(ui.label('Cluster', maskHost(cluster)));
|
|
149
179
|
}
|
|
150
180
|
|
|
151
181
|
await client.close();
|
|
@@ -84,7 +84,7 @@ function createPlaygroundServer() {
|
|
|
84
84
|
|
|
85
85
|
// API: Models
|
|
86
86
|
if (req.method === 'GET' && req.url === '/api/models') {
|
|
87
|
-
const models = MODEL_CATALOG.filter(m => !m.legacy && !m.local);
|
|
87
|
+
const models = MODEL_CATALOG.filter(m => !m.legacy && !m.local && !m.unreleased);
|
|
88
88
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
89
89
|
res.end(JSON.stringify({ models }));
|
|
90
90
|
return;
|
package/src/commands/search.js
CHANGED
|
@@ -16,8 +16,8 @@ function registerSearch(program) {
|
|
|
16
16
|
.requiredOption('--query <text>', 'Search query text')
|
|
17
17
|
.requiredOption('--db <database>', 'Database name')
|
|
18
18
|
.requiredOption('--collection <name>', 'Collection name')
|
|
19
|
-
.
|
|
20
|
-
.
|
|
19
|
+
.option('--index <name>', 'Vector search index name', 'vector_index')
|
|
20
|
+
.option('--field <name>', 'Embedding field name', 'embedding')
|
|
21
21
|
.option('-m, --model <model>', 'Embedding model', getDefaultModel())
|
|
22
22
|
.option('--input-type <type>', 'Input type for query embedding', 'query')
|
|
23
23
|
.option('-d, --dimensions <n>', 'Output dimensions', (v) => parseInt(v, 10))
|
package/src/commands/store.js
CHANGED
|
@@ -17,7 +17,7 @@ function registerStore(program) {
|
|
|
17
17
|
.description('Embed text and store in MongoDB Atlas')
|
|
18
18
|
.requiredOption('--db <database>', 'Database name')
|
|
19
19
|
.requiredOption('--collection <name>', 'Collection name')
|
|
20
|
-
.
|
|
20
|
+
.option('--field <name>', 'Embedding field name', 'embedding')
|
|
21
21
|
.option('--text <text>', 'Text to embed and store')
|
|
22
22
|
.option('-f, --file <path>', 'File to embed and store (text file or .jsonl for batch mode)')
|
|
23
23
|
.option('-m, --model <model>', 'Embedding model', getDefaultModel())
|
package/src/lib/api.js
CHANGED
|
@@ -96,25 +96,29 @@ async function apiRequest(endpoint, body) {
|
|
|
96
96
|
} catch {
|
|
97
97
|
errorDetail = await response.text();
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
const errMsg = `API Error (${response.status}): ${errorDetail}`;
|
|
100
100
|
|
|
101
101
|
// Help users diagnose endpoint mismatch
|
|
102
|
+
let hint = '';
|
|
102
103
|
if (response.status === 403 && base === ATLAS_API_BASE) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
console.error(' vai config set base-url https://api.voyageai.com/v1/');
|
|
108
|
-
console.error('');
|
|
109
|
-
console.error('Or set VOYAGE_API_BASE=https://api.voyageai.com/v1/ in your environment.');
|
|
104
|
+
hint = '\n\nHint: 403 on ai.mongodb.com often means your key is for the Voyage AI' +
|
|
105
|
+
'\nplatform, not MongoDB Atlas. Try switching the base URL:' +
|
|
106
|
+
'\n\n vai config set base-url https://api.voyageai.com/v1/' +
|
|
107
|
+
'\n\nOr set VOYAGE_API_BASE=https://api.voyageai.com/v1/ in your environment.';
|
|
110
108
|
} else if (response.status === 401 && base === VOYAGE_API_BASE) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
console.error('');
|
|
115
|
-
console.error(' vai config set base-url https://ai.mongodb.com/v1/');
|
|
109
|
+
hint = '\n\nHint: 401 on api.voyageai.com may mean your key is an Atlas AI key.' +
|
|
110
|
+
'\nTry switching back:' +
|
|
111
|
+
'\n\n vai config set base-url https://ai.mongodb.com/v1/';
|
|
116
112
|
}
|
|
117
|
-
|
|
113
|
+
|
|
114
|
+
// Log the error + hint to stderr for CLI users
|
|
115
|
+
console.error(errMsg);
|
|
116
|
+
if (hint) console.error(hint);
|
|
117
|
+
|
|
118
|
+
// Throw instead of process.exit so callers (like playground) can catch gracefully
|
|
119
|
+
const err = new Error(errMsg);
|
|
120
|
+
err.statusCode = response.status;
|
|
121
|
+
throw err;
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
return response.json();
|
package/src/lib/catalog.js
CHANGED
|
@@ -32,8 +32,8 @@ const MODEL_CATALOG = [
|
|
|
32
32
|
{ name: 'voyage-code-3', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.18/1M tokens', bestFor: 'Code retrieval', shortFor: 'Code' },
|
|
33
33
|
{ name: 'voyage-finance-2', type: 'embedding', context: '32K', dimensions: '1024', price: '$0.12/1M tokens', bestFor: 'Finance', shortFor: 'Finance' },
|
|
34
34
|
{ name: 'voyage-law-2', type: 'embedding', context: '16K', dimensions: '1024', price: '$0.12/1M tokens', bestFor: 'Legal', shortFor: 'Legal' },
|
|
35
|
-
{ name: 'voyage-context-3', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.18/1M tokens', bestFor: 'Contextualized chunks', shortFor: 'Context chunks' },
|
|
36
|
-
{ name: 'voyage-multimodal-3.5', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.12/M + $0.60/B px', bestFor: 'Text + images + video', shortFor: 'Multimodal' },
|
|
35
|
+
{ name: 'voyage-context-3', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.18/1M tokens', bestFor: 'Contextualized chunks', shortFor: 'Context chunks', unreleased: true },
|
|
36
|
+
{ name: 'voyage-multimodal-3.5', type: 'embedding-multimodal', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.12/M + $0.60/B px', bestFor: 'Text + images + video', shortFor: 'Multimodal', multimodal: true },
|
|
37
37
|
{ name: 'rerank-2.5', type: 'reranking', context: '32K', dimensions: '—', price: '$0.05/1M tokens', bestFor: 'Best quality reranking', shortFor: 'Best reranker' },
|
|
38
38
|
{ name: 'rerank-2.5-lite', type: 'reranking', context: '32K', dimensions: '—', price: '$0.02/1M tokens', bestFor: 'Fast reranking', shortFor: 'Fast reranker' },
|
|
39
39
|
{ name: 'voyage-4-nano', type: 'embedding', context: '32K', dimensions: '512 (default), 128, 256', price: 'Open-weight', bestFor: 'Open-weight / edge', shortFor: 'Open / edge', local: true },
|
|
@@ -42,7 +42,7 @@ const MODEL_CATALOG = [
|
|
|
42
42
|
{ name: 'voyage-3.5', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.06/1M tokens', bestFor: 'Previous gen balanced', shortFor: 'Previous gen balanced', legacy: true },
|
|
43
43
|
{ name: 'voyage-3.5-lite', type: 'embedding', context: '32K', dimensions: '1024 (default), 256, 512, 2048', price: '$0.02/1M tokens', bestFor: 'Previous gen budget', shortFor: 'Previous gen budget', legacy: true },
|
|
44
44
|
{ name: 'voyage-code-2', type: 'embedding', context: '16K', dimensions: '1536', price: '$0.12/1M tokens', bestFor: 'Legacy code', shortFor: 'Legacy code', legacy: true },
|
|
45
|
-
{ name: 'voyage-multimodal-3', type: 'embedding', context: '32K', dimensions: '1024', price: '$0.12/1M tokens', bestFor: 'Legacy multimodal', shortFor: 'Legacy multimodal', legacy: true },
|
|
45
|
+
{ name: 'voyage-multimodal-3', type: 'embedding-multimodal', context: '32K', dimensions: '1024', price: '$0.12/1M tokens', bestFor: 'Legacy multimodal', shortFor: 'Legacy multimodal', legacy: true, multimodal: true },
|
|
46
46
|
{ name: 'rerank-2', type: 'reranking', context: '16K', dimensions: '—', price: '$0.05/1M tokens', bestFor: 'Legacy reranker', shortFor: 'Legacy reranker', legacy: true },
|
|
47
47
|
{ name: 'rerank-2-lite', type: 'reranking', context: '8K', dimensions: '—', price: '$0.02/1M tokens', bestFor: 'Legacy fast reranker', shortFor: 'Legacy fast reranker', legacy: true },
|
|
48
48
|
];
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
|
-
workflow_dispatch:
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
test:
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
strategy:
|
|
14
|
-
matrix:
|
|
15
|
-
node-version: [18, 20, 22]
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v4
|
|
18
|
-
- uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: ${{ matrix.node-version }}
|
|
21
|
-
- run: npm ci
|
|
22
|
-
- run: npm test
|
package/CONTRIBUTING.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
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/demo.gif
DELETED
|
Binary file
|
package/demo.tape
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# VHS demo tape for voyageai-cli
|
|
2
|
-
# Run: vhs demo.tape
|
|
3
|
-
# Requires: VOYAGE_API_KEY set in environment
|
|
4
|
-
|
|
5
|
-
Output demo.gif
|
|
6
|
-
|
|
7
|
-
Set FontSize 16
|
|
8
|
-
Set Width 900
|
|
9
|
-
Set Height 600
|
|
10
|
-
Set Theme "Catppuccin Mocha"
|
|
11
|
-
Set Padding 20
|
|
12
|
-
|
|
13
|
-
# Show version
|
|
14
|
-
Type "vai --version"
|
|
15
|
-
Enter
|
|
16
|
-
Sleep 1.5s
|
|
17
|
-
|
|
18
|
-
# List embedding models
|
|
19
|
-
Type "vai models --type embedding"
|
|
20
|
-
Enter
|
|
21
|
-
Sleep 3s
|
|
22
|
-
|
|
23
|
-
# Generate an embedding
|
|
24
|
-
Type 'vai embed "What is MongoDB Atlas?"'
|
|
25
|
-
Enter
|
|
26
|
-
Sleep 4s
|
|
27
|
-
|
|
28
|
-
# Explain embeddings (first few lines)
|
|
29
|
-
Type "vai explain embeddings"
|
|
30
|
-
Enter
|
|
31
|
-
Sleep 4s
|
|
32
|
-
|
|
33
|
-
# Compare similarity
|
|
34
|
-
Type 'vai similarity "MongoDB is great" "MongoDB Atlas is amazing"'
|
|
35
|
-
Enter
|
|
36
|
-
Sleep 4s
|
|
37
|
-
|
|
38
|
-
# Pause at end to show results
|
|
39
|
-
Sleep 2s
|
package/scripts/record-demo.sh
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Record a demo GIF for voyageai-cli
|
|
3
|
-
# Requires: VOYAGE_API_KEY environment variable
|
|
4
|
-
#
|
|
5
|
-
# Usage:
|
|
6
|
-
# ./scripts/record-demo.sh # Uses vhs (preferred)
|
|
7
|
-
# ./scripts/record-demo.sh asciinema # Uses asciinema instead
|
|
8
|
-
#
|
|
9
|
-
# Output:
|
|
10
|
-
# demo.gif (vhs) or demo.cast (asciinema)
|
|
11
|
-
|
|
12
|
-
set -euo pipefail
|
|
13
|
-
cd "$(dirname "$0")/.."
|
|
14
|
-
|
|
15
|
-
METHOD="${1:-vhs}"
|
|
16
|
-
|
|
17
|
-
if [ "$METHOD" = "vhs" ]; then
|
|
18
|
-
if ! command -v vhs &>/dev/null; then
|
|
19
|
-
echo "❌ vhs not found. Install: brew install charmbracelet/tap/vhs"
|
|
20
|
-
echo " Or run: ./scripts/record-demo.sh asciinema"
|
|
21
|
-
exit 1
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
if [ -z "${VOYAGE_API_KEY:-}" ]; then
|
|
25
|
-
echo "⚠️ VOYAGE_API_KEY not set. Commands that call the API will fail."
|
|
26
|
-
echo " Set it: export VOYAGE_API_KEY=your-key"
|
|
27
|
-
exit 1
|
|
28
|
-
fi
|
|
29
|
-
|
|
30
|
-
echo "🎬 Recording demo with vhs..."
|
|
31
|
-
vhs demo.tape
|
|
32
|
-
echo "✅ Demo GIF saved to demo.gif"
|
|
33
|
-
|
|
34
|
-
elif [ "$METHOD" = "asciinema" ]; then
|
|
35
|
-
if ! command -v asciinema &>/dev/null; then
|
|
36
|
-
echo "❌ asciinema not found. Install: brew install asciinema"
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
CAST_FILE="demo.cast"
|
|
41
|
-
echo "🎬 Recording demo with asciinema..."
|
|
42
|
-
echo " Run the following commands, then press Ctrl-D when done:"
|
|
43
|
-
echo ""
|
|
44
|
-
echo " vai --version"
|
|
45
|
-
echo " vai models --type embedding"
|
|
46
|
-
echo ' vai embed "What is MongoDB Atlas?"'
|
|
47
|
-
echo " vai explain embeddings"
|
|
48
|
-
echo ' vai similarity "MongoDB is great" "MongoDB Atlas is amazing"'
|
|
49
|
-
echo ""
|
|
50
|
-
|
|
51
|
-
asciinema rec "$CAST_FILE"
|
|
52
|
-
echo "✅ Recording saved to $CAST_FILE"
|
|
53
|
-
echo ""
|
|
54
|
-
echo "Convert to GIF with agg or svg-term-cli:"
|
|
55
|
-
echo " agg $CAST_FILE demo.gif"
|
|
56
|
-
echo " # or"
|
|
57
|
-
echo " npx svg-term-cli --in $CAST_FILE --out demo.svg --window"
|
|
58
|
-
|
|
59
|
-
else
|
|
60
|
-
echo "Unknown method: $METHOD"
|
|
61
|
-
echo "Usage: $0 [vhs|asciinema]"
|
|
62
|
-
exit 1
|
|
63
|
-
fi
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const { Command } = require('commander');
|
|
6
|
-
const { registerAbout } = require('../../src/commands/about');
|
|
7
|
-
|
|
8
|
-
describe('about command', () => {
|
|
9
|
-
it('registers correctly on a program', () => {
|
|
10
|
-
const program = new Command();
|
|
11
|
-
registerAbout(program);
|
|
12
|
-
const aboutCmd = program.commands.find(c => c.name() === 'about');
|
|
13
|
-
assert.ok(aboutCmd, 'about command should be registered');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('has --json option', () => {
|
|
17
|
-
const program = new Command();
|
|
18
|
-
registerAbout(program);
|
|
19
|
-
const aboutCmd = program.commands.find(c => c.name() === 'about');
|
|
20
|
-
const optionNames = aboutCmd.options.map(o => o.long);
|
|
21
|
-
assert.ok(optionNames.includes('--json'), 'should have --json option');
|
|
22
|
-
});
|
|
23
|
-
});
|