@zvec/zvec-grep 0.1.4 → 0.1.5

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 (135) hide show
  1. package/README.md +127 -42
  2. package/README_CN.md +124 -42
  3. package/dist/cli/args.d.ts +3 -0
  4. package/dist/cli/args.js +490 -192
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/commands.d.ts +3 -1
  7. package/dist/cli/commands.js +590 -56
  8. package/dist/cli/commands.js.map +1 -1
  9. package/dist/cli/errors.js +6 -5
  10. package/dist/cli/errors.js.map +1 -1
  11. package/dist/cli/format/context.js +33 -29
  12. package/dist/cli/format/context.js.map +1 -1
  13. package/dist/cli/format/debug.js +12 -14
  14. package/dist/cli/format/debug.js.map +1 -1
  15. package/dist/cli/format/highlight.js.map +1 -1
  16. package/dist/cli/format/progress.js +8 -3
  17. package/dist/cli/format/progress.js.map +1 -1
  18. package/dist/cli/format/range.js.map +1 -1
  19. package/dist/cli/format/status.js +59 -26
  20. package/dist/cli/format/status.js.map +1 -1
  21. package/dist/cli/help.d.ts +1 -1
  22. package/dist/cli/help.js +170 -85
  23. package/dist/cli/help.js.map +1 -1
  24. package/dist/cli/index.js +4 -4
  25. package/dist/cli/index.js.map +1 -1
  26. package/dist/cli/mcp.d.ts +2 -0
  27. package/dist/cli/mcp.js +354 -0
  28. package/dist/cli/mcp.js.map +1 -0
  29. package/dist/cli/types.d.ts +22 -9
  30. package/dist/cli/types.js.map +1 -1
  31. package/dist/cli/version.js +3 -1
  32. package/dist/cli/version.js.map +1 -1
  33. package/dist/engine/collection/index.js +15 -15
  34. package/dist/engine/collection/index.js.map +1 -1
  35. package/dist/engine/config.d.ts +28 -0
  36. package/dist/engine/config.js +195 -0
  37. package/dist/engine/config.js.map +1 -0
  38. package/dist/engine/errors/details.js.map +1 -1
  39. package/dist/engine/errors/index.js.map +1 -1
  40. package/dist/engine/extraction/code/adapter.js.map +1 -1
  41. package/dist/engine/extraction/code/extractor.js +87 -73
  42. package/dist/engine/extraction/code/extractor.js.map +1 -1
  43. package/dist/engine/extraction/code/families/c-family.js +12 -6
  44. package/dist/engine/extraction/code/families/c-family.js.map +1 -1
  45. package/dist/engine/extraction/code/families/js-ts.js +24 -18
  46. package/dist/engine/extraction/code/families/js-ts.js.map +1 -1
  47. package/dist/engine/extraction/code/families/metadata.js +11 -8
  48. package/dist/engine/extraction/code/families/metadata.js.map +1 -1
  49. package/dist/engine/extraction/code/families/name-field.js +5 -5
  50. package/dist/engine/extraction/code/families/name-field.js.map +1 -1
  51. package/dist/engine/extraction/code/languages/c.js +1 -4
  52. package/dist/engine/extraction/code/languages/c.js.map +1 -1
  53. package/dist/engine/extraction/code/languages/cpp.js.map +1 -1
  54. package/dist/engine/extraction/code/languages/go.js +1 -3
  55. package/dist/engine/extraction/code/languages/go.js.map +1 -1
  56. package/dist/engine/extraction/code/languages/java.js.map +1 -1
  57. package/dist/engine/extraction/code/languages/javascript.js +1 -3
  58. package/dist/engine/extraction/code/languages/javascript.js.map +1 -1
  59. package/dist/engine/extraction/code/languages/python.js +5 -6
  60. package/dist/engine/extraction/code/languages/python.js.map +1 -1
  61. package/dist/engine/extraction/code/languages/rust.js +1 -5
  62. package/dist/engine/extraction/code/languages/rust.js.map +1 -1
  63. package/dist/engine/extraction/code/languages/typescript.js.map +1 -1
  64. package/dist/engine/extraction/ids.js.map +1 -1
  65. package/dist/engine/extraction/index.js +3 -3
  66. package/dist/engine/extraction/index.js.map +1 -1
  67. package/dist/engine/extraction/markdown/extractor.js +4 -2
  68. package/dist/engine/extraction/markdown/extractor.js.map +1 -1
  69. package/dist/engine/extraction/tree-sitter/grammar.js.map +1 -1
  70. package/dist/engine/extraction/tree-sitter/nodes.js +2 -1
  71. package/dist/engine/extraction/tree-sitter/nodes.js.map +1 -1
  72. package/dist/engine/extraction/tree-sitter/parser.js.map +1 -1
  73. package/dist/engine/files/file-type.js.map +1 -1
  74. package/dist/engine/models/catalog.js +7 -23
  75. package/dist/engine/models/catalog.js.map +1 -1
  76. package/dist/engine/models/embeddings.js +3 -3
  77. package/dist/engine/models/embeddings.js.map +1 -1
  78. package/dist/engine/models/factory.js.map +1 -1
  79. package/dist/engine/models/index.d.ts +1 -1
  80. package/dist/engine/models/index.js.map +1 -1
  81. package/dist/engine/models/providers/index.d.ts +1 -1
  82. package/dist/engine/models/providers/index.js +1 -1
  83. package/dist/engine/models/providers/index.js.map +1 -1
  84. package/dist/engine/models/providers/llama-cpp/embedding.js +49 -18
  85. package/dist/engine/models/providers/llama-cpp/embedding.js.map +1 -1
  86. package/dist/engine/models/providers/qwen/embedding.js +16 -11
  87. package/dist/engine/models/providers/qwen/embedding.js.map +1 -1
  88. package/dist/engine/models/providers/qwen/index.d.ts +1 -1
  89. package/dist/engine/models/providers/qwen/index.js +1 -1
  90. package/dist/engine/models/providers/qwen/index.js.map +1 -1
  91. package/dist/engine/pipeline/indexing/index.js +46 -33
  92. package/dist/engine/pipeline/indexing/index.js.map +1 -1
  93. package/dist/engine/pipeline/indexing/root-paths.js +10 -13
  94. package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
  95. package/dist/engine/pipeline/indexing/scanner/index.js +91 -43
  96. package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
  97. package/dist/engine/pipeline/search/index.js +68 -24
  98. package/dist/engine/pipeline/search/index.js.map +1 -1
  99. package/dist/engine/service/index.d.ts +1 -1
  100. package/dist/engine/service/lexical.d.ts +14 -15
  101. package/dist/engine/service/lexical.js +78 -119
  102. package/dist/engine/service/lexical.js.map +1 -1
  103. package/dist/engine/service/root.js +2 -2
  104. package/dist/engine/service/root.js.map +1 -1
  105. package/dist/engine/service/structure-enrichment.js +17 -11
  106. package/dist/engine/service/structure-enrichment.js.map +1 -1
  107. package/dist/engine/service/types.d.ts +39 -8
  108. package/dist/engine/service/zvec-grep.js +303 -160
  109. package/dist/engine/service/zvec-grep.js.map +1 -1
  110. package/dist/engine/storage/index.js.map +1 -1
  111. package/dist/engine/storage/zvec.js +15 -11
  112. package/dist/engine/storage/zvec.js.map +1 -1
  113. package/dist/engine/types.d.ts +14 -0
  114. package/dist/engine/types.js.map +1 -1
  115. package/dist/engine/utils/file-selection.d.ts +10 -0
  116. package/dist/engine/utils/file-selection.js +120 -0
  117. package/dist/engine/utils/file-selection.js.map +1 -0
  118. package/dist/engine/utils/glob.d.ts +3 -0
  119. package/dist/engine/utils/glob.js +116 -18
  120. package/dist/engine/utils/glob.js.map +1 -1
  121. package/dist/engine/utils/hash.js.map +1 -1
  122. package/dist/engine/utils/json.d.ts +6 -2
  123. package/dist/engine/utils/json.js +50 -12
  124. package/dist/engine/utils/json.js.map +1 -1
  125. package/dist/engine/utils/lock.js +6 -6
  126. package/dist/engine/utils/lock.js.map +1 -1
  127. package/dist/engine/utils/path.js +2 -2
  128. package/dist/engine/utils/path.js.map +1 -1
  129. package/dist/engine/utils/timing.js.map +1 -1
  130. package/dist/index.d.ts +3 -3
  131. package/dist/index.js +2 -2
  132. package/dist/index.js.map +1 -1
  133. package/package.json +34 -7
  134. package/skills/zvec-grep/SKILL.md +58 -48
  135. package/skills/zvec-grep/agents/openai.yaml +1 -1
