voyageai-cli 1.30.1 → 1.30.2

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.
Files changed (37) hide show
  1. package/README.md +4 -4
  2. package/package.json +1 -1
  3. package/src/cli.js +2 -0
  4. package/src/commands/about.js +3 -3
  5. package/src/commands/code-search.js +751 -0
  6. package/src/commands/doctor.js +1 -1
  7. package/src/commands/index-workspace.js +9 -5
  8. package/src/commands/playground.js +9 -1
  9. package/src/commands/quickstart.js +4 -4
  10. package/src/commands/workflow.js +132 -65
  11. package/src/lib/catalog.js +4 -2
  12. package/src/lib/code-search.js +315 -0
  13. package/src/lib/codegen.js +1 -1
  14. package/src/lib/explanations.js +3 -3
  15. package/src/lib/github.js +226 -0
  16. package/src/lib/template-engine.js +154 -20
  17. package/src/lib/workflow-builder.js +753 -0
  18. package/src/lib/workflow-formatters.js +454 -0
  19. package/src/lib/workflow-input-cache.js +111 -0
  20. package/src/lib/workflow-scaffold.js +1 -1
  21. package/src/lib/workflow.js +91 -1
  22. package/src/mcp/schemas/index.js +130 -0
  23. package/src/mcp/server.js +17 -4
  24. package/src/mcp/tools/authoring.js +662 -0
  25. package/src/mcp/tools/code-search.js +620 -0
  26. package/src/mcp/tools/ingest.js +2 -5
  27. package/src/mcp/tools/retrieval.js +2 -15
  28. package/src/mcp/tools/workspace.js +1 -12
  29. package/src/mcp/utils.js +20 -0
  30. package/src/playground/help/workflow-nodes.js +127 -2
  31. package/src/playground/index.html +1366 -24
  32. package/src/workflows/code-review.json +110 -0
  33. package/src/workflows/cost-analysis.json +5 -0
  34. package/src/workflows/tests/code-review.fresh-index.test.json +83 -0
  35. package/src/workflows/tests/code-review.happy-path.test.json +121 -0
  36. package/src/workflows/tests/code-review.no-question.test.json +70 -0
  37. package/src/workflows/tests/smart-ingest.duplicate-detected.test.json +2 -2
@@ -0,0 +1,110 @@
1
+ {
2
+ "$schema": "https://vai.dev/schemas/workflow-v1.json",
3
+ "name": "Code Review Assistant",
4
+ "description": "Index a codebase, find similar patterns, and surface related code for review. Paste a code snippet and get context from across the project — similar implementations, related functions, and architectural patterns.",
5
+ "version": "1.0.0",
6
+ "branding": {
7
+ "icon": "code",
8
+ "color": "#06B6D4"
9
+ },
10
+ "inputs": {
11
+ "source": {
12
+ "type": "string",
13
+ "description": "Local directory path or GitHub repo URL to analyze",
14
+ "required": true
15
+ },
16
+ "code": {
17
+ "type": "string",
18
+ "description": "Code snippet to review — finds similar patterns and related implementations",
19
+ "required": true
20
+ },
21
+ "question": {
22
+ "type": "string",
23
+ "description": "Optional question about the code (e.g., 'are there any other retry implementations?')",
24
+ "default": ""
25
+ },
26
+ "language": {
27
+ "type": "string",
28
+ "description": "Filter results to a specific language (e.g., 'js', 'py', 'go')"
29
+ },
30
+ "limit": {
31
+ "type": "number",
32
+ "description": "Maximum results per search step",
33
+ "default": 5
34
+ }
35
+ },
36
+ "defaults": {
37
+ "db": "vai_code_search"
38
+ },
39
+ "steps": [
40
+ {
41
+ "id": "check_index",
42
+ "name": "Check if codebase is already indexed",
43
+ "tool": "code_status",
44
+ "inputs": {
45
+ "db": "{{ defaults.db }}"
46
+ }
47
+ },
48
+ {
49
+ "id": "index_codebase",
50
+ "name": "Index codebase (skip if already indexed and fresh)",
51
+ "tool": "code_index",
52
+ "inputs": {
53
+ "source": "{{ inputs.source }}",
54
+ "db": "{{ defaults.db }}",
55
+ "refresh": true
56
+ },
57
+ "condition": "{{ !check_index.output || check_index.output.totalChunks === 0 }}"
58
+ },
59
+ {
60
+ "id": "find_similar",
61
+ "name": "Find similar code patterns across the codebase",
62
+ "tool": "code_find_similar",
63
+ "inputs": {
64
+ "code": "{{ inputs.code }}",
65
+ "db": "{{ defaults.db }}",
66
+ "collection": "{{ index_codebase.output.collection || check_index.output.collection }}",
67
+ "limit": "{{ inputs.limit }}",
68
+ "language": "{{ inputs.language }}",
69
+ "threshold": 0.4
70
+ }
71
+ },
72
+ {
73
+ "id": "contextual_search",
74
+ "name": "Search for related architectural context",
75
+ "tool": "code_search",
76
+ "inputs": {
77
+ "query": "{{ inputs.question || 'functions and modules related to: ' + inputs.code }}",
78
+ "db": "{{ defaults.db }}",
79
+ "collection": "{{ index_codebase.output.collection || check_index.output.collection }}",
80
+ "limit": "{{ inputs.limit }}",
81
+ "language": "{{ inputs.language }}",
82
+ "rerank": true
83
+ }
84
+ },
85
+ {
86
+ "id": "deep_query",
87
+ "name": "Answer specific question about the code",
88
+ "tool": "code_query",
89
+ "inputs": {
90
+ "query": "{{ inputs.question }}",
91
+ "db": "{{ defaults.db }}",
92
+ "collection": "{{ index_codebase.output.collection || check_index.output.collection }}",
93
+ "limit": 3,
94
+ "language": "{{ inputs.language }}"
95
+ },
96
+ "condition": "{{ inputs.question && inputs.question.length > 0 }}"
97
+ }
98
+ ],
99
+ "output": {
100
+ "similarPatterns": "{{ find_similar.output.results }}",
101
+ "similarCount": "{{ find_similar.output.metadata.resultCount }}",
102
+ "relatedCode": "{{ contextual_search.output.results }}",
103
+ "relatedCount": "{{ contextual_search.output.metadata.resultCount }}",
104
+ "answer": "{{ deep_query.output.results }}",
105
+ "indexStatus": {
106
+ "totalFiles": "{{ check_index.output.uniqueFiles || index_codebase.output.filesIndexed }}",
107
+ "totalChunks": "{{ check_index.output.totalChunks || index_codebase.output.chunksCreated }}"
108
+ }
109
+ }
110
+ }
@@ -69,5 +69,10 @@
69
69
  "docs": "{{ inputs.docs }}",
