@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.
- package/README.md +127 -42
- package/README_CN.md +124 -42
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.js +490 -192
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands.d.ts +3 -1
- package/dist/cli/commands.js +590 -56
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/errors.js +6 -5
- package/dist/cli/errors.js.map +1 -1
- package/dist/cli/format/context.js +33 -29
- package/dist/cli/format/context.js.map +1 -1
- package/dist/cli/format/debug.js +12 -14
- package/dist/cli/format/debug.js.map +1 -1
- package/dist/cli/format/highlight.js.map +1 -1
- package/dist/cli/format/progress.js +8 -3
- package/dist/cli/format/progress.js.map +1 -1
- package/dist/cli/format/range.js.map +1 -1
- package/dist/cli/format/status.js +59 -26
- package/dist/cli/format/status.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +170 -85
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/index.js +4 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +2 -0
- package/dist/cli/mcp.js +354 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/types.d.ts +22 -9
- package/dist/cli/types.js.map +1 -1
- package/dist/cli/version.js +3 -1
- package/dist/cli/version.js.map +1 -1
- package/dist/engine/collection/index.js +15 -15
- package/dist/engine/collection/index.js.map +1 -1
- package/dist/engine/config.d.ts +28 -0
- package/dist/engine/config.js +195 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/errors/details.js.map +1 -1
- package/dist/engine/errors/index.js.map +1 -1
- package/dist/engine/extraction/code/adapter.js.map +1 -1
- package/dist/engine/extraction/code/extractor.js +87 -73
- package/dist/engine/extraction/code/extractor.js.map +1 -1
- package/dist/engine/extraction/code/families/c-family.js +12 -6
- package/dist/engine/extraction/code/families/c-family.js.map +1 -1
- package/dist/engine/extraction/code/families/js-ts.js +24 -18
- package/dist/engine/extraction/code/families/js-ts.js.map +1 -1
- package/dist/engine/extraction/code/families/metadata.js +11 -8
- package/dist/engine/extraction/code/families/metadata.js.map +1 -1
- package/dist/engine/extraction/code/families/name-field.js +5 -5
- package/dist/engine/extraction/code/families/name-field.js.map +1 -1
- package/dist/engine/extraction/code/languages/c.js +1 -4
- package/dist/engine/extraction/code/languages/c.js.map +1 -1
- package/dist/engine/extraction/code/languages/cpp.js.map +1 -1
- package/dist/engine/extraction/code/languages/go.js +1 -3
- package/dist/engine/extraction/code/languages/go.js.map +1 -1
- package/dist/engine/extraction/code/languages/java.js.map +1 -1
- package/dist/engine/extraction/code/languages/javascript.js +1 -3
- package/dist/engine/extraction/code/languages/javascript.js.map +1 -1
- package/dist/engine/extraction/code/languages/python.js +5 -6
- package/dist/engine/extraction/code/languages/python.js.map +1 -1
- package/dist/engine/extraction/code/languages/rust.js +1 -5
- package/dist/engine/extraction/code/languages/rust.js.map +1 -1
- package/dist/engine/extraction/code/languages/typescript.js.map +1 -1
- package/dist/engine/extraction/ids.js.map +1 -1
- package/dist/engine/extraction/index.js +3 -3
- package/dist/engine/extraction/index.js.map +1 -1
- package/dist/engine/extraction/markdown/extractor.js +4 -2
- package/dist/engine/extraction/markdown/extractor.js.map +1 -1
- package/dist/engine/extraction/tree-sitter/grammar.js.map +1 -1
- package/dist/engine/extraction/tree-sitter/nodes.js +2 -1
- package/dist/engine/extraction/tree-sitter/nodes.js.map +1 -1
- package/dist/engine/extraction/tree-sitter/parser.js.map +1 -1
- package/dist/engine/files/file-type.js.map +1 -1
- package/dist/engine/models/catalog.js +7 -23
- package/dist/engine/models/catalog.js.map +1 -1
- package/dist/engine/models/embeddings.js +3 -3
- package/dist/engine/models/embeddings.js.map +1 -1
- package/dist/engine/models/factory.js.map +1 -1
- package/dist/engine/models/index.d.ts +1 -1
- package/dist/engine/models/index.js.map +1 -1
- package/dist/engine/models/providers/index.d.ts +1 -1
- package/dist/engine/models/providers/index.js +1 -1
- package/dist/engine/models/providers/index.js.map +1 -1
- package/dist/engine/models/providers/llama-cpp/embedding.js +49 -18
- package/dist/engine/models/providers/llama-cpp/embedding.js.map +1 -1
- package/dist/engine/models/providers/qwen/embedding.js +16 -11
- package/dist/engine/models/providers/qwen/embedding.js.map +1 -1
- package/dist/engine/models/providers/qwen/index.d.ts +1 -1
- package/dist/engine/models/providers/qwen/index.js +1 -1
- package/dist/engine/models/providers/qwen/index.js.map +1 -1
- package/dist/engine/pipeline/indexing/index.js +46 -33
- package/dist/engine/pipeline/indexing/index.js.map +1 -1
- package/dist/engine/pipeline/indexing/root-paths.js +10 -13
- package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
- package/dist/engine/pipeline/indexing/scanner/index.js +91 -43
- package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
- package/dist/engine/pipeline/search/index.js +68 -24
- package/dist/engine/pipeline/search/index.js.map +1 -1
- package/dist/engine/service/index.d.ts +1 -1
- package/dist/engine/service/lexical.d.ts +14 -15
- package/dist/engine/service/lexical.js +78 -119
- package/dist/engine/service/lexical.js.map +1 -1
- package/dist/engine/service/root.js +2 -2
- package/dist/engine/service/root.js.map +1 -1
- package/dist/engine/service/structure-enrichment.js +17 -11
- package/dist/engine/service/structure-enrichment.js.map +1 -1
- package/dist/engine/service/types.d.ts +39 -8
- package/dist/engine/service/zvec-grep.js +303 -160
- package/dist/engine/service/zvec-grep.js.map +1 -1
- package/dist/engine/storage/index.js.map +1 -1
- package/dist/engine/storage/zvec.js +15 -11
- package/dist/engine/storage/zvec.js.map +1 -1
- package/dist/engine/types.d.ts +14 -0
- package/dist/engine/types.js.map +1 -1
- package/dist/engine/utils/file-selection.d.ts +10 -0
- package/dist/engine/utils/file-selection.js +120 -0
- package/dist/engine/utils/file-selection.js.map +1 -0
- package/dist/engine/utils/glob.d.ts +3 -0
- package/dist/engine/utils/glob.js +116 -18
- package/dist/engine/utils/glob.js.map +1 -1
- package/dist/engine/utils/hash.js.map +1 -1
- package/dist/engine/utils/json.d.ts +6 -2
- package/dist/engine/utils/json.js +50 -12
- package/dist/engine/utils/json.js.map +1 -1
- package/dist/engine/utils/lock.js +6 -6
- package/dist/engine/utils/lock.js.map +1 -1
- package/dist/engine/utils/path.js +2 -2
- package/dist/engine/utils/path.js.map +1 -1
- package/dist/engine/utils/timing.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +34 -7
- package/skills/zvec-grep/SKILL.md +58 -48
- package/skills/zvec-grep/agents/openai.yaml +1 -1
package/dist/cli/commands.js
CHANGED
|
@@ -1,35 +1,219 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { chmod, lstat, mkdir, open, readFile, readlink, rename, stat, unlink, } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { createInterface } from "node:readline/promises";
|
|
2
6
|
import { createZvecGrep, } from "../index.js";
|
|
7
|
+
import { globalConfigPath, updateGlobalConfigFromExplicitOptions, } from "../engine/config.js";
|
|
3
8
|
import { findNearestAnonymousWorkspace } from "../engine/service/root.js";
|
|
4
|
-
import { contextWarningLines, printAgentContextResult, printHumanContextResult } from "./format/context.js";
|
|
9
|
+
import { contextWarningLines, printAgentContextResult, printHumanContextResult, } from "./format/context.js";
|
|
5
10
|
import { printDebug } from "./format/debug.js";
|
|
6
11
|
import { createIndexProgressReporter } from "./format/progress.js";
|
|
7
12
|
import { printAnonymousInfo, printCollectionInfo, printCollectionList, printCollectionRemoveResult, printIndexPathFilterTip, printIndexResult, } from "./format/status.js";
|
|
13
|
+
const AGENT_INSTALLERS = [
|
|
14
|
+
{
|
|
15
|
+
id: "codex",
|
|
16
|
+
label: "Codex",
|
|
17
|
+
description: "configure zvec-grep MCP and Codex guidance",
|
|
18
|
+
install: installCodexIntegration,
|
|
19
|
+
uninstall: uninstallCodexIntegration,
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
const ZVEC_GREP_CONFIG_START = "# ZVEC_GREP_START";
|
|
23
|
+
const ZVEC_GREP_CONFIG_END = "# ZVEC_GREP_END";
|
|
24
|
+
const ZVEC_GREP_AGENTS_START = "<!-- ZVEC_GREP_START -->";
|
|
25
|
+
const ZVEC_GREP_AGENTS_END = "<!-- ZVEC_GREP_END -->";
|
|
26
|
+
const DEFAULT_MCP_TOOL_TIMEOUT_SECONDS = 600;
|
|
8
27
|
export async function runParsedCommand(parsed) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
28
|
+
switch (parsed.command) {
|
|
29
|
+
case "query":
|
|
30
|
+
await runQuery(parsed);
|
|
31
|
+
return;
|
|
32
|
+
case "index":
|
|
33
|
+
await runIndex(parsed);
|
|
34
|
+
return;
|
|
35
|
+
case "status":
|
|
36
|
+
await runStatus(parsed);
|
|
37
|
+
return;
|
|
38
|
+
case "collections":
|
|
39
|
+
await runCollections(parsed);
|
|
40
|
+
return;
|
|
41
|
+
case "install":
|
|
42
|
+
await runInstall(parsed);
|
|
43
|
+
return;
|
|
44
|
+
case "uninstall":
|
|
45
|
+
await runUninstall(parsed);
|
|
46
|
+
return;
|
|
47
|
+
case "serve":
|
|
48
|
+
await runServe(parsed);
|
|
49
|
+
return;
|
|
50
|
+
case "help":
|
|
51
|
+
case "version":
|
|
52
|
+
throw new Error(`${parsed.command} must be handled before dispatch`);
|
|
12
53
|
}
|
|
13
|
-
|
|
14
|
-
|
|
54
|
+
}
|
|
55
|
+
async function runInstall(parsed) {
|
|
56
|
+
const installers = await resolveInstallers(parsed, "install");
|
|
57
|
+
if (installers.length === 0) {
|
|
58
|
+
console.log("No agents selected.");
|
|
15
59
|
return;
|
|
16
60
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
61
|
+
console.log(`Installing zvec-grep for: ${installers.map((installer) => installer.label).join(", ")}`);
|
|
62
|
+
for (const installer of installers) {
|
|
63
|
+
const result = await installer.install({
|
|
64
|
+
force: parsed.options.force === true,
|
|
65
|
+
mcpToolTimeoutSeconds: parsed.options.installMcpToolTimeoutSeconds ??
|
|
66
|
+
DEFAULT_MCP_TOOL_TIMEOUT_SECONDS,
|
|
67
|
+
});
|
|
68
|
+
console.log(`Installed ${installer.label}:`);
|
|
69
|
+
for (const file of result.files) {
|
|
70
|
+
console.log(` ${file}`);
|
|
71
|
+
}
|
|
20
72
|
}
|
|
21
|
-
|
|
22
|
-
|
|
73
|
+
console.log("Restart the selected agent or start a new session to pick up the integration.");
|
|
74
|
+
if (installers.some((installer) => installer.id === "codex")) {
|
|
75
|
+
console.log("Codex MCP server: zg serve --mcp");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function runUninstall(parsed) {
|
|
79
|
+
const installers = await resolveInstallers(parsed, "uninstall");
|
|
80
|
+
if (installers.length === 0) {
|
|
81
|
+
console.log("No agents selected.");
|
|
23
82
|
return;
|
|
24
83
|
}
|
|
25
|
-
|
|
84
|
+
console.log(`Removing zvec-grep from: ${installers.map((installer) => installer.label).join(", ")}`);
|
|
85
|
+
for (const installer of installers) {
|
|
86
|
+
const result = await installer.uninstall();
|
|
87
|
+
console.log(`Removed ${installer.label} integration:`);
|
|
88
|
+
for (const file of result.files) {
|
|
89
|
+
console.log(` ${file}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
console.log("Restart the selected agent or start a new session to apply the change.");
|
|
93
|
+
}
|
|
94
|
+
async function installCodexIntegration(options) {
|
|
95
|
+
const codexHome = resolveCodexHome();
|
|
96
|
+
const configPath = resolve(codexHome, "config.toml");
|
|
97
|
+
const agentsPath = resolve(codexHome, "AGENTS.md");
|
|
98
|
+
await writeMarkedFile({
|
|
99
|
+
path: configPath,
|
|
100
|
+
startMarker: ZVEC_GREP_CONFIG_START,
|
|
101
|
+
endMarker: ZVEC_GREP_CONFIG_END,
|
|
102
|
+
block: codexConfigBlock(options.mcpToolTimeoutSeconds),
|
|
103
|
+
force: options.force,
|
|
104
|
+
hasConflict: hasCodexMcpServerConfig,
|
|
105
|
+
conflictMessage: `Existing [mcp_servers.zvec_grep] found in ${configPath}. Re-run with --force after removing or moving that table into the zvec-grep managed block.`,
|
|
106
|
+
removeConflict: removeCodexMcpServerConfig,
|
|
107
|
+
});
|
|
108
|
+
await writeMarkedFile({
|
|
109
|
+
path: agentsPath,
|
|
110
|
+
startMarker: ZVEC_GREP_AGENTS_START,
|
|
111
|
+
endMarker: ZVEC_GREP_AGENTS_END,
|
|
112
|
+
block: codexAgentsBlock(),
|
|
113
|
+
force: true,
|
|
114
|
+
});
|
|
115
|
+
return { files: [configPath, agentsPath] };
|
|
116
|
+
}
|
|
117
|
+
async function uninstallCodexIntegration() {
|
|
118
|
+
const codexHome = resolveCodexHome();
|
|
119
|
+
const configPath = resolve(codexHome, "config.toml");
|
|
120
|
+
const agentsPath = resolve(codexHome, "AGENTS.md");
|
|
121
|
+
await removeMarkedFile({
|
|
122
|
+
path: configPath,
|
|
123
|
+
startMarker: ZVEC_GREP_CONFIG_START,
|
|
124
|
+
endMarker: ZVEC_GREP_CONFIG_END,
|
|
125
|
+
});
|
|
126
|
+
await removeMarkedFile({
|
|
127
|
+
path: agentsPath,
|
|
128
|
+
startMarker: ZVEC_GREP_AGENTS_START,
|
|
129
|
+
endMarker: ZVEC_GREP_AGENTS_END,
|
|
130
|
+
});
|
|
131
|
+
return { files: [configPath, agentsPath] };
|
|
132
|
+
}
|
|
133
|
+
async function resolveInstallers(parsed, action) {
|
|
134
|
+
const targetTokens = [
|
|
135
|
+
...(parsed.options.installTargets ?? []),
|
|
136
|
+
...parsed.positionals,
|
|
137
|
+
];
|
|
138
|
+
if (targetTokens.length > 0) {
|
|
139
|
+
return installersFromTokens(targetTokens);
|
|
140
|
+
}
|
|
141
|
+
if (parsed.options.yes === true ||
|
|
142
|
+
!process.stdin.isTTY ||
|
|
143
|
+
!process.stdout.isTTY) {
|
|
144
|
+
return installersFromTokens(["auto"]);
|
|
145
|
+
}
|
|
146
|
+
return promptInstallers(action);
|
|
147
|
+
}
|
|
148
|
+
async function promptInstallers(action) {
|
|
149
|
+
console.log(`Select agents whose zvec-grep integration should be ${action === "install" ? "installed" : "removed"}:`);
|
|
150
|
+
AGENT_INSTALLERS.forEach((installer, index) => {
|
|
151
|
+
console.log(` ${index + 1}. ${installer.label} - ${installer.description}`);
|
|
152
|
+
});
|
|
153
|
+
console.log(" all. All supported agents");
|
|
154
|
+
console.log(" none. Cancel");
|
|
155
|
+
const readline = createInterface({
|
|
156
|
+
input: process.stdin,
|
|
157
|
+
output: process.stdout,
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
const answer = await readline.question("Agents [codex]: ");
|
|
161
|
+
const normalized = answer.trim();
|
|
162
|
+
return installersFromTokens(normalized.length > 0 ? splitTargetTokens(normalized) : ["codex"]);
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
readline.close();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function installersFromTokens(tokens) {
|
|
169
|
+
const normalized = tokens.flatMap(splitTargetTokens);
|
|
170
|
+
if (normalized.length === 0) {
|
|
171
|
+
return installersFromTokens(["auto"]);
|
|
172
|
+
}
|
|
173
|
+
const selected = new Map();
|
|
174
|
+
for (const token of normalized) {
|
|
175
|
+
const lower = token.toLowerCase();
|
|
176
|
+
if (lower === "none") {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
if (lower === "auto" || lower === "all") {
|
|
180
|
+
for (const installer of AGENT_INSTALLERS) {
|
|
181
|
+
selected.set(installer.id, installer);
|
|
182
|
+
}
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const numbered = /^\d+$/.test(lower) ? Number(lower) : Number.NaN;
|
|
186
|
+
if (Number.isInteger(numbered) &&
|
|
187
|
+
numbered >= 1 &&
|
|
188
|
+
numbered <= AGENT_INSTALLERS.length) {
|
|
189
|
+
const installer = AGENT_INSTALLERS[numbered - 1];
|
|
190
|
+
selected.set(installer.id, installer);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const installer = AGENT_INSTALLERS.find((candidate) => candidate.id === lower || candidate.label.toLowerCase() === lower);
|
|
194
|
+
if (!installer) {
|
|
195
|
+
throw new Error(`Unknown install target: ${token}`);
|
|
196
|
+
}
|
|
197
|
+
selected.set(installer.id, installer);
|
|
198
|
+
}
|
|
199
|
+
return [...selected.values()];
|
|
200
|
+
}
|
|
201
|
+
function splitTargetTokens(value) {
|
|
202
|
+
return value
|
|
203
|
+
.split(/[,\s]+/)
|
|
204
|
+
.map((target) => target.trim())
|
|
205
|
+
.filter((target) => target.length > 0);
|
|
26
206
|
}
|
|
27
207
|
async function runIndex(parsed) {
|
|
28
208
|
const explicitRoot = parsed.positionals.length > 0;
|
|
29
209
|
const root = resolveIndexRoot(parsed.positionals[0]);
|
|
30
210
|
const rootPath = indexRootPath(root, parsed.options);
|
|
31
211
|
if (parsed.positionals.length > 1) {
|
|
32
|
-
throw new Error("zg
|
|
212
|
+
throw new Error("zg index accepts at most one root path");
|
|
213
|
+
}
|
|
214
|
+
if (parsed.options.drop) {
|
|
215
|
+
await runDropIndex(parsed, rootPath.absolutePath);
|
|
216
|
+
return;
|
|
33
217
|
}
|
|
34
218
|
const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, rootPath.absolutePath));
|
|
35
219
|
const progress = createIndexProgressReporter();
|
|
@@ -40,14 +224,23 @@ async function runIndex(parsed) {
|
|
|
40
224
|
rootPaths: explicitRoot ? [rootPath] : undefined,
|
|
41
225
|
rebuild: parsed.options.rebuild,
|
|
42
226
|
resetPaths: parsed.options.resetPaths,
|
|
43
|
-
|
|
44
|
-
|
|
227
|
+
globs: parsed.options.globs,
|
|
228
|
+
insensitiveGlobs: parsed.options.insensitiveGlobs,
|
|
229
|
+
fileTypes: parsed.options.fileTypes,
|
|
230
|
+
excludedFileTypes: parsed.options.excludedFileTypes,
|
|
231
|
+
hidden: parsed.options.hidden,
|
|
232
|
+
noIgnore: parsed.options.noIgnore,
|
|
233
|
+
ignoreFiles: parsed.options.ignoreFiles,
|
|
234
|
+
maxDepth: parsed.options.maxDepth,
|
|
235
|
+
maxFileSizeBytes: parsed.options.maxFileSizeBytes,
|
|
236
|
+
follow: parsed.options.follow,
|
|
45
237
|
embeddingConcurrency: parsed.options.embeddingConcurrency,
|
|
46
238
|
onProgress: progress.report,
|
|
47
239
|
});
|
|
48
240
|
progress.finish();
|
|
49
241
|
const info = await zvecGrep.info({ root: rootPath.absolutePath });
|
|
50
242
|
printIndexResult("Indexed anonymous workspace", result, parsed.options, info.collection?.rootPaths);
|
|
243
|
+
persistExplicitGlobalConfig(parsed.options, info.collection?.embedding?.provider);
|
|
51
244
|
}
|
|
52
245
|
catch (error) {
|
|
53
246
|
progress.finish();
|
|
@@ -57,24 +250,50 @@ async function runIndex(parsed) {
|
|
|
57
250
|
await zvecGrep.close();
|
|
58
251
|
}
|
|
59
252
|
}
|
|
60
|
-
async function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
253
|
+
async function runDropIndex(parsed, root) {
|
|
254
|
+
if (!(await confirmIndexDrop(root, parsed.options.yes === true))) {
|
|
255
|
+
console.log("Index drop cancelled.");
|
|
256
|
+
return;
|
|
64
257
|
}
|
|
65
258
|
const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
|
|
66
259
|
try {
|
|
67
|
-
const
|
|
68
|
-
|
|
260
|
+
const removed = await zvecGrep.dropIndex({ root });
|
|
261
|
+
console.log(removed ? `Dropped index for ${root}` : `No index found for ${root}`);
|
|
69
262
|
}
|
|
70
263
|
finally {
|
|
71
264
|
await zvecGrep.close();
|
|
72
265
|
}
|
|
73
266
|
}
|
|
267
|
+
async function confirmIndexDrop(root, accepted) {
|
|
268
|
+
if (accepted) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
272
|
+
throw new Error("zg index --drop requires --yes in a non-interactive shell");
|
|
273
|
+
}
|
|
274
|
+
const readline = createInterface({
|
|
275
|
+
input: process.stdin,
|
|
276
|
+
output: process.stdout,
|
|
277
|
+
});
|
|
278
|
+
try {
|
|
279
|
+
const answer = await readline.question(`Drop the index for ${root}? [y/N] `);
|
|
280
|
+
return ["y", "yes"].includes(answer.trim().toLowerCase());
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
readline.close();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
async function runServe(parsed) {
|
|
287
|
+
if (parsed.positionals.length > 0) {
|
|
288
|
+
throw new Error("zg serve --mcp does not accept positional arguments");
|
|
289
|
+
}
|
|
290
|
+
const { runMcpServer } = await import("./mcp.js");
|
|
291
|
+
await runMcpServer(createServiceOptions(parsed.options, process.cwd()));
|
|
292
|
+
}
|
|
74
293
|
async function runStatus(parsed) {
|
|
75
294
|
const root = parsed.positionals[0] ?? process.cwd();
|
|
76
295
|
if (parsed.positionals.length > 1) {
|
|
77
|
-
throw new Error("zg
|
|
296
|
+
throw new Error("zg status accepts at most one root path");
|
|
78
297
|
}
|
|
79
298
|
const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
|
|
80
299
|
try {
|
|
@@ -87,21 +306,26 @@ async function runStatus(parsed) {
|
|
|
87
306
|
}
|
|
88
307
|
async function runCollections(parsed) {
|
|
89
308
|
const [action = "list", name, root] = parsed.positionals;
|
|
309
|
+
validateCollectionArguments(action, parsed.positionals);
|
|
310
|
+
const indexOption = collectionIndexOption(parsed.options);
|
|
311
|
+
if (action !== "index" && indexOption) {
|
|
312
|
+
throw new Error(`${indexOption} can only be used with zg collections index`);
|
|
313
|
+
}
|
|
90
314
|
const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, undefined));
|
|
91
315
|
try {
|
|
92
316
|
if (action === "list") {
|
|
93
317
|
if (parsed.options.resetPaths) {
|
|
94
|
-
throw new Error("--reset-paths can only be used with
|
|
318
|
+
throw new Error("--reset-paths can only be used with zg collections index");
|
|
95
319
|
}
|
|
96
320
|
printCollectionList(await zvecGrep.collections.list(), parsed.options);
|
|
97
321
|
return;
|
|
98
322
|
}
|
|
99
323
|
if (action === "info") {
|
|
100
324
|
if (parsed.options.resetPaths) {
|
|
101
|
-
throw new Error("--reset-paths can only be used with
|
|
325
|
+
throw new Error("--reset-paths can only be used with zg collections index");
|
|
102
326
|
}
|
|
103
327
|
if (!name) {
|
|
104
|
-
throw new Error("zg
|
|
328
|
+
throw new Error("zg collections info requires <name>");
|
|
105
329
|
}
|
|
106
330
|
const [info, status] = await Promise.all([
|
|
107
331
|
zvecGrep.collections.info(name),
|
|
@@ -115,7 +339,7 @@ async function runCollections(parsed) {
|
|
|
115
339
|
}
|
|
116
340
|
if (action === "index") {
|
|
117
341
|
if (!name) {
|
|
118
|
-
throw new Error("zg
|
|
342
|
+
throw new Error("zg collections index requires <name>");
|
|
119
343
|
}
|
|
120
344
|
const explicitRoot = root !== undefined;
|
|
121
345
|
const rootPath = indexRootPath(root ?? process.cwd(), parsed.options);
|
|
@@ -125,14 +349,23 @@ async function runCollections(parsed) {
|
|
|
125
349
|
const result = await zvecGrep.collections.index(name, rootPaths, {
|
|
126
350
|
rebuild: parsed.options.rebuild,
|
|
127
351
|
resetPaths: parsed.options.resetPaths,
|
|
128
|
-
|
|
129
|
-
|
|
352
|
+
globs: parsed.options.globs,
|
|
353
|
+
insensitiveGlobs: parsed.options.insensitiveGlobs,
|
|
354
|
+
fileTypes: parsed.options.fileTypes,
|
|
355
|
+
excludedFileTypes: parsed.options.excludedFileTypes,
|
|
356
|
+
hidden: parsed.options.hidden,
|
|
357
|
+
noIgnore: parsed.options.noIgnore,
|
|
358
|
+
ignoreFiles: parsed.options.ignoreFiles,
|
|
359
|
+
maxDepth: parsed.options.maxDepth,
|
|
360
|
+
maxFileSizeBytes: parsed.options.maxFileSizeBytes,
|
|
361
|
+
follow: parsed.options.follow,
|
|
130
362
|
embeddingConcurrency: parsed.options.embeddingConcurrency,
|
|
131
363
|
onProgress: progress.report,
|
|
132
364
|
});
|
|
133
365
|
progress.finish();
|
|
134
366
|
const info = await zvecGrep.collections.info(name);
|
|
135
367
|
printIndexResult(`Indexed collection ${name}`, result, parsed.options, info?.rootPaths);
|
|
368
|
+
persistExplicitGlobalConfig(parsed.options, info?.embedding?.provider);
|
|
136
369
|
}
|
|
137
370
|
catch (error) {
|
|
138
371
|
progress.finish();
|
|
@@ -142,17 +375,17 @@ async function runCollections(parsed) {
|
|
|
142
375
|
}
|
|
143
376
|
if (action === "remove") {
|
|
144
377
|
if (parsed.options.resetPaths) {
|
|
145
|
-
throw new Error("--reset-paths can only be used with
|
|
378
|
+
throw new Error("--reset-paths can only be used with zg collections index");
|
|
146
379
|
}
|
|
147
380
|
if (!name) {
|
|
148
|
-
throw new Error("zg
|
|
381
|
+
throw new Error("zg collections remove requires <name>");
|
|
149
382
|
}
|
|
150
383
|
const removed = await zvecGrep.collections.remove(name);
|
|
151
384
|
printCollectionRemoveResult(name, removed, parsed.options);
|
|
152
385
|
return;
|
|
153
386
|
}
|
|
154
387
|
if (parsed.options.resetPaths) {
|
|
155
|
-
throw new Error("--reset-paths can only be used with
|
|
388
|
+
throw new Error("--reset-paths can only be used with zg collections index");
|
|
156
389
|
}
|
|
157
390
|
throw new Error(`Unknown collections action: ${action}`);
|
|
158
391
|
}
|
|
@@ -160,19 +393,67 @@ async function runCollections(parsed) {
|
|
|
160
393
|
await zvecGrep.close();
|
|
161
394
|
}
|
|
162
395
|
}
|
|
396
|
+
function validateCollectionArguments(action, positionals) {
|
|
397
|
+
if (action === "list") {
|
|
398
|
+
if (positionals.length > 1) {
|
|
399
|
+
throw new Error("zg collections list does not accept arguments");
|
|
400
|
+
}
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (action === "info" || action === "remove") {
|
|
404
|
+
if (positionals.length > 2) {
|
|
405
|
+
throw new Error(`zg collections ${action} accepts only <name>`);
|
|
406
|
+
}
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (action === "index") {
|
|
410
|
+
if (positionals.length > 3) {
|
|
411
|
+
throw new Error("zg collections index accepts only <name> and [root]");
|
|
412
|
+
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
throw new Error(`Unknown collections action: ${action}`);
|
|
416
|
+
}
|
|
417
|
+
function collectionIndexOption(options) {
|
|
418
|
+
const candidates = [
|
|
419
|
+
[options.rebuild, "--rebuild"],
|
|
420
|
+
[options.resetPaths, "--reset-paths"],
|
|
421
|
+
[options.embedding, "--embedding"],
|
|
422
|
+
[options.modelCacheDir, "--model-cache"],
|
|
423
|
+
[options.llamaGpu, "--llama-gpu"],
|
|
424
|
+
[options.embeddingParallelism, "--embedding-parallelism"],
|
|
425
|
+
[options.apiKey, "--api-key"],
|
|
426
|
+
[options.endpoint, "--endpoint"],
|
|
427
|
+
[options.embeddingConcurrency, "--embedding-concurrency"],
|
|
428
|
+
[options.globs?.length, "--glob"],
|
|
429
|
+
[options.insensitiveGlobs?.length, "--iglob"],
|
|
430
|
+
[options.fileTypes?.length, "--type"],
|
|
431
|
+
[options.excludedFileTypes?.length, "--type-not"],
|
|
432
|
+
[options.hidden, "--hidden"],
|
|
433
|
+
[options.noIgnore, "--no-ignore"],
|
|
434
|
+
[options.ignoreFiles?.length, "--ignore-file"],
|
|
435
|
+
[options.maxDepth, "--max-depth"],
|
|
436
|
+
[options.maxFileSizeBytes, "--max-filesize"],
|
|
437
|
+
[options.follow, "--follow"],
|
|
438
|
+
];
|
|
439
|
+
return candidates.find(([value]) => Array.isArray(value) ? value.length > 0 : value !== undefined)?.[1];
|
|
440
|
+
}
|
|
163
441
|
async function runQuery(parsed) {
|
|
164
|
-
const rgInput = parsed.options.rg
|
|
165
|
-
? normalizeRgInput(parsed)
|
|
166
|
-
: undefined;
|
|
442
|
+
const rgInput = parsed.options.rg ? normalizeRgInput(parsed) : undefined;
|
|
167
443
|
const commandOptions = rgInput?.options ?? parsed.options;
|
|
168
|
-
const queries = (rgInput?.queries ??
|
|
444
|
+
const queries = (rgInput?.queries ?? [
|
|
445
|
+
...parsed.positionals,
|
|
446
|
+
...(parsed.options.hybridQueries ?? []),
|
|
447
|
+
])
|
|
169
448
|
.map((query) => query.trim())
|
|
170
449
|
.filter((query) => query.length > 0);
|
|
171
450
|
const routes = parsed.options.routes ?? [];
|
|
172
|
-
if (queries.length === 0 &&
|
|
451
|
+
if (queries.length === 0 &&
|
|
452
|
+
routes.length === 0 &&
|
|
453
|
+
(parsed.options.rgOptions?.patternFiles?.length ?? 0) === 0) {
|
|
173
454
|
throw new Error(parsed.options.rg
|
|
174
|
-
? "zg --rg requires a pattern. Use
|
|
175
|
-
: "zg query requires text or --fts/--vector routes. Use
|
|
455
|
+
? "zg query --rg requires a pattern. Use zg help query for examples."
|
|
456
|
+
: "zg query requires text or --hybrid/--fts/--vector routes. Use zg help query for examples.");
|
|
176
457
|
}
|
|
177
458
|
const zvecGrep = await createZvecGrep(createServiceOptions(commandOptions, undefined));
|
|
178
459
|
const progress = createIndexProgressReporter();
|
|
@@ -213,15 +494,23 @@ function contextOptions(options, queries, onAutoUpdateProgress) {
|
|
|
213
494
|
rgOptions: options.rgOptions,
|
|
214
495
|
rgPaths: options.rgPaths,
|
|
215
496
|
routes: options.routes,
|
|
497
|
+
fuse: options.fuse,
|
|
216
498
|
collection: options.collection,
|
|
217
499
|
limit: options.limit,
|
|
218
|
-
fallback: "disabled",
|
|
219
500
|
autoUpdate: !options.noAutoUpdate,
|
|
220
501
|
onAutoUpdateProgress,
|
|
221
502
|
trace: options.trace,
|
|
222
503
|
preferSymbol: options.preferSymbol,
|
|
223
|
-
|
|
224
|
-
|
|
504
|
+
globs: options.globs,
|
|
505
|
+
insensitiveGlobs: options.insensitiveGlobs,
|
|
506
|
+
fileTypes: options.fileTypes,
|
|
507
|
+
excludedFileTypes: options.excludedFileTypes,
|
|
508
|
+
hidden: options.hidden,
|
|
509
|
+
noIgnore: options.noIgnore,
|
|
510
|
+
ignoreFiles: options.ignoreFiles,
|
|
511
|
+
maxDepth: options.maxDepth,
|
|
512
|
+
maxFileSizeBytes: options.maxFileSizeBytes,
|
|
513
|
+
follow: options.follow,
|
|
225
514
|
modifiedAfter: options.modifiedAfter,
|
|
226
515
|
modifiedBefore: options.modifiedBefore,
|
|
227
516
|
symbolTypes: options.symbolTypes,
|
|
@@ -230,10 +519,11 @@ function contextOptions(options, queries, onAutoUpdateProgress) {
|
|
|
230
519
|
}
|
|
231
520
|
function normalizeRgInput(parsed) {
|
|
232
521
|
const explicitPatterns = parsed.options.rgOptions?.patterns ?? [];
|
|
233
|
-
const
|
|
522
|
+
const hasPatternFiles = (parsed.options.rgOptions?.patternFiles?.length ?? 0) > 0;
|
|
523
|
+
const queries = explicitPatterns.length > 0 || hasPatternFiles
|
|
234
524
|
? explicitPatterns
|
|
235
525
|
: parsed.positionals.slice(0, 1);
|
|
236
|
-
const paths = explicitPatterns.length > 0
|
|
526
|
+
const paths = explicitPatterns.length > 0 || hasPatternFiles
|
|
237
527
|
? parsed.positionals
|
|
238
528
|
: parsed.positionals.slice(1);
|
|
239
529
|
return {
|
|
@@ -244,12 +534,12 @@ function normalizeRgInput(parsed) {
|
|
|
244
534
|
},
|
|
245
535
|
};
|
|
246
536
|
}
|
|
247
|
-
function createServiceOptions(options, root) {
|
|
537
|
+
export function createServiceOptions(options, root) {
|
|
248
538
|
const embedding = options.embedding ?? process.env.ZVEC_GREP_EMBEDDING;
|
|
249
|
-
const apiKey = options.apiKey
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
539
|
+
const apiKey = options.apiKey ??
|
|
540
|
+
process.env.ZVEC_GREP_API_KEY ??
|
|
541
|
+
process.env.DASHSCOPE_API_KEY ??
|
|
542
|
+
process.env.QWEN_API_KEY;
|
|
253
543
|
const endpoint = options.endpoint ?? process.env.ZVEC_GREP_ENDPOINT;
|
|
254
544
|
return {
|
|
255
545
|
root,
|
|
@@ -259,15 +549,25 @@ function createServiceOptions(options, root) {
|
|
|
259
549
|
endpoint,
|
|
260
550
|
modelCacheDir: options.modelCacheDir ?? process.env.ZVEC_GREP_MODEL_CACHE,
|
|
261
551
|
llamaGpu: options.llamaGpu ?? parseEnvLlamaGpu(process.env.ZVEC_GREP_LLAMA_GPU),
|
|
262
|
-
embeddingParallelism: options.embeddingParallelism ??
|
|
552
|
+
embeddingParallelism: options.embeddingParallelism ??
|
|
553
|
+
parseEnvPositiveInteger(process.env.ZVEC_GREP_EMBED_PARALLELISM),
|
|
263
554
|
};
|
|
264
555
|
}
|
|
556
|
+
function persistExplicitGlobalConfig(options, indexedProvider) {
|
|
557
|
+
if (!updateGlobalConfigFromExplicitOptions(options, indexedProvider)) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
console.log(`Global config: ${globalConfigPath()}`);
|
|
561
|
+
}
|
|
265
562
|
function parseEnvLlamaGpu(value) {
|
|
266
563
|
const normalized = value?.trim().toLowerCase() ?? "";
|
|
267
564
|
if (!normalized) {
|
|
268
565
|
return undefined;
|
|
269
566
|
}
|
|
270
|
-
if (normalized === "auto" ||
|
|
567
|
+
if (normalized === "auto" ||
|
|
568
|
+
normalized === "metal" ||
|
|
569
|
+
normalized === "vulkan" ||
|
|
570
|
+
normalized === "cuda") {
|
|
271
571
|
return normalized;
|
|
272
572
|
}
|
|
273
573
|
if (["false", "off", "none", "disable", "disabled", "0"].includes(normalized)) {
|
|
@@ -277,11 +577,237 @@ function parseEnvLlamaGpu(value) {
|
|
|
277
577
|
}
|
|
278
578
|
function parseEnvPositiveInteger(value) {
|
|
279
579
|
const normalized = value?.trim() ?? "";
|
|
280
|
-
if (
|
|
580
|
+
if (!/^\d+$/.test(normalized)) {
|
|
281
581
|
return undefined;
|
|
282
582
|
}
|
|
283
|
-
const parsed = Number
|
|
284
|
-
return Number.
|
|
583
|
+
const parsed = Number(normalized);
|
|
584
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
585
|
+
}
|
|
586
|
+
function resolveCodexHome() {
|
|
587
|
+
return resolve(process.env.CODEX_HOME ?? resolve(homedir(), ".codex"));
|
|
588
|
+
}
|
|
589
|
+
async function writeMarkedFile(options) {
|
|
590
|
+
let existing = await readTextFileIfExists(options.path);
|
|
591
|
+
const next = replaceMarkedBlock(existing, options.startMarker, options.endMarker, options.block);
|
|
592
|
+
if (next === null) {
|
|
593
|
+
existing = removeOrphanedMarkers(existing, options.startMarker, options.endMarker);
|
|
594
|
+
}
|
|
595
|
+
if (next === null && options.hasConflict?.(existing)) {
|
|
596
|
+
if (!options.force) {
|
|
597
|
+
throw new Error(options.conflictMessage ??
|
|
598
|
+
`Existing unmanaged configuration found in ${options.path}`);
|
|
599
|
+
}
|
|
600
|
+
existing = options.removeConflict
|
|
601
|
+
? options.removeConflict(existing)
|
|
602
|
+
: existing;
|
|
603
|
+
}
|
|
604
|
+
await writeTextFileAtomic(options.path, next ?? appendMarkedBlock(existing, options.block));
|
|
605
|
+
}
|
|
606
|
+
async function removeMarkedFile(options) {
|
|
607
|
+
const existing = await readTextFileIfExists(options.path);
|
|
608
|
+
if (!existing) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const next = replaceMarkedBlock(existing, options.startMarker, options.endMarker, "") ??
|
|
612
|
+
removeOrphanedMarkers(existing, options.startMarker, options.endMarker);
|
|
613
|
+
if (next === existing) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
await writeTextFileAtomic(options.path, next);
|
|
617
|
+
}
|
|
618
|
+
async function writeTextFileAtomic(path, content) {
|
|
619
|
+
const targetPath = await resolveAtomicWriteTarget(path);
|
|
620
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
621
|
+
const mode = await fileModeIfExists(targetPath);
|
|
622
|
+
const temporaryPath = `${targetPath}.${process.pid}.${randomUUID()}.tmp`;
|
|
623
|
+
let temporaryFile;
|
|
624
|
+
try {
|
|
625
|
+
temporaryFile = await open(temporaryPath, "wx", mode);
|
|
626
|
+
await temporaryFile.writeFile(content, "utf8");
|
|
627
|
+
await temporaryFile.sync();
|
|
628
|
+
await temporaryFile.close();
|
|
629
|
+
temporaryFile = undefined;
|
|
630
|
+
if (mode !== undefined) {
|
|
631
|
+
await chmod(temporaryPath, mode);
|
|
632
|
+
}
|
|
633
|
+
await rename(temporaryPath, targetPath);
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
await temporaryFile?.close().catch(() => undefined);
|
|
637
|
+
await unlink(temporaryPath).catch(() => undefined);
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
async function resolveAtomicWriteTarget(path, visited = new Set()) {
|
|
642
|
+
const absolutePath = resolve(path);
|
|
643
|
+
if (visited.has(absolutePath)) {
|
|
644
|
+
throw new Error(`Cannot atomically write through circular symbolic link: ${path}`);
|
|
645
|
+
}
|
|
646
|
+
try {
|
|
647
|
+
const file = await lstat(absolutePath);
|
|
648
|
+
if (!file.isSymbolicLink()) {
|
|
649
|
+
return absolutePath;
|
|
650
|
+
}
|
|
651
|
+
visited.add(absolutePath);
|
|
652
|
+
const link = await readlink(absolutePath);
|
|
653
|
+
return resolveAtomicWriteTarget(resolve(dirname(absolutePath), link), visited);
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
657
|
+
return absolutePath;
|
|
658
|
+
}
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
async function fileModeIfExists(path) {
|
|
663
|
+
try {
|
|
664
|
+
return (await stat(path)).mode & 0o777;
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
if (isNodeError(error) && error.code === "ENOENT") {
|
|
668
|
+
return undefined;
|
|
669
|
+
}
|
|
670
|
+
throw error;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
async function readTextFileIfExists(path) {
|
|
674
|
+
try {
|
|
675
|
+
return await readFile(path, "utf8");
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
679
|
+
return "";
|
|
680
|
+
}
|
|
681
|
+
throw error;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function isNodeError(error) {
|
|
685
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
686
|
+
}
|
|
687
|
+
function replaceMarkedBlock(existing, startMarker, endMarker, block) {
|
|
688
|
+
const lines = existing.split(/\r?\n/);
|
|
689
|
+
const markerLines = new Set();
|
|
690
|
+
const ranges = [];
|
|
691
|
+
let pendingStart;
|
|
692
|
+
for (const [index, line] of lines.entries()) {
|
|
693
|
+
const trimmed = line.trim();
|
|
694
|
+
if (trimmed === startMarker) {
|
|
695
|
+
markerLines.add(index);
|
|
696
|
+
pendingStart = index;
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
if (trimmed === endMarker) {
|
|
700
|
+
markerLines.add(index);
|
|
701
|
+
if (pendingStart !== undefined) {
|
|
702
|
+
ranges.push({ start: pendingStart, end: index });
|
|
703
|
+
pendingStart = undefined;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
const first = ranges[0];
|
|
708
|
+
if (!first) {
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
const before = retainedMarkedLines(lines, 0, first.start, markerLines, [])
|
|
712
|
+
.join("\n")
|
|
713
|
+
.trimEnd();
|
|
714
|
+
const after = retainedMarkedLines(lines, first.end + 1, lines.length, markerLines, ranges.slice(1))
|
|
715
|
+
.join("\n")
|
|
716
|
+
.trim();
|
|
717
|
+
return ([before, block.trim(), after.trim()]
|
|
718
|
+
.filter((part) => part.length > 0)
|
|
719
|
+
.join("\n\n") + "\n");
|
|
720
|
+
}
|
|
721
|
+
function retainedMarkedLines(lines, start, end, markerLines, removedRanges) {
|
|
722
|
+
const retained = [];
|
|
723
|
+
for (let index = start; index < end; index += 1) {
|
|
724
|
+
if (markerLines.has(index)) {
|
|
725
|
+
continue;
|
|
726
|
+
}
|
|
727
|
+
if (removedRanges.some((range) => index >= range.start && index <= range.end)) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
retained.push(lines[index]);
|
|
731
|
+
}
|
|
732
|
+
return retained;
|
|
733
|
+
}
|
|
734
|
+
function removeOrphanedMarkers(existing, startMarker, endMarker) {
|
|
735
|
+
return (existing
|
|
736
|
+
.split(/\r?\n/)
|
|
737
|
+
.filter((line) => {
|
|
738
|
+
const trimmed = line.trim();
|
|
739
|
+
return trimmed !== startMarker && trimmed !== endMarker;
|
|
740
|
+
})
|
|
741
|
+
.join("\n")
|
|
742
|
+
.trimEnd() + "\n");
|
|
743
|
+
}
|
|
744
|
+
function appendMarkedBlock(existing, block) {
|
|
745
|
+
const prefix = existing.trimEnd();
|
|
746
|
+
return `${prefix.length > 0 ? `${prefix}\n\n` : ""}${block.trim()}\n`;
|
|
747
|
+
}
|
|
748
|
+
function hasCodexMcpServerConfig(existing) {
|
|
749
|
+
return existing.split(/\r?\n/).some((line) => {
|
|
750
|
+
const tableName = tomlTableName(line);
|
|
751
|
+
return tableName !== undefined && isCodexMcpServerTableName(tableName);
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
function removeCodexMcpServerConfig(existing) {
|
|
755
|
+
const lines = existing.split(/\r?\n/);
|
|
756
|
+
const kept = [];
|
|
757
|
+
let skipping = false;
|
|
758
|
+
for (const line of lines) {
|
|
759
|
+
const tableName = tomlTableName(line);
|
|
760
|
+
if (tableName !== undefined) {
|
|
761
|
+
skipping = isCodexMcpServerTableName(tableName);
|
|
762
|
+
}
|
|
763
|
+
if (!skipping) {
|
|
764
|
+
kept.push(line);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return kept.join("\n").trimEnd() + "\n";
|
|
768
|
+
}
|
|
769
|
+
function tomlTableName(line) {
|
|
770
|
+
return line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/)?.[1]?.trim();
|
|
771
|
+
}
|
|
772
|
+
function isCodexMcpServerTableName(tableName) {
|
|
773
|
+
return /^(?:mcp_servers|"mcp_servers"|'mcp_servers')\s*\.\s*(?:zvec_grep|"zvec_grep"|'zvec_grep')(?:\s*\.|$)/.test(tableName);
|
|
774
|
+
}
|
|
775
|
+
function codexConfigBlock(mcpToolTimeoutSeconds) {
|
|
776
|
+
return `${ZVEC_GREP_CONFIG_START}
|
|
777
|
+
[mcp_servers.zvec_grep]
|
|
778
|
+
command = "zg"
|
|
779
|
+
args = ["serve", "--mcp"]
|
|
780
|
+
env_vars = [
|
|
781
|
+
"DASHSCOPE_API_KEY",
|
|
782
|
+
"QWEN_API_KEY",
|
|
783
|
+
"ZVEC_GREP_API_KEY",
|
|
784
|
+
"ZVEC_GREP_EMBEDDING",
|
|
785
|
+
"ZVEC_GREP_ENDPOINT",
|
|
786
|
+
"ZVEC_GREP_HOME",
|
|
787
|
+
"ZVEC_GREP_MODEL_CACHE",
|
|
788
|
+
"ZVEC_GREP_LLAMA_GPU",
|
|
789
|
+
"ZVEC_GREP_EMBED_PARALLELISM",
|
|
790
|
+
"NODE_LLAMA_CPP_CMAKE_OPTION_GGML_OPENMP",
|
|
791
|
+
"NODE_LLAMA_CPP_CMAKE_OPTION_GGML_NATIVE",
|
|
792
|
+
"NODE_LLAMA_CPP_CMAKE_OPTION_GGML_CPU_ARM_ARCH"
|
|
793
|
+
]
|
|
794
|
+
startup_timeout_sec = 20
|
|
795
|
+
tool_timeout_sec = ${mcpToolTimeoutSeconds}
|
|
796
|
+
default_tools_approval_mode = "auto"
|
|
797
|
+
${ZVEC_GREP_CONFIG_END}`;
|
|
798
|
+
}
|
|
799
|
+
function codexAgentsBlock() {
|
|
800
|
+
return `${ZVEC_GREP_AGENTS_START}
|
|
801
|
+
## zvec-grep
|
|
802
|
+
|
|
803
|
+
Use zvec-grep before grep, rg, or broad file reads when you need to understand or locate code.
|
|
804
|
+
|
|
805
|
+
- **MCP tools**: Use \`zvec_grep_search\` for indexed semantic/lexical code search and \`zvec_grep_rg\` for explicit no-index lexical search.
|
|
806
|
+
- **Indexing and status**: These are CLI-only operations. If an index is missing, use \`zvec_grep_rg\` and mention \`zg index\` as the opt-in setup path; use \`zg status\` when status inspection is needed.
|
|
807
|
+
- **Shell fallback**: If the MCP server is unavailable, use \`zg status\`, \`zg query "<query>"\`, and \`zg query --rg "<pattern>"\`.
|
|
808
|
+
|
|
809
|
+
Prefer focused -g/--glob and -t/--type filters, and exclude dependencies, generated output, caches, build artifacts, and logs unless the task is about those files.
|
|
810
|
+
${ZVEC_GREP_AGENTS_END}`;
|
|
285
811
|
}
|
|
286
812
|
function resolveIndexRoot(root) {
|
|
287
813
|
if (root !== undefined) {
|
|
@@ -293,8 +819,16 @@ function indexRootPath(path, options) {
|
|
|
293
819
|
return {
|
|
294
820
|
absolutePath: resolve(path),
|
|
295
821
|
recursive: true,
|
|
296
|
-
|
|
297
|
-
|
|
822
|
+
globs: options.globs,
|
|
823
|
+
insensitiveGlobs: options.insensitiveGlobs,
|
|
824
|
+
fileTypes: options.fileTypes,
|
|
825
|
+
excludedFileTypes: options.excludedFileTypes,
|
|
826
|
+
hidden: options.hidden,
|
|
827
|
+
noIgnore: options.noIgnore,
|
|
828
|
+
ignoreFiles: options.ignoreFiles,
|
|
829
|
+
maxDepth: options.maxDepth,
|
|
830
|
+
maxFileSizeBytes: options.maxFileSizeBytes,
|
|
831
|
+
follow: options.follow,
|
|
298
832
|
};
|
|
299
833
|
}
|
|
300
834
|
//# sourceMappingURL=commands.js.map
|