voyageai-cli 1.12.1 → 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 +1 -1
- 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 -133
- 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
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const { Command } = require('commander');
|
|
6
|
-
const { registerCompletions, generateBashCompletions, generateZshCompletions } = require('../../src/commands/completions');
|
|
7
|
-
|
|
8
|
-
describe('completions command', () => {
|
|
9
|
-
let originalLog;
|
|
10
|
-
let originalWrite;
|
|
11
|
-
let originalError;
|
|
12
|
-
let originalExit;
|
|
13
|
-
let output;
|
|
14
|
-
let stdoutOutput;
|
|
15
|
-
let stderrOutput;
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
originalLog = console.log;
|
|
19
|
-
originalWrite = process.stdout.write;
|
|
20
|
-
originalError = console.error;
|
|
21
|
-
originalExit = process.exit;
|
|
22
|
-
output = [];
|
|
23
|
-
stdoutOutput = [];
|
|
24
|
-
stderrOutput = [];
|
|
25
|
-
console.log = (...args) => output.push(args.join(' '));
|
|
26
|
-
process.stdout.write = (data) => { stdoutOutput.push(data); return true; };
|
|
27
|
-
console.error = (...args) => stderrOutput.push(args.join(' '));
|
|
28
|
-
process.exit = (code) => { throw new Error(`EXIT_${code}`); };
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
afterEach(() => {
|
|
32
|
-
console.log = originalLog;
|
|
33
|
-
process.stdout.write = originalWrite;
|
|
34
|
-
console.error = originalError;
|
|
35
|
-
process.exit = originalExit;
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('registers correctly on a program', () => {
|
|
39
|
-
const program = new Command();
|
|
40
|
-
registerCompletions(program);
|
|
41
|
-
const cmd = program.commands.find(c => c.name() === 'completions');
|
|
42
|
-
assert.ok(cmd, 'completions command should be registered');
|
|
43
|
-
assert.ok(cmd.description().includes('completion'), 'should have a description about completions');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('shows usage when called without shell argument', async () => {
|
|
47
|
-
const program = new Command();
|
|
48
|
-
program.exitOverride();
|
|
49
|
-
registerCompletions(program);
|
|
50
|
-
|
|
51
|
-
await program.parseAsync(['node', 'test', 'completions']);
|
|
52
|
-
|
|
53
|
-
const combined = output.join('\n');
|
|
54
|
-
assert.ok(combined.includes('bash'), 'should mention bash');
|
|
55
|
-
assert.ok(combined.includes('zsh'), 'should mention zsh');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('outputs bash completion script', async () => {
|
|
59
|
-
const program = new Command();
|
|
60
|
-
program.exitOverride();
|
|
61
|
-
registerCompletions(program);
|
|
62
|
-
|
|
63
|
-
await program.parseAsync(['node', 'test', 'completions', 'bash']);
|
|
64
|
-
|
|
65
|
-
const combined = stdoutOutput.join('');
|
|
66
|
-
assert.ok(combined.includes('_vai_completions'), 'should contain bash completion function');
|
|
67
|
-
assert.ok(combined.includes('complete -F _vai_completions vai'), 'should register completion');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('outputs zsh completion script', async () => {
|
|
71
|
-
const program = new Command();
|
|
72
|
-
program.exitOverride();
|
|
73
|
-
registerCompletions(program);
|
|
74
|
-
|
|
75
|
-
await program.parseAsync(['node', 'test', 'completions', 'zsh']);
|
|
76
|
-
|
|
77
|
-
const combined = stdoutOutput.join('');
|
|
78
|
-
assert.ok(combined.includes('#compdef vai'), 'should contain zsh compdef header');
|
|
79
|
-
assert.ok(combined.includes('_vai'), 'should contain zsh completion function');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('rejects unknown shell', async () => {
|
|
83
|
-
const program = new Command();
|
|
84
|
-
program.exitOverride();
|
|
85
|
-
registerCompletions(program);
|
|
86
|
-
|
|
87
|
-
await assert.rejects(
|
|
88
|
-
() => program.parseAsync(['node', 'test', 'completions', 'fish']),
|
|
89
|
-
/EXIT_1/,
|
|
90
|
-
'should exit with code 1 for unsupported shell'
|
|
91
|
-
);
|
|
92
|
-
const combined = stderrOutput.join('\n');
|
|
93
|
-
assert.ok(combined.includes('fish'), 'should mention the unknown shell name');
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('generateBashCompletions', () => {
|
|
98
|
-
it('includes all 14 commands (including completions)', () => {
|
|
99
|
-
const script = generateBashCompletions();
|
|
100
|
-
const commands = ['embed', 'rerank', 'store', 'search', 'index', 'models', 'ping', 'config', 'demo', 'explain', 'similarity', 'ingest', 'completions', 'help'];
|
|
101
|
-
for (const cmd of commands) {
|
|
102
|
-
assert.ok(script.includes(cmd), `should include command: ${cmd}`);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('includes model completions', () => {
|
|
107
|
-
const script = generateBashCompletions();
|
|
108
|
-
assert.ok(script.includes('voyage-4-large'), 'should include voyage-4-large model');
|
|
109
|
-
assert.ok(script.includes('rerank-2.5'), 'should include rerank-2.5 model');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('includes flag completions for embed', () => {
|
|
113
|
-
const script = generateBashCompletions();
|
|
114
|
-
assert.ok(script.includes('--model'), 'should include --model flag');
|
|
115
|
-
assert.ok(script.includes('--dimensions'), 'should include --dimensions flag');
|
|
116
|
-
assert.ok(script.includes('--input-type'), 'should include --input-type flag');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('includes index subcommands', () => {
|
|
120
|
-
const script = generateBashCompletions();
|
|
121
|
-
assert.ok(script.includes('create list delete'), 'should include index subcommands');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('includes config subcommands', () => {
|
|
125
|
-
const script = generateBashCompletions();
|
|
126
|
-
assert.ok(script.includes('set get delete path reset'), 'should include config subcommands');
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('includes input-type values', () => {
|
|
130
|
-
const script = generateBashCompletions();
|
|
131
|
-
assert.ok(script.includes('query document'), 'should include input-type values');
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('generateZshCompletions', () => {
|
|
136
|
-
it('includes compdef header', () => {
|
|
137
|
-
const script = generateZshCompletions();
|
|
138
|
-
assert.ok(script.startsWith('#compdef vai'), 'should start with #compdef vai');
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('includes all commands with descriptions', () => {
|
|
142
|
-
const script = generateZshCompletions();
|
|
143
|
-
const commands = ['embed', 'rerank', 'store', 'search', 'index', 'models', 'ping', 'config', 'demo', 'explain', 'similarity', 'ingest', 'completions'];
|
|
144
|
-
for (const cmd of commands) {
|
|
145
|
-
assert.ok(script.includes(`'${cmd}:`), `should include command with description: ${cmd}`);
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('includes model names', () => {
|
|
150
|
-
const script = generateZshCompletions();
|
|
151
|
-
assert.ok(script.includes('voyage-4-large'), 'should include voyage-4-large model');
|
|
152
|
-
assert.ok(script.includes('voyage-code-3'), 'should include voyage-code-3 model');
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('includes explain topics', () => {
|
|
156
|
-
const script = generateZshCompletions();
|
|
157
|
-
assert.ok(script.includes('embeddings'), 'should include embeddings topic');
|
|
158
|
-
assert.ok(script.includes('cosine-similarity'), 'should include cosine-similarity topic');
|
|
159
|
-
assert.ok(script.includes('batch-processing'), 'should include batch-processing topic');
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('includes file completion for --file flags', () => {
|
|
163
|
-
const script = generateZshCompletions();
|
|
164
|
-
assert.ok(script.includes('_files'), 'should use _files completion');
|
|
165
|
-
});
|
|
166
|
-
});
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const { Command } = require('commander');
|
|
6
|
-
const { registerConfig } = require('../../src/commands/config');
|
|
7
|
-
|
|
8
|
-
describe('config command', () => {
|
|
9
|
-
it('registers config command with subcommands', () => {
|
|
10
|
-
const program = new Command();
|
|
11
|
-
program.exitOverride();
|
|
12
|
-
registerConfig(program);
|
|
13
|
-
|
|
14
|
-
const configCmd = program.commands.find(c => c.name() === 'config');
|
|
15
|
-
assert.ok(configCmd, 'config command should be registered');
|
|
16
|
-
|
|
17
|
-
const subNames = configCmd.commands.map(c => c.name());
|
|
18
|
-
assert.ok(subNames.includes('set'), 'should have set subcommand');
|
|
19
|
-
assert.ok(subNames.includes('get'), 'should have get subcommand');
|
|
20
|
-
assert.ok(subNames.includes('delete'), 'should have delete subcommand');
|
|
21
|
-
assert.ok(subNames.includes('path'), 'should have path subcommand');
|
|
22
|
-
assert.ok(subNames.includes('reset'), 'should have reset subcommand');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('config set/get/delete round-trip via lib functions', () => {
|
|
26
|
-
// This test exercises the underlying lib (already tested in config.test.js)
|
|
27
|
-
// but validates the key mapping used by the command
|
|
28
|
-
const { KEY_MAP } = require('../../src/lib/config');
|
|
29
|
-
|
|
30
|
-
assert.equal(KEY_MAP['api-key'], 'apiKey');
|
|
31
|
-
assert.equal(KEY_MAP['mongodb-uri'], 'mongodbUri');
|
|
32
|
-
assert.equal(KEY_MAP['default-model'], 'defaultModel');
|
|
33
|
-
assert.equal(KEY_MAP['default-dimensions'], 'defaultDimensions');
|
|
34
|
-
});
|
|
35
|
-
});
|
|
@@ -1,46 +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 { registerDemo } = require('../../src/commands/demo');
|
|
7
|
-
|
|
8
|
-
describe('demo command', () => {
|
|
9
|
-
it('registers correctly on a program', () => {
|
|
10
|
-
const program = new Command();
|
|
11
|
-
registerDemo(program);
|
|
12
|
-
const demoCmd = program.commands.find(c => c.name() === 'demo');
|
|
13
|
-
assert.ok(demoCmd, 'demo command should be registered');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('has --no-pause option', () => {
|
|
17
|
-
const program = new Command();
|
|
18
|
-
registerDemo(program);
|
|
19
|
-
const demoCmd = program.commands.find(c => c.name() === 'demo');
|
|
20
|
-
const opts = demoCmd.options.map(o => o.long);
|
|
21
|
-
assert.ok(opts.includes('--no-pause'), 'Should have --no-pause option');
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('has --skip-pipeline option', () => {
|
|
25
|
-
const program = new Command();
|
|
26
|
-
registerDemo(program);
|
|
27
|
-
const demoCmd = program.commands.find(c => c.name() === 'demo');
|
|
28
|
-
const opts = demoCmd.options.map(o => o.long);
|
|
29
|
-
assert.ok(opts.includes('--skip-pipeline'), 'Should have --skip-pipeline option');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('has --keep option', () => {
|
|
33
|
-
const program = new Command();
|
|
34
|
-
registerDemo(program);
|
|
35
|
-
const demoCmd = program.commands.find(c => c.name() === 'demo');
|
|
36
|
-
const opts = demoCmd.options.map(o => o.long);
|
|
37
|
-
assert.ok(opts.includes('--keep'), 'Should have --keep option');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('has correct description', () => {
|
|
41
|
-
const program = new Command();
|
|
42
|
-
registerDemo(program);
|
|
43
|
-
const demoCmd = program.commands.find(c => c.name() === 'demo');
|
|
44
|
-
assert.ok(demoCmd.description().includes('walkthrough'), 'Should mention walkthrough');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it, beforeEach, afterEach, mock } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const { Command } = require('commander');
|
|
6
|
-
const { registerEmbed } = require('../../src/commands/embed');
|
|
7
|
-
|
|
8
|
-
describe('embed command', () => {
|
|
9
|
-
it('registers correctly on a program', () => {
|
|
10
|
-
const program = new Command();
|
|
11
|
-
registerEmbed(program);
|
|
12
|
-
const embedCmd = program.commands.find(c => c.name() === 'embed');
|
|
13
|
-
assert.ok(embedCmd, 'embed command should be registered');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('has --truncation flag', () => {
|
|
17
|
-
const program = new Command();
|
|
18
|
-
registerEmbed(program);
|
|
19
|
-
const embedCmd = program.commands.find(c => c.name() === 'embed');
|
|
20
|
-
const optionNames = embedCmd.options.map(o => o.long);
|
|
21
|
-
assert.ok(optionNames.includes('--truncation'), 'should have --truncation option');
|
|
22
|
-
assert.ok(optionNames.includes('--no-truncation'), 'should have --no-truncation option');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('has --input-type flag', () => {
|
|
26
|
-
const program = new Command();
|
|
27
|
-
registerEmbed(program);
|
|
28
|
-
const embedCmd = program.commands.find(c => c.name() === 'embed');
|
|
29
|
-
const optionNames = embedCmd.options.map(o => o.long);
|
|
30
|
-
assert.ok(optionNames.includes('--input-type'), 'should have --input-type option');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('has --output-dtype flag with float default', () => {
|
|
34
|
-
const program = new Command();
|
|
35
|
-
registerEmbed(program);
|
|
36
|
-
const embedCmd = program.commands.find(c => c.name() === 'embed');
|
|
37
|
-
const optionNames = embedCmd.options.map(o => o.long);
|
|
38
|
-
assert.ok(optionNames.includes('--output-dtype'), 'should have --output-dtype option');
|
|
39
|
-
const opt = embedCmd.options.find(o => o.long === '--output-dtype');
|
|
40
|
-
assert.equal(opt.defaultValue, 'float');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { describe, it, beforeEach, afterEach } = require('node:test');
|
|
4
|
-
const assert = require('node:assert/strict');
|
|
5
|
-
const { Command } = require('commander');
|
|
6
|
-
const { registerExplain } = require('../../src/commands/explain');
|
|
7
|
-
|
|
8
|
-
describe('explain command', () => {
|
|
9
|
-
let originalLog;
|
|
10
|
-
let originalError;
|
|
11
|
-
let originalExit;
|
|
12
|
-
let output;
|
|
13
|
-
let errorOutput;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
originalLog = console.log;
|
|
17
|
-
originalError = console.error;
|
|
18
|
-
originalExit = process.exit;
|
|
19
|
-
output = [];
|
|
20
|
-
errorOutput = [];
|
|
21
|
-
console.log = (...args) => output.push(args.join(' '));
|
|
22
|
-
console.error = (...args) => errorOutput.push(args.join(' '));
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
console.log = originalLog;
|
|
27
|
-
console.error = originalError;
|
|
28
|
-
process.exit = originalExit;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('registers correctly on a program', () => {
|
|
32
|
-
const program = new Command();
|
|
33
|
-
registerExplain(program);
|
|
34
|
-
const cmd = program.commands.find(c => c.name() === 'explain');
|
|
35
|
-
assert.ok(cmd, 'explain command should be registered');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('lists topics when no argument given', async () => {
|
|
39
|
-
const program = new Command();
|
|
40
|
-
program.exitOverride();
|
|
41
|
-
registerExplain(program);
|
|
42
|
-
|
|
43
|
-
await program.parseAsync(['node', 'test', 'explain']);
|
|
44
|
-
|
|
45
|
-
const combined = output.join('\n');
|
|
46
|
-
assert.ok(combined.includes('Available topics'), 'Should show available topics header');
|
|
47
|
-
assert.ok(combined.includes('embeddings'), 'Should list embeddings');
|
|
48
|
-
assert.ok(combined.includes('reranking'), 'Should list reranking');
|
|
49
|
-
assert.ok(combined.includes('rag'), 'Should list rag');
|
|
50
|
-
assert.ok(combined.includes('vector-search'), 'Should list vector-search');
|
|
51
|
-
assert.ok(combined.includes('vai explain <topic>'), 'Should show usage hint');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('shows content for a known concept', async () => {
|
|
55
|
-
const program = new Command();
|
|
56
|
-
program.exitOverride();
|
|
57
|
-
registerExplain(program);
|
|
58
|
-
|
|
59
|
-
await program.parseAsync(['node', 'test', 'explain', 'embeddings']);
|
|
60
|
-
|
|
61
|
-
const combined = output.join('\n');
|
|
62
|
-
assert.ok(combined.includes('Embeddings'), 'Should show title');
|
|
63
|
-
assert.ok(combined.includes('vector'), 'Should contain explanation about vectors');
|
|
64
|
-
assert.ok(combined.includes('Try it'), 'Should show Try it section');
|
|
65
|
-
assert.ok(combined.includes('Learn more'), 'Should show Learn more section');
|
|
66
|
-
assert.ok(combined.includes('not affiliated'), 'Should show disclaimer');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('resolves alias "embed" to embeddings', async () => {
|
|
70
|
-
const program = new Command();
|
|
71
|
-
program.exitOverride();
|
|
72
|
-
registerExplain(program);
|
|
73
|
-
|
|
74
|
-
await program.parseAsync(['node', 'test', 'explain', 'embed']);
|
|
75
|
-
|
|
76
|
-
const combined = output.join('\n');
|
|
77
|
-
assert.ok(combined.includes('Embeddings'), 'Should resolve alias and show Embeddings');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('resolves alias "rerank" to reranking', async () => {
|
|
81
|
-
const program = new Command();
|
|
82
|
-
program.exitOverride();
|
|
83
|
-
registerExplain(program);
|
|
84
|
-
|
|
85
|
-
await program.parseAsync(['node', 'test', 'explain', 'rerank']);
|
|
86
|
-
|
|
87
|
-
const combined = output.join('\n');
|
|
88
|
-
assert.ok(combined.includes('Reranking'), 'Should resolve alias and show Reranking');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('resolves alias "vectors" to vector-search', async () => {
|
|
92
|
-
const program = new Command();
|
|
93
|
-
program.exitOverride();
|
|
94
|
-
registerExplain(program);
|
|
95
|
-
|
|
96
|
-
await program.parseAsync(['node', 'test', 'explain', 'vectors']);
|
|
97
|
-
|
|
98
|
-
const combined = output.join('\n');
|
|
99
|
-
assert.ok(combined.includes('Vector Search'), 'Should resolve alias and show Vector Search');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('resolves alias "similarity" to cosine-similarity', async () => {
|
|
103
|
-
const program = new Command();
|
|
104
|
-
program.exitOverride();
|
|
105
|
-
registerExplain(program);
|
|
106
|
-
|
|
107
|
-
await program.parseAsync(['node', 'test', 'explain', 'similarity']);
|
|
108
|
-
|
|
109
|
-
const combined = output.join('\n');
|
|
110
|
-
assert.ok(combined.includes('Cosine Similarity'), 'Should resolve alias');
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('resolves alias "two-stage" to two-stage-retrieval', async () => {
|
|
114
|
-
const program = new Command();
|
|
115
|
-
program.exitOverride();
|
|
116
|
-
registerExplain(program);
|
|
117
|
-
|
|
118
|
-
await program.parseAsync(['node', 'test', 'explain', 'two-stage']);
|
|
119
|
-
|
|
120
|
-
const combined = output.join('\n');
|
|
121
|
-
assert.ok(combined.includes('Two-Stage Retrieval'), 'Should resolve alias');
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('resolves alias "keys" to api-keys', async () => {
|
|
125
|
-
const program = new Command();
|
|
126
|
-
program.exitOverride();
|
|
127
|
-
registerExplain(program);
|
|
128
|
-
|
|
129
|
-
await program.parseAsync(['node', 'test', 'explain', 'keys']);
|
|
130
|
-
|
|
131
|
-
const combined = output.join('\n');
|
|
132
|
-
assert.ok(combined.includes('API Keys'), 'Should resolve alias');
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('resolves alias "batch" to batch-processing', async () => {
|
|
136
|
-
const program = new Command();
|
|
137
|
-
program.exitOverride();
|
|
138
|
-
registerExplain(program);
|
|
139
|
-
|
|
140
|
-
await program.parseAsync(['node', 'test', 'explain', 'batch']);
|
|
141
|
-
|
|
142
|
-
const combined = output.join('\n');
|
|
143
|
-
assert.ok(combined.includes('Batch Processing'), 'Should resolve alias');
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('shows error and suggestions for unknown concept', async () => {
|
|
147
|
-
let exitCode = null;
|
|
148
|
-
process.exit = (code) => {
|
|
149
|
-
exitCode = code;
|
|
150
|
-
throw new Error('process.exit called');
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const program = new Command();
|
|
154
|
-
program.exitOverride();
|
|
155
|
-
registerExplain(program);
|
|
156
|
-
|
|
157
|
-
await assert.rejects(
|
|
158
|
-
() => program.parseAsync(['node', 'test', 'explain', 'nonexistent']),
|
|
159
|
-
/process\.exit called/
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
assert.equal(exitCode, 1);
|
|
163
|
-
const combined = errorOutput.join('\n');
|
|
164
|
-
assert.ok(combined.includes('Unknown topic'), 'Should show unknown topic error');
|
|
165
|
-
assert.ok(combined.includes('vai explain'), 'Should suggest running vai explain');
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('outputs JSON for topic list with --json flag', async () => {
|
|
169
|
-
const program = new Command();
|
|
170
|
-
program.exitOverride();
|
|
171
|
-
registerExplain(program);
|
|
172
|
-
|
|
173
|
-
await program.parseAsync(['node', 'test', 'explain', '--json']);
|
|
174
|
-
|
|
175
|
-
const combined = output.join('\n');
|
|
176
|
-
const parsed = JSON.parse(combined);
|
|
177
|
-
assert.ok(Array.isArray(parsed.topics), 'Should have topics array');
|
|
178
|
-
assert.ok(parsed.topics.length >= 10, 'Should have at least 10 topics');
|
|
179
|
-
assert.ok(parsed.topics[0].key, 'Each topic should have a key');
|
|
180
|
-
assert.ok(parsed.topics[0].title, 'Each topic should have a title');
|
|
181
|
-
assert.ok(parsed.topics[0].summary, 'Each topic should have a summary');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('outputs JSON for a specific concept with --json flag', async () => {
|
|
185
|
-
const program = new Command();
|
|
186
|
-
program.exitOverride();
|
|
187
|
-
registerExplain(program);
|
|
188
|
-
|
|
189
|
-
await program.parseAsync(['node', 'test', 'explain', 'rag', '--json']);
|
|
190
|
-
|
|
191
|
-
const combined = output.join('\n');
|
|
192
|
-
const parsed = JSON.parse(combined);
|
|
193
|
-
assert.equal(parsed.concept, 'rag');
|
|
194
|
-
assert.equal(parsed.title, 'RAG (Retrieval-Augmented Generation)');
|
|
195
|
-
assert.ok(parsed.content, 'Should have content');
|
|
196
|
-
assert.ok(Array.isArray(parsed.links), 'Should have links');
|
|
197
|
-
assert.ok(Array.isArray(parsed.tryIt), 'Should have tryIt');
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('has --json option', () => {
|
|
201
|
-
const program = new Command();
|
|
202
|
-
registerExplain(program);
|
|
203
|
-
const cmd = program.commands.find(c => c.name() === 'explain');
|
|
204
|
-
const opts = cmd.options.map(o => o.long);
|
|
205
|
-
assert.ok(opts.includes('--json'), 'Should have --json option');
|
|
206
|
-
});
|
|
207
|
-
});
|