70
70
  "queriesPerMonth": "{{ inputs.queries }}",
71
71
  "months": "{{ inputs.months }}"
72
+ },
73
+ "formatters": {
74
+ "default": "table",
75
+ "title": "Cost Analysis",
76
+ "arrayField": "comparison"
72
77
  }
73
78
  }
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "code-review: fresh index required (no existing index)",
3
+ "inputs": {
4
+ "source": "https://github.com/mrlynn/voyageai-cli",
5
+ "code": "function generateEmbeddings(texts, model) { ... }",
6
+ "limit": 5
7
+ },
8
+ "mocks": {
9
+ "code_status": {
10
+ "totalChunks": 0,
11
+ "uniqueFiles": 0,
12
+ "languages": {},
13
+ "lastIndexed": null,
14
+ "indexes": []
15
+ },
16
+ "code_index": {
17
+ "source": "https://github.com/mrlynn/voyageai-cli",
18
+ "sourceType": "github",
19
+ "db": "vai_code_search",
20
+ "collection": "voyageai_cli_code",
21
+ "model": "voyage-code-3",
22
+ "filesFound": 89,
23
+ "filesIndexed": 89,
24
+ "chunksCreated": 642,
25
+ "totalTokens": 185000,
26
+ "errors": [],
27
+ "timeMs": 8400,
28
+ "refresh": true,
29
+ "indexName": "code_search_index"
30
+ },
31
+ "code_find_similar": {
32
+ "results": [
33
+ {
34
+ "source": "src/lib/api.js",
35
+ "language": "js",
36
+ "startLine": 45,
37
+ "endLine": 78,
38
+ "symbols": ["generateEmbeddings", "batchEmbed"],
39
+ "content": "async function generateEmbeddings(texts, model, opts) { ... }",
40
+ "score": 0.962,
41
+ "chunkType": "boundary"
42
+ }
43
+ ],
44
+ "metadata": {
45
+ "collection": "voyageai_cli_code",
46
+ "model": "voyage-code-3",
47
+ "resultCount": 1,
48
+ "timeMs": 145
49
+ }
50
+ },
51
+ "code_search": {
52
+ "results": [
53
+ {
54
+ "source": "src/lib/api.js",
55
+ "language": "js",
56
+ "startLine": 1,
57
+ "endLine": 30,
58
+ "symbols": ["apiRequest", "BASE_URL"],
59
+ "content": "const BASE_URL = process.env.VOYAGE_API_URL || 'https://ai.mongodb.com/v1/'; ...",
60
+ "score": 0.834
61
+ }
62
+ ],
63
+ "metadata": {
64
+ "collection": "voyageai_cli_code",
65
+ "model": "voyage-code-3",
66
+ "reranked": true,
67
+ "resultCount": 1,
68
+ "timeMs": 210
69
+ }
70
+ },
71
+ "code_query": null
72
+ },
73
+ "expect": {
74
+ "steps": {
75
+ "check_index": { "status": "completed" },
76
+ "index_codebase": { "status": "completed" },
77
+ "find_similar": { "status": "completed" },
78
+ "contextual_search": { "status": "completed" },
79
+ "deep_query": { "status": "skipped" }
80
+ },
81
+ "noErrors": true
82
+ }
83
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "code-review: find similar patterns with contextual search",
3
+ "inputs": {
4
+ "source": "/Users/dev/myapp",
5
+ "code": "async function retryWithBackoff(fn, maxRetries = 3) {\n for (let i = 0; i < maxRetries; i++) {\n try { return await fn(); }\n catch (e) { if (i === maxRetries - 1) throw e; await sleep(Math.pow(2, i) * 1000); }\n }\n}",
6
+ "question": "are there other retry or backoff implementations?",
7
+ "language": "js",
8
+ "limit": 5
9
+ },
10
+ "mocks": {
11
+ "code_status": {
12
+ "totalChunks": 1823,
13
+ "uniqueFiles": 247,
14
+ "collection": "myapp_code",
15
+ "languages": { "js": 180, "ts": 45, "json": 22 },
16
+ "lastIndexed": "2026-02-16T12:00:00.000Z",
17
+ "indexes": [{ "name": "code_search_index", "status": "READY" }]
18
+ },
19
+ "code_index": null,
20
+ "code_find_similar": {
21
+ "results": [
22
+ {
23
+ "source": "src/lib/http-client.js",
24
+ "language": "js",
25
+ "startLine": 88,
26
+ "endLine": 112,
27
+ "symbols": ["retryRequest", "exponentialDelay"],
28
+ "content": "async function retryRequest(url, opts, retries = 5) {\n const exponentialDelay = (attempt) => Math.pow(2, attempt) * 500;\n for (let attempt = 0; attempt < retries; attempt++) { ... }",
29
+ "score": 0.921,
30
+ "chunkType": "boundary"
31
+ },
32
+ {
33
+ "source": "src/lib/queue.js",
34
+ "language": "js",
35
+ "startLine": 34,
36
+ "endLine": 58,
37
+ "symbols": ["processWithRetry"],
38
+ "content": "async function processWithRetry(task, { maxAttempts = 3, backoff = 'exponential' }) { ... }",
39
+ "score": 0.867,
40
+ "chunkType": "boundary"
41
+ },
42
+ {
43
+ "source": "src/utils/resilience.js",
44
+ "language": "js",
45
+ "startLine": 1,
46
+ "endLine": 30,
47
+ "symbols": ["circuitBreaker", "withTimeout"],
48
+ "content": "function circuitBreaker(fn, { threshold = 5, resetMs = 30000 }) { ... }",
49
+ "score": 0.743,
50
+ "chunkType": "boundary"
51
+ }
52
+ ],
53
+ "metadata": {
54
+ "collection": "myapp_code",
55
+ "model": "voyage-code-3",
56
+ "resultCount": 3,
57
+ "timeMs": 187
58
+ }
59
+ },
60
+ "code_search": {
61
+ "results": [
62
+ {
63
+ "source": "src/lib/http-client.js",
64
+ "language": "js",
65
+ "startLine": 1,
66
+ "endLine": 25,
67
+ "symbols": ["createClient", "DEFAULT_TIMEOUT"],
68
+ "content": "const DEFAULT_TIMEOUT = 30000;\nfunction createClient(baseUrl, opts) { ... }",
69
+ "score": 0.856
70
+ },
71
+ {
72
+ "source": "docs/resilience.md",
73
+ "language": "md",
74
+ "startLine": 1,
75
+ "endLine": 40,
76
+ "symbols": [],
77
+ "content": "# Resilience Patterns\n\nThis project uses exponential backoff with jitter for all HTTP retries...",
78
+ "score": 0.812
79
+ }
80
+ ],
81
+ "metadata": {
82
+ "collection": "myapp_code",
83
+ "model": "voyage-code-3",
84
+ "rerankModel": "rerank-2.5",
85
+ "reranked": true,
86
+ "resultCount": 2,
87
+ "timeMs": 234
88
+ }
89
+ },
90
+ "code_query": {
91
+ "results": [
92
+ {
93
+ "source": "src/lib/http-client.js",
94
+ "language": "js",
95
+ "startLine": 88,
96
+ "endLine": 112,
97
+ "symbols": ["retryRequest", "exponentialDelay"],
98
+ "content": "async function retryRequest(url, opts, retries = 5) { ... }",
99
+ "score": 0.943
100
+ }
101
+ ],
102
+ "metadata": {
103
+ "collection": "myapp_code",
104
+ "model": "voyage-code-3",
105
+ "reranked": true,
106
+ "resultCount": 1,
107
+ "timeMs": 198
108
+ }
109
+ }
110
+ },
111
+ "expect": {
112
+ "steps": {
113
+ "check_index": { "status": "completed" },
114
+ "index_codebase": { "status": "skipped" },
115
+ "find_similar": { "status": "completed" },
116
+ "contextual_search": { "status": "completed" },
117
+ "deep_query": { "status": "completed" }
118
+ },
119
+ "noErrors": true
120
+ }
121
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "code-review: no question — skip deep_query, auto-generate search from snippet",
3
+ "inputs": {
4
+ "source": "/Users/dev/myapp",
5
+ "code": "class DatabasePool {\n constructor(uri, { maxSize = 10, idleTimeoutMs = 30000 }) {\n this.pool = [];\n this.maxSize = maxSize;\n }\n async acquire() { ... }\n release(conn) { ... }\n}",
6
+ "limit": 3
7
+ },
8
+ "mocks": {
9
+ "code_status": {
10
+ "totalChunks": 500,
11
+ "uniqueFiles": 80,
12
+ "collection": "myapp_code",
13
+ "languages": { "js": 60, "ts": 20 },
14
+ "lastIndexed": "2026-02-16T10:00:00.000Z",
15
+ "indexes": [{ "name": "code_search_index", "status": "READY" }]
16
+ },
17
+ "code_index": null,
18
+ "code_find_similar": {
19
+ "results": [
20
+ {
21
+ "source": "src/lib/redis-pool.js",
22
+ "language": "js",
23
+ "startLine": 5,
24
+ "endLine": 45,
25
+ "symbols": ["RedisPool", "acquire", "release"],
26
+ "content": "class RedisPool { constructor(opts) { ... } async acquire() { ... } }",
27
+ "score": 0.889,
28
+ "chunkType": "boundary"
29
+ }
30
+ ],
31
+ "metadata": {
32
+ "collection": "myapp_code",
33
+ "model": "voyage-code-3",
34
+ "resultCount": 1,
35
+ "timeMs": 156
36
+ }
37
+ },
38
+ "code_search": {
39
+ "results": [
40
+ {
41
+ "source": "src/lib/mongo.js",
42
+ "language": "js",
43
+ "startLine": 12,
44
+ "endLine": 50,
45
+ "symbols": ["getMongoCollection", "closeClient"],
46
+ "content": "async function getMongoCollection(db, collection) { ... }",
47
+ "score": 0.801
48
+ }
49
+ ],
50
+ "metadata": {
51
+ "collection": "myapp_code",
52
+ "model": "voyage-code-3",
53
+ "reranked": true,
54
+ "resultCount": 1,
55
+ "timeMs": 189
56
+ }
57
+ },
58
+ "code_query": null
59
+ },
60
+ "expect": {
61
+ "steps": {
62
+ "check_index": { "status": "completed" },
63
+ "index_codebase": { "status": "skipped" },
64
+ "find_similar": { "status": "completed" },
65
+ "contextual_search": { "status": "completed" },
66
+ "deep_query": { "status": "skipped" }
67
+ },
68
+ "noErrors": true
69
+ }
70
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-ingest: duplicate detected (high similarity)",
3
- "description": "NOTE: Due to a known dependency extraction issue with negated conditions (!similarity_check), the ingest_doc step's condition cannot properly wait for similarity_check. The !prefix prevents dependency tracking, so ingest_doc runs in parallel with check_existing. The condition evaluates with similarity_check.output as undefined, making !undefined = true, so ingest_doc always executes. This test validates actual engine behavior.",
3
+ "description": "When a near-duplicate is found (similarity above 0.85), the ingest_doc step is correctly skipped to avoid ingesting duplicate content.",
4
4
  "inputs": {
5
5
  "text": "A document that already exists in the knowledge base",
6
6
  "source": "existing-doc.md",
@@ -27,7 +27,7 @@
27
27
  "steps": {
28
28
  "check_existing": { "status": "completed" },
29
29
  "similarity_check": { "status": "completed" },
30
- "ingest_doc": { "status": "completed" }
30
+ "ingest_doc": { "status": "skipped" }
31
31
  },
32
32
  "noErrors": true
33
33
  }