package/dist/cli/args.js CHANGED
@@ -1,27 +1,44 @@
1
1
  import { VALID_SYMBOL_TYPES } from "./types.js";
2
2
  const RG_OPTIONS_WITH_VALUE = new Set([
3
+ "--dfa-size-limit",
3
4
  "--encoding",
4
5
  "--engine",
5
- "--ignore-file",
6
- "--max-depth",
7
- "--type",
8
- "--type-not",
6
+ "--max-columns",
7
+ "--max-count",
8
+ "--regex-size-limit",
9
+ "--threads",
9
10
  ]);
10
11
  const RG_OPTIONS_WITHOUT_VALUE = new Set([
11
12
  "--auto-hybrid-regex",
12
13
  "--case-sensitive",
13
- "--glob-case-insensitive",
14
+ "--binary",
15
+ "--crlf",
16
+ "--invert-match",
17
+ "--line-regexp",
18
+ "--mmap",
14
19
  "--multiline",
15
20
  "--multiline-dotall",
21
+ "--no-crlf",
22
+ "--no-fixed-strings",
16
23
  "--no-ignore",
17
24
  "--no-ignore-dot",
18
25
  "--no-ignore-files",
19
26
  "--no-ignore-global",
20
27
  "--no-ignore-parent",
21
28
  "--no-ignore-vcs",
29
+ "--no-config",
30
+ "--no-mmap",
31
+ "--no-multiline",
32
+ "--no-search-zip",
22
33
  "--pcre2",
34
+ "--one-file-system",
23
35
  "--search-zip",
24
36
  "--smart-case",
37
+ "--stop-on-nonmatch",
38
+ "--text",
39
+ "--unicode",
40
+ "--no-unicode",
41
+ "--glob-case-insensitive",
25
42
  ]);
26
43
  const MANAGED_RG_OUTPUT_OPTIONS = new Set([
27
44
  "--count",
@@ -29,18 +46,51 @@ const MANAGED_RG_OUTPUT_OPTIONS = new Set([
29
46
  "--files",
30
47
  "--files-with-matches",
31
48
  "--files-without-match",
49
+ "--column",
50
+ "--byte-offset",
51
+ "--no-column",
52
+ "--colors",
53
+ "--context-separator",
54
+ "--field-context-separator",
55
+ "--field-match-separator",
32
56
  "--json",
57
+ "--heading",
58
+ "--no-heading",
59
+ "--no-filename",
60
+ "--no-line-number",
33
61
  "--only-matching",
62
+ "--passthru",
63
+ "--path-separator",
64
+ "--quiet",
65
+ "--pretty",
34
66
  "--replace",
67
+ "--stats",
68
+ "--trim",
35
69
  "--vimgrep",
36
70
  "-c",
71
+ "-b",
72
+ "-I",
37
73
  "-l",
74
+ "-N",
38
75
  "-o",
76
+ "-p",
77
+ "-q",
78
+ "-r",
39
79
  ]);
40
80
  export function parseArgs(args) {
81
+ const commandInput = parseCommand(args);
82
+ if (commandInput.command === "help" || commandInput.command === "version") {
83
+ return {
84
+ command: commandInput.command,
85
+ options: {},
86
+ positionals: [],
87
+ ...(commandInput.helpTopic ? { helpTopic: commandInput.helpTopic } : {}),
88
+ };
89
+ }
41
90
  const options = {};
42
91
  const positionals = [];
43
- for (let index = 0; index < args.length; index++) {
92
+ const startIndex = 1;
93
+ for (let index = startIndex; index < args.length; index++) {
44
94
  const arg = args[index];
45
95
  if (arg === "--") {
46
96
  positionals.push(...args.slice(index + 1));
@@ -51,22 +101,33 @@ export function parseArgs(args) {
51
101
  continue;
52
102
  }
53
103
  if (arg === "--help" || arg === "-h") {
54
- options.help = true;
104
+ return {
105
+ command: "help",
106
+ options: {},
107
+ positionals: [],
108
+ helpTopic: commandInput.command,
109
+ };
110
+ }
111
+ else if (arg === "--version") {
112
+ throw new Error(`${arg} must be used without a command`);
113
+ }
114
+ else if (arg === "--mcp") {
115
+ options.mcp = true;
55
116
  }
56
- else if (arg === "--version" || arg === "-v") {
57
- options.version = true;
117
+ else if (isLongOptionWithValue(arg, "--target")) {
118
+ options.installTargets = appendInstallTargets(options.installTargets, valueFromLongOption(arg));
58
119
  }
59
- else if (arg === "--index") {
60
- options.index = true;
120
+ else if (arg === "--target") {
121
+ options.installTargets = appendInstallTargets(options.installTargets, readOptionValue(args, ++index, arg));
61
122
  }
62
- else if (arg === "--disable-index") {
63
- options.disableIndex = true;
123
+ else if (isLongOptionWithValue(arg, "--mcp-tool-timeout")) {
124
+ options.installMcpToolTimeoutSeconds = parsePositiveInteger(valueFromLongOption(arg), "--mcp-tool-timeout");
64
125
  }
65
- else if (arg === "--status") {
66
- options.status = true;
126
+ else if (arg === "--mcp-tool-timeout") {
127
+ options.installMcpToolTimeoutSeconds = parsePositiveInteger(readOptionValue(args, ++index, arg), arg);
67
128
  }
68
- else if (arg === "--collections") {
69
- options.collections = true;
129
+ else if (arg === "--yes") {
130
+ options.yes = true;
70
131
  }
71
132
  else if (arg === "--rg") {
72
133
  options.rg = true;
@@ -95,12 +156,15 @@ export function parseArgs(args) {
95
156
  else if (arg === "--rebuild") {
96
157
  options.rebuild = true;
97
158
  }
159
+ else if (arg === "--drop") {
160
+ options.drop = true;
161
+ }
162
+ else if (arg === "--force") {
163
+ options.force = true;
164
+ }
98
165
  else if (arg === "--reset-paths") {
99
166
  options.resetPaths = true;
100
167
  }
101
- else if (arg === "--no-fallback") {
102
- options.noFallback = true;
103
- }
104
168
  else if (arg === "--no-auto-update") {
105
169
  options.noAutoUpdate = true;
106
170
  }
@@ -143,57 +207,99 @@ export function parseArgs(args) {
143
207
  else if (arg === "--embedding-concurrency") {
144
208
  options.embeddingConcurrency = parsePositiveInteger(readOptionValue(args, ++index, arg), arg);
145
209
  }
210
+ else if (isLongOptionWithValue(arg, "--hybrid")) {
211
+ options.hybridQueries = appendQuery(options.hybridQueries, valueFromLongOption(arg), "--hybrid");
212
+ }
213
+ else if (arg === "--hybrid") {
214
+ options.hybridQueries = appendQuery(options.hybridQueries, readOptionValue(args, ++index, arg), arg);
215
+ }
216
+ else if (isLongOptionWithValue(arg, "--fts")) {
217
+ options.routes = appendRoute(options.routes, "fts", valueFromLongOption(arg), "--fts");
218
+ }
146
219
  else if (arg === "--fts") {
147
- const routeValues = readRouteOptionValues(args, index + 1, arg);
148
- options.routes = appendRoutes(options.routes, "fts", routeValues.values);
149
- index = routeValues.nextIndex - 1;
220
+ options.routes = appendRoute(options.routes, "fts", readOptionValue(args, ++index, arg), arg);
221
+ }
222
+ else if (isLongOptionWithValue(arg, "--vector")) {
223
+ options.routes = appendRoute(options.routes, "vector", valueFromLongOption(arg), "--vector");
150
224
  }
151
225
  else if (arg === "--vector") {
152
- const routeValues = readRouteOptionValues(args, index + 1, arg);
153
- options.routes = appendRoutes(options.routes, "vector", routeValues.values);
154
- index = routeValues.nextIndex - 1;
226
+ options.routes = appendRoute(options.routes, "vector", readOptionValue(args, ++index, arg), arg);
227
+ }
228
+ else if (arg === "--fuse") {
229
+ options.fuse = true;
155
230
  }
156
231
  else if (arg === "--color") {
157
232
  options.color = parseColorMode(readOptionValue(args, ++index, arg));
158
233
  }
159
- else if (isLongOptionWithValue(arg, "--include")) {
160
- options.includePaths = appendPathFilters(options.includePaths, valueFromLongOption(arg));
234
+ else if (isLongOptionWithValue(arg, "--glob")) {
235
+ options.globs = appendValue(options.globs, valueFromLongOption(arg), "--glob");
236
+ }
237
+ else if (arg === "--glob" || arg === "-g") {
238
+ options.globs = appendValue(options.globs, readOptionValue(args, ++index, arg), arg);
239
+ }
240
+ else if (isLongOptionWithValue(arg, "--iglob")) {
241
+ options.insensitiveGlobs = appendValue(options.insensitiveGlobs, valueFromLongOption(arg), "--iglob");
242
+ }
243
+ else if (arg === "--iglob") {
244
+ options.insensitiveGlobs = appendValue(options.insensitiveGlobs, readOptionValue(args, ++index, arg), arg);
245
+ }
246
+ else if (isLongOptionWithValue(arg, "--type")) {
247
+ options.fileTypes = appendValue(options.fileTypes, valueFromLongOption(arg), "--type");
248
+ }
249
+ else if (arg === "--type" || arg === "-t") {
250
+ options.fileTypes = appendValue(options.fileTypes, readOptionValue(args, ++index, arg), arg);
251
+ }
252
+ else if (isLongOptionWithValue(arg, "--type-not")) {
253
+ options.excludedFileTypes = appendValue(options.excludedFileTypes, valueFromLongOption(arg), "--type-not");
254
+ }
255
+ else if (arg === "--type-not" || arg === "-T") {
256
+ options.excludedFileTypes = appendValue(options.excludedFileTypes, readOptionValue(args, ++index, arg), arg);
257
+ }
258
+ else if (arg === "--hidden") {
259
+ options.hidden = true;
260
+ }
261
+ else if (arg === "--no-ignore") {
262
+ options.noIgnore = true;
263
+ }
264
+ else if (isLongOptionWithValue(arg, "--ignore-file")) {
265
+ options.ignoreFiles = appendValue(options.ignoreFiles, valueFromLongOption(arg), "--ignore-file");
266
+ }
267
+ else if (arg === "--ignore-file") {
268
+ options.ignoreFiles = appendValue(options.ignoreFiles, readOptionValue(args, ++index, arg), arg);
161
269
  }
162
- else if (arg === "--include") {
163
- options.includePaths = appendPathFilters(options.includePaths, readOptionValue(args, ++index, arg));
270
+ else if (isLongOptionWithValue(arg, "--max-depth")) {
271
+ options.maxDepth = parseNonNegativeInteger(valueFromLongOption(arg), "--max-depth");
164
272
  }
165
- else if (isLongOptionWithValue(arg, "--exclude")) {
166
- options.excludePaths = appendPathFilters(options.excludePaths, valueFromLongOption(arg));
273
+ else if (arg === "--max-depth") {
274
+ options.maxDepth = parseNonNegativeInteger(readOptionValue(args, ++index, arg), arg);
167
275
  }
168
- else if (arg === "--exclude") {
169
- options.excludePaths = appendPathFilters(options.excludePaths, readOptionValue(args, ++index, arg));
276
+ else if (isLongOptionWithValue(arg, "--max-filesize")) {
277
+ options.maxFileSizeBytes = parseByteSize(valueFromLongOption(arg), "--max-filesize");
278
+ }
279
+ else if (arg === "--max-filesize") {
280
+ options.maxFileSizeBytes = parseByteSize(readOptionValue(args, ++index, arg), arg);
281
+ }
282
+ else if (arg === "--follow" || arg === "-L") {
283
+ options.follow = true;
170
284
  }
171
285
  else if (arg === "--ignore-case") {
172
- options.rgOptions = {
173
- ...(options.rgOptions ?? {}),
174
- ignoreCase: true,
175
- };
286
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [arg]);
176
287
  markRgCompatibilityOption(options, arg);
177
288
  }
178
289
  else if (arg === "--word-regexp") {
179
- options.rgOptions = {
180
- ...(options.rgOptions ?? {}),
181
- wordRegexp: true,
182
- };
290
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [arg]);
183
291
  markRgCompatibilityOption(options, arg);
184
292
  }
185
293
  else if (arg === "--fixed-strings") {
186
- options.rgOptions = {
187
- ...(options.rgOptions ?? {}),
188
- fixedStrings: true,
189
- };
294
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [arg]);
190
295
  markRgCompatibilityOption(options, arg);
191
296
  }
192
- else if (arg === "--hidden") {
193
- options.rgOptions = {
194
- ...(options.rgOptions ?? {}),
195
- hidden: true,
196
- };
297
+ else if (isLongOptionWithValue(arg, "--file")) {
298
+ options.rgOptions = appendRgPatternFile(options.rgOptions, valueFromLongOption(arg), "--file");
299
+ markRgCompatibilityOption(options, "--file");
300
+ }
301
+ else if (arg === "--file") {
302
+ options.rgOptions = appendRgPatternFile(options.rgOptions, readOptionValue(args, ++index, arg), arg);
197
303
  markRgCompatibilityOption(options, arg);
198
304
  }
199
305
  else if (isRgFlagWithValue(arg)) {
@@ -215,7 +321,9 @@ export function parseArgs(args) {
215
321
  options.rgOptions = appendRgExtraArgs(options.rgOptions, [arg]);
216
322
  markRgCompatibilityOption(options, arg);
217
323
  }
218
- else if (arg === "--recursive" || arg === "--line-number" || arg === "--with-filename") {
324
+ else if (arg === "--recursive" ||
325
+ arg === "--line-number" ||
326
+ arg === "--with-filename") {
219
327
  markRgCompatibilityOption(options, arg);
220
328
  }
221
329
  else if (isLongOptionWithValue(arg, "--regexp")) {
@@ -250,18 +358,6 @@ export function parseArgs(args) {
250
358
  options.rgOptions = setRgContext(options.rgOptions, "after", readOptionValue(args, ++index, arg), arg);
251
359
  markRgCompatibilityOption(options, arg);
252
360
  }
253
- else if (isLongOptionWithValue(arg, "--glob")) {
254
- appendRgGlobFilter(options, valueFromLongOption(arg));
255
- markRgCompatibilityOption(options, "--glob");
256
- }
257
- else if (arg === "--glob") {
258
- appendRgGlobFilter(options, readOptionValue(args, ++index, arg));
259
- markRgCompatibilityOption(options, arg);
260
- }
261
- else if (arg === "-g") {
262
- appendRgGlobFilter(options, readOptionValue(args, ++index, arg));
263
- markRgCompatibilityOption(options, arg);
264
- }
265
361
  else if (isManagedRgOutputOption(arg)) {
266
362
  throw new Error(`${arg} changes rg output and cannot be used with managed --rg`);
267
363
  }
@@ -275,83 +371,227 @@ export function parseArgs(args) {
275
371
  options.modifiedBefore = parseModifiedTime(readOptionValue(args, ++index, arg), arg);
276
372
  }
277
373
  else if (arg === "--symbol-type") {
278
- options.symbolTypes = [...(options.symbolTypes ?? []), parseSymbolType(readOptionValue(args, ++index, arg))];
374
+ options.symbolTypes = [
375
+ ...(options.symbolTypes ?? []),
376
+ parseSymbolType(readOptionValue(args, ++index, arg)),
377
+ ];
279
378
  }
280
379
  else {
281
380
  throw new Error(`Unknown option: ${arg}`);
282
381
  }
283
382
  }
284
- validateCliShape(options);
285
- return { options, positionals };
383
+ validateCliShape(commandInput.command, options, positionals);
384
+ return { command: commandInput.command, options, positionals };
286
385
  }
287
- function validateCliShape(options) {
288
- if (options.index && options.collections) {
289
- throw new Error("--index and --collections cannot be used together");
290
- }
291
- if (options.disableIndex && options.collections) {
292
- throw new Error("--disable-index and --collections cannot be used together");
293
- }
294
- if (options.disableIndex && options.index) {
295
- throw new Error("--disable-index and --index cannot be used together");
296
- }
297
- if (options.disableIndex && options.status) {
298
- throw new Error("--disable-index and --status cannot be used together");
299
- }
300
- if (options.status && options.collections) {
301
- throw new Error("--status and --collections cannot be used together");
302
- }
303
- if (options.status && options.index) {
304
- throw new Error("--status and --index cannot be used together");
305
- }
306
- if (options.status && options.collection) {
307
- throw new Error("--status does not accept --collection; use --collections info <name>");
308
- }
309
- if (options.index && options.collection) {
310
- throw new Error("--index does not accept --collection");
386
+ function parseCommand(args) {
387
+ const [first, ...rest] = args;
388
+ if (first === undefined ||
389
+ first === "help" ||
390
+ first === "-h" ||
391
+ first === "--help") {
392
+ if (first !== "help" && rest.length > 0) {
393
+ throw new Error(`${first} does not accept arguments`);
394
+ }
395
+ if (first === "help" && rest.length > 1) {
396
+ throw new Error("zg help accepts at most one command name");
397
+ }
398
+ return {
399
+ command: "help",
400
+ ...(first === "help" && rest[0] ? { helpTopic: rest[0] } : {}),
401
+ };
311
402
  }
312
- if (options.disableIndex && options.collection) {
313
- throw new Error("--disable-index does not accept --collection");
403
+ if (first === "version" || first === "-v" || first === "--version") {
404
+ const acceptsVersionFlag = first === "version" &&
405
+ rest.length === 1 &&
406
+ (rest[0] === "-v" || rest[0] === "--version");
407
+ if (rest.length > 0 && !acceptsVersionFlag) {
408
+ throw new Error(`${first} does not accept arguments`);
409
+ }
410
+ return { command: "version" };
411
+ }
412
+ if (first === "query" ||
413
+ first === "index" ||
414
+ first === "status" ||
415
+ first === "collections" ||
416
+ first === "install" ||
417
+ first === "uninstall" ||
418
+ first === "serve") {
419
+ return { command: first };
420
+ }
421
+ throw new Error(`Unknown command: ${first}`);
422
+ }
423
+ function validateCliShape(command, options, positionals) {
424
+ const queryOnly = firstEnabledOption([
425
+ [options.rg, "--rg"],
426
+ [options.hybridQueries?.length, "--hybrid"],
427
+ [options.routes?.length, "--fts/--vector"],
428
+ [options.fuse, "--fuse"],
429
+ [options.debug, "--debug"],
430
+ [options.trace, "--trace"],
431
+ [options.human, "--human"],
432
+ [options.preview, "--preview"],
433
+ [options.limit, "--limit"],
434
+ [options.noAutoUpdate, "--no-auto-update"],
435
+ [options.preferSymbol, "--prefer-symbol"],
436
+ [options.symbolTypes?.length, "--symbol-type"],
437
+ [options.modifiedAfter, "--modified-after"],
438
+ [options.modifiedBefore, "--modified-before"],
439
+ [options.collection, "--collection"],
440
+ [options.rgCompatibilityOptions?.length, "ripgrep options"],
441
+ ]);
442
+ if (command !== "query" && queryOnly) {
443
+ throw new Error(`${queryOnly} can only be used with zg query`);
444
+ }
445
+ const sharedSelection = firstEnabledOption([
446
+ [options.globs?.length, "--glob"],
447
+ [options.insensitiveGlobs?.length, "--iglob"],
448
+ [options.fileTypes?.length, "--type"],
449
+ [options.excludedFileTypes?.length, "--type-not"],
450
+ ]);
451
+ if (sharedSelection &&
452
+ command !== "query" &&
453
+ command !== "index" &&
454
+ command !== "collections") {
455
+ throw new Error(`${sharedSelection} can only be used with query or index commands`);
456
+ }
457
+ const discoveryOption = firstEnabledOption([
458
+ [options.hidden, "--hidden"],
459
+ [options.noIgnore, "--no-ignore"],
460
+ [options.ignoreFiles?.length, "--ignore-file"],
461
+ [options.maxDepth, "--max-depth"],
462
+ [options.maxFileSizeBytes, "--max-filesize"],
463
+ [options.follow, "--follow"],
464
+ ]);
465
+ if (discoveryOption &&
466
+ command !== "index" &&
467
+ command !== "collections" &&
468
+ !(command === "query" && options.rg)) {
469
+ throw new Error(`${discoveryOption} can only be used with index commands or zg query --rg`);
470
+ }
471
+ if (options.rg &&
472
+ (hasExplicitRoutes(options) || options.hybridQueries?.length)) {
473
+ throw new Error("--rg cannot be combined with --hybrid, --fts, or --vector");
474
+ }
475
+ if (options.rg && options.fuse) {
476
+ throw new Error("--rg cannot be combined with --fuse");
314
477
  }
315
478
  if (options.rg && options.collection) {
316
- throw new Error("--rg does not accept --collection");
317
- }
318
- if (options.collections && options.collection) {
319
- throw new Error("--collections and --collection cannot be used together");
320
- }
321
- if ((options.index || options.disableIndex || options.status || options.collections) && hasExplicitRoutes(options)) {
322
- throw new Error("--fts and --vector can only be used with query commands");
323
- }
324
- if ((options.index || options.disableIndex || options.status || options.collections) && options.rg) {
325
- throw new Error("--rg can only be used with query commands");
326
- }
327
- if ((options.index || options.disableIndex || options.status || options.collections) && options.preview) {
328
- throw new Error("--preview can only be used with query commands");
329
- }
330
- if ((options.index || options.disableIndex || options.status || options.collections) && options.noAutoUpdate) {
331
- throw new Error("--no-auto-update can only be used with query commands");
332
- }
333
- if (options.rg && hasExplicitRoutes(options)) {
334
- throw new Error("--rg cannot be combined with --fts or --vector");
479
+ throw new Error("--rg cannot be combined with --collection");
335
480
  }
336
481
  if (options.rg && options.preview) {
337
482
  throw new Error("--preview is not supported with --rg; use -A/-B/-C for rg context");
338
483
  }
339
- if (options.rg && options.noFallback) {
340
- throw new Error("--rg cannot be combined with --no-fallback");
341
- }
342
484
  if (options.rg && options.trace) {
343
485
  throw new Error("--rg cannot be combined with --trace");
344
486
  }
345
487
  if (options.rg && (options.preferSymbol || options.symbolTypes?.length)) {
346
488
  throw new Error("--rg cannot be combined with indexed symbol options");
347
489
  }
348
- if (options.resetPaths && !options.index && !options.collections) {
349
- throw new Error("--reset-paths can only be used with --index or --collections index");
490
+ if (options.rg &&
491
+ (options.noAutoUpdate || options.embeddingConcurrency !== undefined)) {
492
+ throw new Error("--rg cannot be combined with indexed refresh options");
350
493
  }
351
494
  if (!options.rg && (options.rgCompatibilityOptions?.length ?? 0) > 0) {
352
495
  const [option] = options.rgCompatibilityOptions;
353
496
  throw new Error(`${option} can only be used with --rg`);
354
497
  }
498
+ if (options.mcp && command !== "serve") {
499
+ throw new Error("--mcp can only be used with zg serve");
500
+ }
501
+ if (command === "serve" && !options.mcp) {
502
+ throw new Error("zg serve currently requires --mcp");
503
+ }
504
+ if (options.installTargets?.length &&
505
+ command !== "install" &&
506
+ command !== "uninstall") {
507
+ throw new Error("--target can only be used with zg install or zg uninstall");
508
+ }
509
+ if (options.installMcpToolTimeoutSeconds !== undefined &&
510
+ command !== "install") {
511
+ throw new Error("--mcp-tool-timeout can only be used with zg install");
512
+ }
513
+ if (options.force && command !== "install") {
514
+ throw new Error("--force can only be used with zg install");
515
+ }
516
+ if (command === "install" || command === "uninstall") {
517
+ const unsupported = firstEnabledOption([
518
+ [options.mcp, "--mcp"],
519
+ [options.color, "--color"],
520
+ [options.home, "--home"],
521
+ [options.embedding, "--embedding"],
522
+ [options.modelCacheDir, "--model-cache"],
523
+ [options.llamaGpu, "--llama-gpu"],
524
+ [options.embeddingParallelism, "--embedding-parallelism"],
525
+ [options.apiKey, "--api-key"],
526
+ [options.endpoint, "--endpoint"],
527
+ [options.rebuild, "--rebuild"],
528
+ [options.drop, "--drop"],
529
+ [options.resetPaths, "--reset-paths"],
530
+ [options.globs?.length, "--glob"],
531
+ [options.insensitiveGlobs?.length, "--iglob"],
532
+ [options.fileTypes?.length, "--type"],
533
+ [options.excludedFileTypes?.length, "--type-not"],
534
+ [options.hidden, "--hidden"],
535
+ [options.noIgnore, "--no-ignore"],
536
+ [options.ignoreFiles?.length, "--ignore-file"],
537
+ [options.maxDepth, "--max-depth"],
538
+ [options.maxFileSizeBytes, "--max-filesize"],
539
+ [options.follow, "--follow"],
540
+ [options.embeddingConcurrency, "--embedding-concurrency"],
541
+ ]);
542
+ if (unsupported) {
543
+ throw new Error(`${unsupported} is not supported with zg ${command}`);
544
+ }
545
+ }
546
+ if (options.yes &&
547
+ command !== "install" &&
548
+ command !== "uninstall" &&
549
+ !(command === "index" && options.drop)) {
550
+ throw new Error("--yes is only valid for install, uninstall, or index --drop");
551
+ }
552
+ if (options.drop && command !== "index") {
553
+ throw new Error("--drop can only be used with zg index");
554
+ }
555
+ if (options.rebuild && command !== "index" && command !== "collections") {
556
+ throw new Error("--rebuild can only be used with zg index or zg collections index");
557
+ }
558
+ if (options.resetPaths && command !== "index" && command !== "collections") {
559
+ throw new Error("--reset-paths can only be used with zg index or zg collections index");
560
+ }
561
+ if (options.drop &&
562
+ (options.rebuild ||
563
+ options.resetPaths ||
564
+ options.home ||
565
+ options.embedding ||
566
+ options.modelCacheDir ||
567
+ options.llamaGpu !== undefined ||
568
+ options.embeddingParallelism ||
569
+ options.apiKey ||
570
+ options.endpoint ||
571
+ options.globs?.length ||
572
+ options.insensitiveGlobs?.length ||
573
+ options.fileTypes?.length ||
574
+ options.excludedFileTypes?.length ||
575
+ options.hidden ||
576
+ options.noIgnore ||
577
+ options.ignoreFiles?.length ||
578
+ options.maxDepth !== undefined ||
579
+ options.maxFileSizeBytes !== undefined ||
580
+ options.follow ||
581
+ options.embeddingConcurrency)) {
582
+ throw new Error("zg index --drop cannot be combined with indexing options");
583
+ }
584
+ if (command === "query" && !options.rg) {
585
+ const queryCount = positionals.length +
586
+ (options.hybridQueries?.length ?? 0) +
587
+ (options.routes?.length ?? 0);
588
+ if (queryCount === 0) {
589
+ throw new Error("zg query requires a query or --hybrid/--fts/--vector route");
590
+ }
591
+ }
592
+ }
593
+ function firstEnabledOption(candidates) {
594
+ return candidates.find(([value]) => Array.isArray(value) ? value.length > 0 : value !== undefined)?.[1];
355
595
  }
356
596
  function readOptionValue(args, index, option) {
357
597
  const value = args[index];
@@ -380,9 +620,7 @@ function isManagedRgOutputOption(arg) {
380
620
  return MANAGED_RG_OUTPUT_OPTIONS.has(option);
381
621
  }
382
622
  function isShortRgOptionGroup(arg) {
383
- return /^-[A-Za-z].*$/.test(arg)
384
- && arg !== "-h"
385
- && arg !== "-v";
623
+ return /^-[A-Za-z].*$/.test(arg) && arg !== "-h";
386
624
  }
387
625
  function parseShortRgOptionGroup(args, index, options) {
388
626
  const arg = args[index];
@@ -395,35 +633,32 @@ function parseShortRgOptionGroup(args, index, options) {
395
633
  markRgCompatibilityOption(options, flag);
396
634
  break;
397
635
  case "F":
398
- options.rgOptions = {
399
- ...(options.rgOptions ?? {}),
400
- fixedStrings: true,
401
- };
636
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [flag]);
402
637
  markRgCompatibilityOption(options, flag);
403
638
  break;
404
639
  case "i":
405
- options.rgOptions = {
406
- ...(options.rgOptions ?? {}),
407
- ignoreCase: true,
408
- };
640
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [flag]);
409
641
  markRgCompatibilityOption(options, flag);
410
642
  break;
411
643
  case "w":
412
- options.rgOptions = {
413
- ...(options.rgOptions ?? {}),
414
- wordRegexp: true,
415
- };
644
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [flag]);
416
645
  markRgCompatibilityOption(options, flag);
417
646
  break;
418
647
  case "P":
419
648
  case "S":
420
649
  case "s":
650
+ case "a":
421
651
  case "u":
422
652
  case "U":
653
+ case "v":
654
+ case "x":
423
655
  case "z":
424
656
  options.rgOptions = appendRgExtraArgs(options.rgOptions, [flag]);
425
657
  markRgCompatibilityOption(options, flag);
426
658
  break;
659
+ case "L":
660
+ options.follow = true;
661
+ break;
427
662
  case "e": {
428
663
  const value = readShortOptionValue(args, index, offset, arg, flag);
429
664
  options.rgOptions = appendRgPattern(options.rgOptions, value.value);
@@ -432,15 +667,52 @@ function parseShortRgOptionGroup(args, index, options) {
432
667
  }
433
668
  case "g": {
434
669
  const value = readShortOptionValue(args, index, offset, arg, flag);
435
- appendRgGlobFilter(options, value.value);
670
+ options.globs = appendValue(options.globs, value.value, flag);
671
+ return value.nextIndex;
672
+ }
673
+ case "E": {
674
+ const value = readShortOptionValue(args, index, offset, arg, flag);
675
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [
676
+ flag,
677
+ value.value,
678
+ ]);
436
679
  markRgCompatibilityOption(options, flag);
437
680
  return value.nextIndex;
438
681
  }
439
682
  case "t":
440
- case "T":
441
- case "E": {
683
+ case "T": {
684
+ const value = readShortOptionValue(args, index, offset, arg, flag);
685
+ if (option === "t") {
686
+ options.fileTypes = appendValue(options.fileTypes, value.value, flag);
687
+ }
688
+ else {
689
+ options.excludedFileTypes = appendValue(options.excludedFileTypes, value.value, flag);
690
+ }
691
+ return value.nextIndex;
692
+ }
693
+ case "f": {
694
+ const value = readShortOptionValue(args, index, offset, arg, flag);
695
+ options.rgOptions = appendRgPatternFile(options.rgOptions, value.value, flag);
696
+ markRgCompatibilityOption(options, flag);
697
+ return value.nextIndex;
698
+ }
699
+ case "m": {
442
700
  const value = readShortOptionValue(args, index, offset, arg, flag);
443
- options.rgOptions = appendRgExtraArgs(options.rgOptions, [flag, value.value]);
701
+ parseNonNegativeInteger(value.value, flag);
702
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [
703
+ flag,
704
+ value.value,
705
+ ]);
706
+ markRgCompatibilityOption(options, flag);
707
+ return value.nextIndex;
708
+ }
709
+ case "j": {
710
+ const value = readShortOptionValue(args, index, offset, arg, flag);
711
+ parseNonNegativeInteger(value.value, flag);
712
+ options.rgOptions = appendRgExtraArgs(options.rgOptions, [
713
+ flag,
714
+ value.value,
715
+ ]);
444
716
  markRgCompatibilityOption(options, flag);
445
717
  return value.nextIndex;
446
718
  }
@@ -448,11 +720,7 @@ function parseShortRgOptionGroup(args, index, options) {
448
720
  case "B":
449
721
  case "C": {
450
722
  const value = readShortOptionValue(args, index, offset, arg, flag);
451
- const direction = option === "A"
452
- ? "after"
453
- : option === "B"
454
- ? "before"
455
- : "both";
723
+ const direction = option === "A" ? "after" : option === "B" ? "before" : "both";
456
724
  options.rgOptions = setRgContext(options.rgOptions, direction, value.value, flag);
457
725
  markRgCompatibilityOption(options, flag);
458
726
  return value.nextIndex;
@@ -488,12 +756,25 @@ function markRgCompatibilityOption(options, option) {
488
756
  function appendRgPattern(existing, value) {
489
757
  return {
490
758
  ...(existing ?? {}),
491
- patterns: [
492
- ...(existing?.patterns ?? []),
493
- value,
494
- ],
759
+ patterns: [...(existing?.patterns ?? []), value],
760
+ };
761
+ }
762
+ function appendRgPatternFile(existing, value, option) {
763
+ return {
764
+ ...(existing ?? {}),
765
+ patternFiles: appendValue(existing?.patternFiles, value, option),
495
766
  };
496
767
  }
768
+ function appendInstallTargets(existing, value) {
769
+ const targets = value
770
+ .split(/[,\s]+/)
771
+ .map((target) => target.trim())
772
+ .filter((target) => target.length > 0);
773
+ if (targets.length === 0) {
774
+ throw new Error("--target requires at least one agent name");
775
+ }
776
+ return [...(existing ?? []), ...targets];
777
+ }
497
778
  function setRgContext(existing, direction, value, option) {
498
779
  const parsed = parseNonNegativeInteger(value, option);
499
780
  return {
@@ -509,47 +790,47 @@ function setRgContext(existing, direction, value, option) {
509
790
  function appendRgExtraArgs(existing, args) {
510
791
  return {
511
792
  ...(existing ?? {}),
512
- extraArgs: [
513
- ...(existing?.extraArgs ?? []),
514
- ...args,
515
- ],
793
+ extraArgs: [...(existing?.extraArgs ?? []), ...args],
516
794
  };
517
795
  }
518
- function appendRgGlobFilter(options, value) {
519
- if (value.startsWith("!")) {
520
- options.excludePaths = appendPathFilters(options.excludePaths, value.slice(1));
521
- return;
522
- }
523
- options.includePaths = appendPathFilters(options.includePaths, value);
524
- }
525
- function readRouteOptionValues(args, index, option) {
526
- const values = [];
527
- let nextIndex = index;
528
- while (nextIndex < args.length) {
529
- const value = args[nextIndex];
530
- if (value.startsWith("-") && value !== "-") {
531
- break;
532
- }
533
- if (value.trim().length > 0) {
534
- values.push(value);
535
- }
536
- nextIndex++;
537
- }
538
- if (values.length === 0) {
539
- throw new Error(`${option} requires at least one query`);
540
- }
541
- return { values, nextIndex };
542
- }
543
796
  function parsePositiveInteger(value, option) {
544
- const parsed = Number.parseInt(value, 10);
545
- if (!Number.isInteger(parsed) || parsed < 1) {
797
+ if (!/^\d+$/.test(value)) {
798
+ throw new Error(`${option} requires a positive integer`);
799
+ }
800
+ const parsed = Number(value);
801
+ if (!Number.isSafeInteger(parsed) || parsed < 1) {
546
802
  throw new Error(`${option} requires a positive integer`);
547
803
  }
548
804
  return parsed;
549
805
  }
806
+ function parseByteSize(value, option) {
807
+ const match = value.trim().match(/^(\d+)([KMGT])?$/i);
808
+ if (!match) {
809
+ throw new Error(`${option} requires bytes or an integer K/M/G/T size`);
810
+ }
811
+ const amount = Number.parseInt(match[1], 10);
812
+ const suffix = match[2]?.toUpperCase();
813
+ const multiplier = suffix === "K"
814
+ ? 1024
815
+ : suffix === "M"
816
+ ? 1024 ** 2
817
+ : suffix === "G"
818
+ ? 1024 ** 3
819
+ : suffix === "T"
820
+ ? 1024 ** 4
821
+ : 1;
822
+ const bytes = amount * multiplier;
823
+ if (!Number.isSafeInteger(bytes)) {
824
+ throw new Error(`${option} is too large`);
825
+ }
826
+ return bytes;
827
+ }
550
828
  function parseNonNegativeInteger(value, option) {
551
- const parsed = Number.parseInt(value, 10);
552
- if (!Number.isInteger(parsed) || parsed < 0) {
829
+ if (!/^\d+$/.test(value)) {
830
+ throw new Error(`${option} requires a non-negative integer`);
831
+ }
832
+ const parsed = Number(value);
833
+ if (!Number.isSafeInteger(parsed)) {
553
834
  throw new Error(`${option} requires a non-negative integer`);
554
835
  }
555
836
  return parsed;
@@ -566,9 +847,12 @@ function parsePreviewMode(value) {
566
847
  }
567
848
  throw new Error(`Unsupported preview mode: ${value}`);
568
849
  }
569
- function parseLlamaGpu(value) {
850
+ export function parseLlamaGpu(value) {
570
851
  const normalized = value.trim().toLowerCase();
571
- if (normalized === "auto" || normalized === "metal" || normalized === "vulkan" || normalized === "cuda") {
852
+ if (normalized === "auto" ||
853
+ normalized === "metal" ||
854
+ normalized === "vulkan" ||
855
+ normalized === "cuda") {
572
856
  return normalized;
573
857
  }
574
858
  if (["false", "off", "none", "disable", "disabled", "0"].includes(normalized)) {
@@ -579,11 +863,19 @@ function parseLlamaGpu(value) {
579
863
  function hasExplicitRoutes(options) {
580
864
  return (options.routes?.length ?? 0) > 0;
581
865
  }
582
- function appendRoutes(existing, mode, queries) {
583
- return [
584
- ...(existing ?? []),
585
- ...queries.map((query) => ({ mode, query })),
586
- ];
866
+ function appendRoute(existing, mode, query, option) {
867
+ const normalized = query.trim();
868
+ if (!normalized) {
869
+ throw new Error(`${option} requires a non-empty query`);
870
+ }
871
+ return [...(existing ?? []), { mode, query: normalized }];
872
+ }
873
+ function appendQuery(existing, query, option) {
874
+ const normalized = query.trim();
875
+ if (!normalized) {
876
+ throw new Error(`${option} requires a non-empty query`);
877
+ }
878
+ return [...(existing ?? []), normalized];
587
879
  }
588
880
  function parseSymbolType(value) {
589
881
  if (VALID_SYMBOL_TYPES.has(value)) {
@@ -591,14 +883,20 @@ function parseSymbolType(value) {
591
883
  }
592
884
  throw new Error(`Unsupported symbol type: ${value}`);
593
885
  }
594
- function appendPathFilters(existing, value) {
595
- const values = value
886
+ export function splitPathFilters(value) {
887
+ return value
596
888
  .split(",")
597
889
  .map((item) => item.trim())
598
890
  .filter((item) => item.length > 0);
599
- return [...(existing ?? []), ...values];
600
891
  }
601
- function parseModifiedTime(value, option) {
892
+ function appendValue(existing, value, option) {
893
+ const normalized = value.trim();
894
+ if (!normalized) {
895
+ throw new Error(`${option} requires a non-empty value`);
896
+ }
897
+ return [...(existing ?? []), normalized];
898
+ }
899
+ export function parseModifiedTime(value, option) {
602
900
  if (/^\d+$/.test(value)) {
603
901
  const parsed = Number.parseInt(value, 10);
604
902
  if (Number.isSafeInteger(parsed) && parsed >= 0) {
@@ -611,9 +909,9 @@ function parseModifiedTime(value, option) {
611
909
  const month = Number.parseInt(dateOnly[2], 10);
612
910
  const day = Number.parseInt(dateOnly[3], 10);
613
911
  const date = new Date(year, month - 1, day);
614
- if (date.getFullYear() === year
615
- && date.getMonth() === month - 1
616
- && date.getDate() === day) {
912
+ if (date.getFullYear() === year &&
913
+ date.getMonth() === month - 1 &&
914
+ date.getDate() === day) {
617
915
  return date.getTime();
618
916
  }
619
917
  }