@zvec/zvec-grep 0.1.5 → 0.1.6

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 (317) hide show
  1. package/README.md +88 -249
  2. package/README_CN.md +82 -246
  3. package/dist/authorization/index.d.ts +7 -0
  4. package/dist/authorization/index.js +7 -0
  5. package/dist/authorization/index.js.map +1 -0
  6. package/dist/authorization/manager.d.ts +8 -0
  7. package/dist/authorization/manager.js +19 -0
  8. package/dist/authorization/manager.js.map +1 -0
  9. package/dist/authorization/operation.d.ts +7 -0
  10. package/dist/authorization/operation.js +50 -0
  11. package/dist/authorization/operation.js.map +1 -0
  12. package/dist/authorization/planner.d.ts +21 -0
  13. package/dist/authorization/planner.js +97 -0
  14. package/dist/authorization/planner.js.map +1 -0
  15. package/dist/authorization/prompt.d.ts +11 -0
  16. package/dist/authorization/prompt.js +62 -0
  17. package/dist/authorization/prompt.js.map +1 -0
  18. package/dist/authorization/store.d.ts +20 -0
  19. package/dist/authorization/store.js +251 -0
  20. package/dist/authorization/store.js.map +1 -0
  21. package/dist/authorization/target.d.ts +15 -0
  22. package/dist/authorization/target.js +49 -0
  23. package/dist/authorization/target.js.map +1 -0
  24. package/dist/authorization/types.d.ts +61 -0
  25. package/dist/authorization/types.js +2 -0
  26. package/dist/authorization/types.js.map +1 -0
  27. package/dist/cli/args.d.ts +1 -1
  28. package/dist/cli/args.js +304 -54
  29. package/dist/cli/args.js.map +1 -1
  30. package/dist/cli/auth.d.ts +21 -0
  31. package/dist/cli/auth.js +212 -0
  32. package/dist/cli/auth.js.map +1 -0
  33. package/dist/cli/commands.js +433 -618
  34. package/dist/cli/commands.js.map +1 -1
  35. package/dist/cli/errors.js +2 -2
  36. package/dist/cli/errors.js.map +1 -1
  37. package/dist/cli/format/context.d.ts +1 -0
  38. package/dist/cli/format/context.js +241 -45
  39. package/dist/cli/format/context.js.map +1 -1
  40. package/dist/cli/format/debug.js +2 -2
  41. package/dist/cli/format/debug.js.map +1 -1
  42. package/dist/cli/format/progress.d.ts +4 -0
  43. package/dist/cli/format/progress.js +219 -46
  44. package/dist/cli/format/progress.js.map +1 -1
  45. package/dist/cli/format/status.d.ts +77 -6
  46. package/dist/cli/format/status.js +302 -106
  47. package/dist/cli/format/status.js.map +1 -1
  48. package/dist/cli/help.js +258 -59
  49. package/dist/cli/help.js.map +1 -1
  50. package/dist/cli/index.js +0 -0
  51. package/dist/cli/install.d.ts +4 -0
  52. package/dist/cli/install.js +845 -0
  53. package/dist/cli/install.js.map +1 -0
  54. package/dist/cli/managed-rg.d.ts +10 -0
  55. package/dist/cli/managed-rg.js +329 -0
  56. package/dist/cli/managed-rg.js.map +1 -0
  57. package/dist/cli/types.d.ts +20 -6
  58. package/dist/cli/types.js.map +1 -1
  59. package/dist/client/daemon-client.d.ts +19 -0
  60. package/dist/client/daemon-client.js +180 -0
  61. package/dist/client/daemon-client.js.map +1 -0
  62. package/dist/client/mode-router.d.ts +9 -0
  63. package/dist/client/mode-router.js +28 -0
  64. package/dist/client/mode-router.js.map +1 -0
  65. package/dist/client/search-policy.d.ts +11 -0
  66. package/dist/client/search-policy.js +15 -0
  67. package/dist/client/search-policy.js.map +1 -0
  68. package/dist/daemon/backend.d.ts +76 -0
  69. package/dist/daemon/backend.js +1049 -0
  70. package/dist/daemon/backend.js.map +1 -0
  71. package/dist/daemon/change-set.d.ts +25 -0
  72. package/dist/daemon/change-set.js +101 -0
  73. package/dist/daemon/change-set.js.map +1 -0
  74. package/dist/daemon/config.d.ts +24 -0
  75. package/dist/daemon/config.js +88 -0
  76. package/dist/daemon/config.js.map +1 -0
  77. package/dist/daemon/errors.d.ts +5 -0
  78. package/dist/daemon/errors.js +11 -0
  79. package/dist/daemon/errors.js.map +1 -0
  80. package/dist/daemon/http-server.d.ts +30 -0
  81. package/dist/daemon/http-server.js +287 -0
  82. package/dist/daemon/http-server.js.map +1 -0
  83. package/dist/daemon/index-coordinator.d.ts +23 -0
  84. package/dist/daemon/index-coordinator.js +68 -0
  85. package/dist/daemon/index-coordinator.js.map +1 -0
  86. package/dist/daemon/job-scheduler.d.ts +70 -0
  87. package/dist/daemon/job-scheduler.js +366 -0
  88. package/dist/daemon/job-scheduler.js.map +1 -0
  89. package/dist/daemon/logger.d.ts +9 -0
  90. package/dist/daemon/logger.js +53 -0
  91. package/dist/daemon/logger.js.map +1 -0
  92. package/dist/daemon/model-pool.d.ts +45 -0
  93. package/dist/daemon/model-pool.js +187 -0
  94. package/dist/daemon/model-pool.js.map +1 -0
  95. package/dist/daemon/root-lease.d.ts +14 -0
  96. package/dist/daemon/root-lease.js +188 -0
  97. package/dist/daemon/root-lease.js.map +1 -0
  98. package/dist/daemon/root-runtime.d.ts +78 -0
  99. package/dist/daemon/root-runtime.js +333 -0
  100. package/dist/daemon/root-runtime.js.map +1 -0
  101. package/dist/daemon/runtime-manager.d.ts +45 -0
  102. package/dist/daemon/runtime-manager.js +243 -0
  103. package/dist/daemon/runtime-manager.js.map +1 -0
  104. package/dist/daemon/runtime.d.ts +12 -0
  105. package/dist/daemon/runtime.js +102 -0
  106. package/dist/daemon/runtime.js.map +1 -0
  107. package/dist/daemon/server-controller.d.ts +39 -0
  108. package/dist/daemon/server-controller.js +203 -0
  109. package/dist/daemon/server-controller.js.map +1 -0
  110. package/dist/daemon/watch-manager.d.ts +50 -0
  111. package/dist/daemon/watch-manager.js +293 -0
  112. package/dist/daemon/watch-manager.js.map +1 -0
  113. package/dist/daemon/workspace-read-session-cache.d.ts +31 -0
  114. package/dist/daemon/workspace-read-session-cache.js +115 -0
  115. package/dist/daemon/workspace-read-session-cache.js.map +1 -0
  116. package/dist/engine/config.d.ts +30 -8
  117. package/dist/engine/config.js +171 -45
  118. package/dist/engine/config.js.map +1 -1
  119. package/dist/engine/{errors/index.d.ts → errors.d.ts} +6 -1
  120. package/dist/engine/{errors/details.js → errors.js} +17 -4
  121. package/dist/engine/errors.js.map +1 -0
  122. package/dist/engine/extraction/code/adapter.d.ts +1 -1
  123. package/dist/engine/extraction/code/extractor.d.ts +5 -11
  124. package/dist/engine/extraction/code/extractor.js +105 -44
  125. package/dist/engine/extraction/code/extractor.js.map +1 -1
  126. package/dist/engine/extraction/code/families/c-family.js +1 -1
  127. package/dist/engine/extraction/code/families/c-family.js.map +1 -1
  128. package/dist/engine/extraction/code/families/js-ts.d.ts +1 -1
  129. package/dist/engine/extraction/code/families/metadata.d.ts +1 -1
  130. package/dist/engine/extraction/code/tree-sitter/grammar.js.map +1 -0
  131. package/dist/engine/extraction/code/tree-sitter/nodes.js.map +1 -0
  132. package/dist/engine/extraction/code/tree-sitter/parser.js.map +1 -0
  133. package/dist/engine/extraction/image/extractor.d.ts +5 -0
  134. package/dist/engine/extraction/image/extractor.js +35 -0
  135. package/dist/engine/extraction/image/extractor.js.map +1 -0
  136. package/dist/engine/extraction/index.d.ts +3 -44
  137. package/dist/engine/extraction/index.js +1 -280
  138. package/dist/engine/extraction/index.js.map +1 -1
  139. package/dist/engine/extraction/markdown/extractor.d.ts +5 -11
  140. package/dist/engine/extraction/markdown/extractor.js +35 -16
  141. package/dist/engine/extraction/markdown/extractor.js.map +1 -1
  142. package/dist/engine/extraction/runtime.d.ts +4 -0
  143. package/dist/engine/extraction/runtime.js +26 -0
  144. package/dist/engine/extraction/runtime.js.map +1 -0
  145. package/dist/engine/extraction/source.d.ts +18 -0
  146. package/dist/engine/extraction/source.js +22 -0
  147. package/dist/engine/extraction/source.js.map +1 -0
  148. package/dist/engine/extraction/text/extractor.d.ts +7 -0
  149. package/dist/engine/extraction/text/extractor.js +168 -0
  150. package/dist/engine/extraction/text/extractor.js.map +1 -0
  151. package/dist/engine/extraction/types.d.ts +4 -0
  152. package/dist/engine/{models → extraction}/types.js.map +1 -1
  153. package/dist/engine/{files/file-type.d.ts → file-type.d.ts} +1 -1
  154. package/dist/engine/file-type.js.map +1 -0
  155. package/dist/engine/index-status.d.ts +9 -0
  156. package/dist/engine/index-status.js +38 -0
  157. package/dist/engine/index-status.js.map +1 -0
  158. package/dist/engine/manifest.d.ts +12 -0
  159. package/dist/engine/manifest.js +120 -0
  160. package/dist/engine/manifest.js.map +1 -0
  161. package/dist/engine/models/{providers/llama-cpp/embedding.d.ts → backends/llama-cpp.d.ts} +25 -20
  162. package/dist/engine/models/{providers/llama-cpp/embedding.js → backends/llama-cpp.js} +127 -106
  163. package/dist/engine/models/backends/llama-cpp.js.map +1 -0
  164. package/dist/engine/models/backends/model2vec.d.ts +57 -0
  165. package/dist/engine/models/backends/model2vec.js +332 -0
  166. package/dist/engine/models/backends/model2vec.js.map +1 -0
  167. package/dist/engine/models/backends/qwen.d.ts +44 -0
  168. package/dist/engine/models/{providers/qwen/embedding.js → backends/qwen.js} +155 -94
  169. package/dist/engine/models/backends/qwen.js.map +1 -0
  170. package/dist/engine/models/backends/transformers-js.d.ts +87 -0
  171. package/dist/engine/models/backends/transformers-js.js +316 -0
  172. package/dist/engine/models/backends/transformers-js.js.map +1 -0
  173. package/dist/engine/models/catalog.d.ts +188 -23
  174. package/dist/engine/models/catalog.js +172 -25
  175. package/dist/engine/models/catalog.js.map +1 -1
  176. package/dist/engine/models/download-progress.d.ts +15 -0
  177. package/dist/engine/models/download-progress.js +48 -0
  178. package/dist/engine/models/download-progress.js.map +1 -0
  179. package/dist/engine/models/embeddings.d.ts +58 -18
  180. package/dist/engine/models/embeddings.js +52 -28
  181. package/dist/engine/models/embeddings.js.map +1 -1
  182. package/dist/engine/models/factory.d.ts +2 -5
  183. package/dist/engine/models/factory.js +41 -56
  184. package/dist/engine/models/factory.js.map +1 -1
  185. package/dist/engine/models/index.d.ts +4 -6
  186. package/dist/engine/models/index.js +4 -4
  187. package/dist/engine/models/index.js.map +1 -1
  188. package/dist/engine/models/ranking.d.ts +7 -3
  189. package/dist/engine/models/resolution.d.ts +8 -0
  190. package/dist/engine/models/resolution.js +22 -0
  191. package/dist/engine/models/resolution.js.map +1 -0
  192. package/dist/engine/pipeline/indexing/index.d.ts +9 -7
  193. package/dist/engine/pipeline/indexing/index.js +360 -121
  194. package/dist/engine/pipeline/indexing/index.js.map +1 -1
  195. package/dist/engine/pipeline/indexing/root-paths.js +6 -6
  196. package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
  197. package/dist/engine/pipeline/indexing/scanner/index.d.ts +6 -1
  198. package/dist/engine/pipeline/indexing/scanner/index.js +233 -29
  199. package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
  200. package/dist/engine/pipeline/search/index.d.ts +6 -6
  201. package/dist/engine/pipeline/search/index.js +8 -10
  202. package/dist/engine/pipeline/search/index.js.map +1 -1
  203. package/dist/engine/service/index.d.ts +3 -2
  204. package/dist/engine/service/index.js +1 -1
  205. package/dist/engine/service/index.js.map +1 -1
  206. package/dist/engine/service/root.d.ts +13 -12
  207. package/dist/engine/service/root.js +35 -24
  208. package/dist/engine/service/root.js.map +1 -1
  209. package/dist/engine/service/structure-enrichment.js +12 -14
  210. package/dist/engine/service/structure-enrichment.js.map +1 -1
  211. package/dist/engine/service/types.d.ts +32 -37
  212. package/dist/engine/service/workspace-index.d.ts +24 -0
  213. package/dist/engine/service/workspace-index.js +151 -0
  214. package/dist/engine/service/workspace-index.js.map +1 -0
  215. package/dist/engine/service/zvec-grep.d.ts +12 -1
  216. package/dist/engine/service/zvec-grep.js +677 -486
  217. package/dist/engine/service/zvec-grep.js.map +1 -1
  218. package/dist/engine/storage/index.d.ts +8 -4
  219. package/dist/engine/storage/index.js +1 -1
  220. package/dist/engine/storage/index.js.map +1 -1
  221. package/dist/engine/storage/zvec.d.ts +10 -33
  222. package/dist/engine/storage/zvec.js +95 -38
  223. package/dist/engine/storage/zvec.js.map +1 -1
  224. package/dist/engine/types.d.ts +15 -23
  225. package/dist/engine/types.js +1 -1
  226. package/dist/engine/types.js.map +1 -1
  227. package/dist/engine/utils/daemon-lease.d.ts +17 -0
  228. package/dist/engine/utils/daemon-lease.js +175 -0
  229. package/dist/engine/utils/daemon-lease.js.map +1 -0
  230. package/dist/engine/utils/file-selection.js +38 -1
  231. package/dist/engine/utils/file-selection.js.map +1 -1
  232. package/dist/engine/utils/lock.js +1 -1
  233. package/dist/engine/utils/lock.js.map +1 -1
  234. package/dist/index-progress.d.ts +10 -0
  235. package/dist/index-progress.js +159 -0
  236. package/dist/index-progress.js.map +1 -0
  237. package/dist/index.d.ts +4 -4
  238. package/dist/index.js +1 -1
  239. package/dist/index.js.map +1 -1
  240. package/dist/mcp/http-transport.d.ts +27 -0
  241. package/dist/mcp/http-transport.js +182 -0
  242. package/dist/mcp/http-transport.js.map +1 -0
  243. package/dist/mcp/input-normalization.d.ts +38 -0
  244. package/dist/mcp/input-normalization.js +95 -0
  245. package/dist/mcp/input-normalization.js.map +1 -0
  246. package/dist/mcp/progress-heartbeat.d.ts +17 -0
  247. package/dist/mcp/progress-heartbeat.js +46 -0
  248. package/dist/mcp/progress-heartbeat.js.map +1 -0
  249. package/dist/mcp/request-metadata.d.ts +2 -0
  250. package/dist/mcp/request-metadata.js +11 -0
  251. package/dist/mcp/request-metadata.js.map +1 -0
  252. package/dist/mcp/request-state.d.ts +40 -0
  253. package/dist/mcp/request-state.js +210 -0
  254. package/dist/mcp/request-state.js.map +1 -0
  255. package/dist/mcp/result-format.d.ts +13 -0
  256. package/dist/mcp/result-format.js +75 -0
  257. package/dist/mcp/result-format.js.map +1 -0
  258. package/dist/mcp/schemas.d.ts +430 -0
  259. package/dist/mcp/schemas.js +447 -0
  260. package/dist/mcp/schemas.js.map +1 -0
  261. package/dist/mcp/tools.d.ts +150 -0
  262. package/dist/mcp/tools.js +448 -0
  263. package/dist/mcp/tools.js.map +1 -0
  264. package/dist/mcp/toolset.d.ts +5 -0
  265. package/dist/mcp/toolset.js +12 -0
  266. package/dist/mcp/toolset.js.map +1 -0
  267. package/dist/observability/trace-context.d.ts +11 -0
  268. package/dist/observability/trace-context.js +138 -0
  269. package/dist/observability/trace-context.js.map +1 -0
  270. package/docs/01-agents.md +111 -0
  271. package/docs/02-cli.md +229 -0
  272. package/docs/03-mcp.md +167 -0
  273. package/docs/04-pipeline.md +218 -0
  274. package/docs/05-architecture.md +86 -0
  275. package/docs/06-server.md +210 -0
  276. package/docs/07-embedding.md +179 -0
  277. package/docs/08-roadmap.md +85 -0
  278. package/docs/README.md +53 -0
  279. package/package.json +17 -8
  280. package/skills/zvec-grep/SKILL.md +43 -133
  281. package/skills/zvec-grep/agents/openai.yaml +2 -2
  282. package/skills/zvec-grep/references/cli-fallback.md +85 -0
  283. package/dist/cli/mcp.d.ts +0 -2
  284. package/dist/cli/mcp.js +0 -354
  285. package/dist/cli/mcp.js.map +0 -1
  286. package/dist/engine/collection/index.d.ts +0 -55
  287. package/dist/engine/collection/index.js +0 -710
  288. package/dist/engine/collection/index.js.map +0 -1
  289. package/dist/engine/errors/details.d.ts +0 -6
  290. package/dist/engine/errors/details.js.map +0 -1
  291. package/dist/engine/errors/index.js +0 -16
  292. package/dist/engine/errors/index.js.map +0 -1
  293. package/dist/engine/extraction/tree-sitter/grammar.js.map +0 -1
  294. package/dist/engine/extraction/tree-sitter/nodes.js.map +0 -1
  295. package/dist/engine/extraction/tree-sitter/parser.js.map +0 -1
  296. package/dist/engine/files/file-type.js.map +0 -1
  297. package/dist/engine/models/providers/index.d.ts +0 -2
  298. package/dist/engine/models/providers/index.js +0 -3
  299. package/dist/engine/models/providers/index.js.map +0 -1
  300. package/dist/engine/models/providers/llama-cpp/embedding.js.map +0 -1
  301. package/dist/engine/models/providers/llama-cpp/index.d.ts +0 -1
  302. package/dist/engine/models/providers/llama-cpp/index.js +0 -2
  303. package/dist/engine/models/providers/llama-cpp/index.js.map +0 -1
  304. package/dist/engine/models/providers/qwen/embedding.d.ts +0 -42
  305. package/dist/engine/models/providers/qwen/embedding.js.map +0 -1
  306. package/dist/engine/models/providers/qwen/index.d.ts +0 -1
  307. package/dist/engine/models/providers/qwen/index.js +0 -2
  308. package/dist/engine/models/providers/qwen/index.js.map +0 -1
  309. package/dist/engine/models/types.d.ts +0 -30
  310. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.d.ts +0 -0
  311. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.js +0 -0
  312. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.d.ts +0 -0
  313. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.js +0 -0
  314. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.d.ts +0 -0
  315. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.js +0 -0
  316. /package/dist/engine/{models → extraction}/types.js +0 -0
  317. /package/dist/engine/{files/file-type.js → file-type.js} +0 -0
@@ -0,0 +1,845 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { constants as fileSystemConstants } from "node:fs";
3
+ import { access, chmod, lstat, mkdir, open, readFile, readlink, rename, stat, unlink, } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { delimiter, dirname, resolve } from "node:path";
6
+ import { createInterface } from "node:readline/promises";
7
+ import { resolveServerUrl } from "../client/mode-router.js";
8
+ const AGENT_INSTALLERS = [
9
+ {
10
+ id: "claude",
11
+ label: "Claude Code",
12
+ executable: "claude",
13
+ install: installClaudeIntegration,
14
+ uninstall: uninstallClaudeIntegration,
15
+ },
16
+ {
17
+ id: "codex",
18
+ label: "Codex",
19
+ executable: "codex",
20
+ install: installCodexIntegration,
21
+ uninstall: uninstallCodexIntegration,
22
+ },
23
+ {
24
+ id: "opencode",
25
+ label: "OpenCode",
26
+ executable: "opencode",
27
+ install: installOpenCodeIntegration,
28
+ uninstall: uninstallOpenCodeIntegration,
29
+ },
30
+ {
31
+ id: "cursor",
32
+ label: "Cursor",
33
+ executable: "cursor",
34
+ install: installCursorIntegration,
35
+ uninstall: uninstallCursorIntegration,
36
+ },
37
+ ];
38
+ const ZVEC_GREP_CONFIG_START = "# ZVEC_GREP_START";
39
+ const ZVEC_GREP_CONFIG_END = "# ZVEC_GREP_END";
40
+ const ZVEC_GREP_AGENTS_START = "<!-- ZVEC_GREP_START -->";
41
+ const ZVEC_GREP_AGENTS_END = "<!-- ZVEC_GREP_END -->";
42
+ const CLAUDE_MCP_PERMISSION = "mcp__zvec_grep__*";
43
+ const DEFAULT_MCP_TOOL_TIMEOUT_SECONDS = 600;
44
+ export async function runInstall(parsed) {
45
+ printInstallHeader();
46
+ const installers = await resolveInstallers(parsed, "install");
47
+ if (installers.length === 0) {
48
+ console.log("\nNo agent integrations selected.");
49
+ return;
50
+ }
51
+ console.log("\nInstalling integrations\n");
52
+ for (const installer of installers) {
53
+ await installer.install({
54
+ force: parsed.options.force === true,
55
+ mcpToolTimeoutSeconds: parsed.options.installMcpToolTimeoutSeconds ??
56
+ DEFAULT_MCP_TOOL_TIMEOUT_SECONDS,
57
+ mcpTokenEnv: parsed.options.installMcpTokenEnv,
58
+ });
59
+ console.log(` ${installSuccessMark()} ${installer.label}`);
60
+ console.log(" MCP configured");
61
+ console.log("");
62
+ }
63
+ const server = await ensureInstalledServer();
64
+ if (server.ready) {
65
+ console.log(` ${installSuccessMark()} Server`);
66
+ console.log(` ready at ${server.serverUrl ?? resolveServerUrl()}`);
67
+ }
68
+ else {
69
+ console.log(` ${installMutedMark()} Server`);
70
+ console.log(" not started; run `zg server on`");
71
+ }
72
+ console.log("\nzvec-grep is ready\n");
73
+ console.log(` Agents ${installers.map((installer) => installer.label).join(", ")}`);
74
+ console.log(" Remote data Authorization requested on first remote use");
75
+ console.log("\nRestart the selected agents or start a new session to load the integration.");
76
+ }
77
+ export async function runUninstall(parsed) {
78
+ printInstallHeader();
79
+ const installers = await resolveInstallers(parsed, "uninstall");
80
+ if (installers.length === 0) {
81
+ console.log("\nNo agent integrations selected.");
82
+ return;
83
+ }
84
+ console.log("\nRemoving integrations\n");
85
+ for (const installer of installers) {
86
+ await installer.uninstall();
87
+ console.log(` ${installSuccessMark()} ${installer.label}`);
88
+ console.log(" integration removed");
89
+ }
90
+ console.log("\nRestart the selected agents or start a new session to apply the change.");
91
+ }
92
+ async function installCodexIntegration(options) {
93
+ const codexHome = resolveCodexHome();
94
+ const configPath = resolve(codexHome, "config.toml");
95
+ const agentsPath = resolve(codexHome, "AGENTS.md");
96
+ await writeMarkedFile({
97
+ path: configPath,
98
+ startMarker: ZVEC_GREP_CONFIG_START,
99
+ endMarker: ZVEC_GREP_CONFIG_END,
100
+ block: codexConfigBlock(options.mcpToolTimeoutSeconds, options.mcpTokenEnv),
101
+ force: options.force,
102
+ hasConflict: hasCodexMcpServerConfig,
103
+ 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.`,
104
+ removeConflict: removeCodexMcpServerConfig,
105
+ });
106
+ await writeMarkedFile({
107
+ path: agentsPath,
108
+ startMarker: ZVEC_GREP_AGENTS_START,
109
+ endMarker: ZVEC_GREP_AGENTS_END,
110
+ block: agentGuidanceBlock(),
111
+ force: true,
112
+ });
113
+ return { files: [configPath, agentsPath] };
114
+ }
115
+ async function installClaudeIntegration(options) {
116
+ const configDirectory = resolveClaudeConfigDirectory();
117
+ const mcpConfigPath = resolveClaudeMcpConfigPath();
118
+ const settingsPath = resolve(configDirectory, "settings.json");
119
+ const guidancePath = resolve(configDirectory, "CLAUDE.md");
120
+ await updateClaudeMcpConfig({
121
+ path: mcpConfigPath,
122
+ force: options.force,
123
+ tokenEnv: options.mcpTokenEnv,
124
+ });
125
+ await updateClaudePermissionSettings(settingsPath, true);
126
+ await writeMarkedFile({
127
+ path: guidancePath,
128
+ startMarker: ZVEC_GREP_AGENTS_START,
129
+ endMarker: ZVEC_GREP_AGENTS_END,
130
+ block: agentGuidanceBlock(),
131
+ force: true,
132
+ });
133
+ return { files: [mcpConfigPath, settingsPath, guidancePath] };
134
+ }
135
+ async function uninstallClaudeIntegration() {
136
+ const configDirectory = resolveClaudeConfigDirectory();
137
+ const mcpConfigPath = resolveClaudeMcpConfigPath();
138
+ const settingsPath = resolve(configDirectory, "settings.json");
139
+ const guidancePath = resolve(configDirectory, "CLAUDE.md");
140
+ await removeClaudeMcpConfig(mcpConfigPath);
141
+ await updateClaudePermissionSettings(settingsPath, false);
142
+ await removeMarkedFile({
143
+ path: guidancePath,
144
+ startMarker: ZVEC_GREP_AGENTS_START,
145
+ endMarker: ZVEC_GREP_AGENTS_END,
146
+ });
147
+ return { files: [mcpConfigPath, settingsPath, guidancePath] };
148
+ }
149
+ async function uninstallCodexIntegration() {
150
+ const codexHome = resolveCodexHome();
151
+ const configPath = resolve(codexHome, "config.toml");
152
+ const agentsPath = resolve(codexHome, "AGENTS.md");
153
+ await removeMarkedFile({
154
+ path: configPath,
155
+ startMarker: ZVEC_GREP_CONFIG_START,
156
+ endMarker: ZVEC_GREP_CONFIG_END,
157
+ });
158
+ await removeMarkedFile({
159
+ path: agentsPath,
160
+ startMarker: ZVEC_GREP_AGENTS_START,
161
+ endMarker: ZVEC_GREP_AGENTS_END,
162
+ });
163
+ return { files: [configPath, agentsPath] };
164
+ }
165
+ async function installOpenCodeIntegration(options) {
166
+ const configPath = resolveOpenCodeConfigPath();
167
+ const guidancePath = resolve(dirname(configPath), "AGENTS.md");
168
+ await installJsonMcpServer({
169
+ path: configPath,
170
+ containerKey: "mcp",
171
+ server: {
172
+ type: "remote",
173
+ url: resolveServerUrl(),
174
+ enabled: true,
175
+ timeout: options.mcpToolTimeoutSeconds * 1_000,
176
+ oauth: false,
177
+ ...(options.mcpTokenEnv
178
+ ? {
179
+ headers: {
180
+ Authorization: `Bearer {env:${options.mcpTokenEnv}}`,
181
+ },
182
+ }
183
+ : {}),
184
+ },
185
+ force: options.force,
186
+ label: "OpenCode",
187
+ });
188
+ await writeMarkedFile({
189
+ path: guidancePath,
190
+ startMarker: ZVEC_GREP_AGENTS_START,
191
+ endMarker: ZVEC_GREP_AGENTS_END,
192
+ block: agentGuidanceBlock({
193
+ search: "zvec_grep_zvec_grep_search",
194
+ }),
195
+ force: true,
196
+ });
197
+ return { files: [configPath, guidancePath] };
198
+ }
199
+ async function uninstallOpenCodeIntegration() {
200
+ const configPath = resolveOpenCodeConfigPath();
201
+ const guidancePath = resolve(dirname(configPath), "AGENTS.md");
202
+ await uninstallJsonMcpServer(configPath, "mcp");
203
+ await removeMarkedFile({
204
+ path: guidancePath,
205
+ startMarker: ZVEC_GREP_AGENTS_START,
206
+ endMarker: ZVEC_GREP_AGENTS_END,
207
+ });
208
+ return { files: [configPath, guidancePath] };
209
+ }
210
+ async function installCursorIntegration(options) {
211
+ const configPath = resolveCursorConfigPath();
212
+ await installJsonMcpServer({
213
+ path: configPath,
214
+ containerKey: "mcpServers",
215
+ server: {
216
+ url: resolveServerUrl(),
217
+ ...(options.mcpTokenEnv
218
+ ? {
219
+ headers: {
220
+ Authorization: `Bearer \${${options.mcpTokenEnv}}`,
221
+ },
222
+ }
223
+ : {}),
224
+ },
225
+ force: options.force,
226
+ label: "Cursor",
227
+ });
228
+ return { files: [configPath] };
229
+ }
230
+ async function uninstallCursorIntegration() {
231
+ const configPath = resolveCursorConfigPath();
232
+ await uninstallJsonMcpServer(configPath, "mcpServers");
233
+ return { files: [configPath] };
234
+ }
235
+ async function resolveInstallers(parsed, action) {
236
+ const detected = await detectAgentInstallers();
237
+ const targetTokens = [
238
+ ...(parsed.options.installTargets ?? []),
239
+ ...parsed.positionals,
240
+ ];
241
+ if (targetTokens.length > 0) {
242
+ return installersFromTokens(targetTokens, detected);
243
+ }
244
+ if (parsed.options.yes === true ||
245
+ !process.stdin.isTTY ||
246
+ !process.stdout.isTTY) {
247
+ return installersFromTokens(["auto"], detected);
248
+ }
249
+ return promptInstallers(action, detected);
250
+ }
251
+ async function promptInstallers(action, detected) {
252
+ console.log(action === "install"
253
+ ? "\nChoose agent integrations\n"
254
+ : "\nChoose integrations to remove\n");
255
+ const selected = await promptInstallerSelection(detected);
256
+ return AGENT_INSTALLERS.filter((installer) => selected.has(installer.id));
257
+ }
258
+ function installersFromTokens(tokens, detected = new Set()) {
259
+ const normalized = tokens.flatMap(splitTargetTokens);
260
+ if (normalized.length === 0) {
261
+ return installersFromTokens(["auto"], detected);
262
+ }
263
+ const selected = new Map();
264
+ for (const token of normalized) {
265
+ const input = token.toLowerCase();
266
+ const lower = input === "cc" || input === "claude-code" ? "claude" : input;
267
+ if (lower === "none") {
268
+ return [];
269
+ }
270
+ if (lower === "auto") {
271
+ for (const installer of AGENT_INSTALLERS) {
272
+ if (detected.has(installer.id)) {
273
+ selected.set(installer.id, installer);
274
+ }
275
+ }
276
+ continue;
277
+ }
278
+ if (lower === "all") {
279
+ for (const installer of AGENT_INSTALLERS) {
280
+ selected.set(installer.id, installer);
281
+ }
282
+ continue;
283
+ }
284
+ const numbered = /^\d+$/.test(lower) ? Number(lower) : Number.NaN;
285
+ if (Number.isInteger(numbered) &&
286
+ numbered >= 1 &&
287
+ numbered <= AGENT_INSTALLERS.length) {
288
+ const installer = AGENT_INSTALLERS[numbered - 1];
289
+ selected.set(installer.id, installer);
290
+ continue;
291
+ }
292
+ const installer = AGENT_INSTALLERS.find((candidate) => candidate.id === lower || candidate.label.toLowerCase() === lower);
293
+ if (!installer) {
294
+ throw new Error(`Unknown install target: ${token}`);
295
+ }
296
+ selected.set(installer.id, installer);
297
+ }
298
+ return [...selected.values()];
299
+ }
300
+ async function detectAgentInstallers() {
301
+ const detected = new Set();
302
+ const checks = await Promise.all(AGENT_INSTALLERS.map(async (installer) => ({
303
+ installer,
304
+ available: await executableIsAvailable(installer.executable),
305
+ })));
306
+ for (const check of checks) {
307
+ if (check.available) {
308
+ detected.add(check.installer.id);
309
+ }
310
+ }
311
+ return detected;
312
+ }
313
+ async function executableIsAvailable(executable) {
314
+ const path = process.env.PATH ?? "";
315
+ const extensions = process.platform === "win32"
316
+ ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";")
317
+ : [""];
318
+ for (const pathEntry of path.split(delimiter)) {
319
+ const directory = pathEntry || process.cwd();
320
+ for (const extension of extensions) {
321
+ try {
322
+ await access(resolve(directory, `${executable}${extension.toLowerCase()}`), fileSystemConstants.X_OK);
323
+ return true;
324
+ }
325
+ catch {
326
+ // Continue searching PATH.
327
+ }
328
+ }
329
+ }
330
+ return false;
331
+ }
332
+ async function promptInstallerSelection(detected) {
333
+ if (typeof process.stdin.setRawMode !== "function") {
334
+ return promptInstallerLineSelection(detected);
335
+ }
336
+ let activeIndex = Math.max(0, AGENT_INSTALLERS.findIndex((installer) => detected.has(installer.id)));
337
+ let renderedLineCount = 0;
338
+ const render = () => {
339
+ const lines = installerSelectionLines(activeIndex, detected);
340
+ if (renderedLineCount > 0) {
341
+ process.stdout.write(`\u001b[${renderedLineCount}A`);
342
+ }
343
+ for (const line of lines) {
344
+ process.stdout.write(`\u001b[2K${line}\n`);
345
+ }
346
+ renderedLineCount = lines.length;
347
+ };
348
+ render();
349
+ return new Promise((resolveSelection) => {
350
+ const wasRaw = process.stdin.isRaw === true;
351
+ const finish = (result) => {
352
+ process.stdin.removeListener("data", onData);
353
+ process.stdin.setRawMode(wasRaw);
354
+ if (!wasRaw)
355
+ process.stdin.pause();
356
+ process.stdout.write("\n");
357
+ resolveSelection(result);
358
+ };
359
+ const onData = (chunk) => {
360
+ const key = chunk.toString();
361
+ if (key === "\u0003" || key === "\u001b") {
362
+ finish(new Set());
363
+ return;
364
+ }
365
+ if (key === "\u001b[A") {
366
+ activeIndex =
367
+ (activeIndex - 1 + AGENT_INSTALLERS.length) % AGENT_INSTALLERS.length;
368
+ render();
369
+ return;
370
+ }
371
+ if (key === "\u001b[B") {
372
+ activeIndex = (activeIndex + 1) % AGENT_INSTALLERS.length;
373
+ render();
374
+ return;
375
+ }
376
+ if (key.includes("\r") || key.includes("\n")) {
377
+ finish(new Set([AGENT_INSTALLERS[activeIndex].id]));
378
+ }
379
+ };
380
+ process.stdin.setRawMode(true);
381
+ process.stdin.resume();
382
+ process.stdin.on("data", onData);
383
+ });
384
+ }
385
+ export function installerSelectionLines(activeIndex, detected) {
386
+ const labelWidth = Math.max(...AGENT_INSTALLERS.map((installer) => installer.label.length));
387
+ return [
388
+ ...AGENT_INSTALLERS.map((installer, index) => {
389
+ const marker = index === activeIndex ? installSuccess("●") : installDim("○");
390
+ const label = installer.label.padEnd(labelWidth);
391
+ const status = detected.has(installer.id)
392
+ ? installDim("detected")
393
+ : installDim("not found");
394
+ return ` ${marker} ${label} ${status}`;
395
+ }),
396
+ "",
397
+ installDim(" Use ↑↓ to move · Enter to select"),
398
+ ];
399
+ }
400
+ async function promptInstallerLineSelection(detected) {
401
+ AGENT_INSTALLERS.forEach((installer, index) => {
402
+ console.log(` ${index + 1}. ${installer.label} (${detected.has(installer.id) ? "detected" : "not found"})`);
403
+ });
404
+ const defaults = [...detected].join(",") || "none";
405
+ const readline = createInterface({
406
+ input: process.stdin,
407
+ output: process.stdout,
408
+ });
409
+ try {
410
+ const answer = await readline.question(`Agents [${defaults}]: `);
411
+ const value = answer.trim() || defaults;
412
+ return new Set(installersFromTokens(splitTargetTokens(value), detected).map((installer) => installer.id));
413
+ }
414
+ finally {
415
+ readline.close();
416
+ }
417
+ }
418
+ function printInstallHeader() {
419
+ console.log(installAccent("zvec-grep setup"));
420
+ console.log(installDim("─".repeat(40)));
421
+ }
422
+ function installSuccessMark() {
423
+ return installSuccess("✓");
424
+ }
425
+ function installMutedMark() {
426
+ return installDim("○");
427
+ }
428
+ function installSuccess(value) {
429
+ return installStyle("32", value);
430
+ }
431
+ function installAccent(value) {
432
+ return installStyle("36", value);
433
+ }
434
+ function installDim(value) {
435
+ return installStyle("2", value);
436
+ }
437
+ function installStyle(code, value) {
438
+ return process.stdout.isTTY && process.env.NO_COLOR === undefined
439
+ ? `\u001b[${code}m${value}\u001b[0m`
440
+ : value;
441
+ }
442
+ async function ensureInstalledServer() {
443
+ if (process.env.ZVEC_GREP_INSTALL_SKIP_SERVER === "1") {
444
+ return { running: false, ready: false };
445
+ }
446
+ const { startServer } = await import("../daemon/server-controller.js");
447
+ return startServer({ cliPath: process.argv[1] });
448
+ }
449
+ function splitTargetTokens(value) {
450
+ return value
451
+ .split(/[,\s]+/)
452
+ .map((target) => target.trim())
453
+ .filter((target) => target.length > 0);
454
+ }
455
+ function resolveCodexHome() {
456
+ return resolve(process.env.CODEX_HOME ?? resolve(homedir(), ".codex"));
457
+ }
458
+ function resolveClaudeConfigDirectory() {
459
+ return resolve(process.env.CLAUDE_CONFIG_DIR ?? resolve(homedir(), ".claude"));
460
+ }
461
+ function resolveClaudeMcpConfigPath() {
462
+ return process.env.CLAUDE_CONFIG_DIR
463
+ ? resolve(process.env.CLAUDE_CONFIG_DIR, ".claude.json")
464
+ : resolve(homedir(), ".claude.json");
465
+ }
466
+ function resolveOpenCodeConfigPath() {
467
+ return resolve(process.env.OPENCODE_CONFIG ??
468
+ resolve(homedir(), ".config", "opencode", "opencode.json"));
469
+ }
470
+ function resolveCursorConfigPath() {
471
+ return resolve(process.env.CURSOR_CONFIG_DIR ?? resolve(homedir(), ".cursor"), "mcp.json");
472
+ }
473
+ async function installJsonMcpServer(options) {
474
+ const config = await readJsonObject(options.path);
475
+ const existingContainer = config[options.containerKey];
476
+ if (existingContainer !== undefined && !isJsonObject(existingContainer)) {
477
+ throw new Error(`Expected ${options.containerKey} in ${options.path} to be a JSON object`);
478
+ }
479
+ const container = { ...(existingContainer ?? {}) };
480
+ const existingServer = container.zvec_grep;
481
+ if (existingServer !== undefined &&
482
+ !isManagedJsonMcpServer(existingServer) &&
483
+ !options.force) {
484
+ throw new Error(`Existing unmanaged zvec_grep MCP server found in ${options.path}. Re-run with --force to replace it for ${options.label}.`);
485
+ }
486
+ container.zvec_grep = options.server;
487
+ config[options.containerKey] = container;
488
+ await writeTextFileAtomic(options.path, `${JSON.stringify(config, null, 2)}\n`);
489
+ }
490
+ async function uninstallJsonMcpServer(path, containerKey) {
491
+ const existing = await readTextFileIfExists(path);
492
+ if (!existing)
493
+ return;
494
+ const config = parseJsonObject(path, existing);
495
+ const container = config[containerKey];
496
+ if (!isJsonObject(container))
497
+ return;
498
+ if (!isManagedJsonMcpServer(container.zvec_grep))
499
+ return;
500
+ const nextContainer = { ...container };
501
+ delete nextContainer.zvec_grep;
502
+ if (Object.keys(nextContainer).length === 0) {
503
+ delete config[containerKey];
504
+ }
505
+ else {
506
+ config[containerKey] = nextContainer;
507
+ }
508
+ await writeTextFileAtomic(path, `${JSON.stringify(config, null, 2)}\n`);
509
+ }
510
+ async function updateClaudeMcpConfig(options) {
511
+ const root = await readJsonObject(options.path);
512
+ const currentServers = root.mcpServers;
513
+ if (currentServers !== undefined &&
514
+ !isJsonObject(currentServers) &&
515
+ !options.force) {
516
+ throw new Error(`Invalid mcpServers configuration in ${options.path}. Re-run with --force to replace it.`);
517
+ }
518
+ const mcpServers = isJsonObject(currentServers) ? currentServers : {};
519
+ const current = mcpServers.zvec_grep;
520
+ if (current !== undefined &&
521
+ (!isJsonObject(current) || current.url !== resolveServerUrl()) &&
522
+ !options.force) {
523
+ throw new Error(`Existing Claude Code MCP server "zvec_grep" found in ${options.path}. Re-run with --force to replace it.`);
524
+ }
525
+ const existingServer = isJsonObject(current) ? current : {};
526
+ const existingHeaders = isJsonObject(existingServer.headers)
527
+ ? existingServer.headers
528
+ : {};
529
+ mcpServers.zvec_grep = {
530
+ ...existingServer,
531
+ type: "http",
532
+ url: resolveServerUrl(),
533
+ ...(options.tokenEnv
534
+ ? {
535
+ headers: {
536
+ ...existingHeaders,
537
+ Authorization: `Bearer \${${options.tokenEnv}}`,
538
+ },
539
+ }
540
+ : {}),
541
+ };
542
+ root.mcpServers = mcpServers;
543
+ await writeJsonObject(options.path, root);
544
+ }
545
+ async function removeClaudeMcpConfig(path) {
546
+ const source = await readTextFileIfExists(path);
547
+ if (!source.trim())
548
+ return;
549
+ const root = parseJsonObject(path, source);
550
+ if (!isJsonObject(root.mcpServers))
551
+ return;
552
+ const current = root.mcpServers.zvec_grep;
553
+ if (!isJsonObject(current) || current.url !== resolveServerUrl())
554
+ return;
555
+ delete root.mcpServers.zvec_grep;
556
+ if (Object.keys(root.mcpServers).length === 0) {
557
+ delete root.mcpServers;
558
+ }
559
+ await writeJsonObject(path, root);
560
+ }
561
+ async function updateClaudePermissionSettings(path, grant) {
562
+ const source = await readTextFileIfExists(path);
563
+ if (!source.trim() && !grant)
564
+ return;
565
+ const root = source.trim() ? parseJsonObject(path, source) : {};
566
+ const currentPermissions = root.permissions;
567
+ if (currentPermissions !== undefined && !isJsonObject(currentPermissions)) {
568
+ throw new Error(`Invalid permissions configuration in ${path}.`);
569
+ }
570
+ const permissions = isJsonObject(currentPermissions)
571
+ ? currentPermissions
572
+ : {};
573
+ const currentAllow = permissions.allow;
574
+ if (currentAllow !== undefined && !Array.isArray(currentAllow)) {
575
+ throw new Error(`Invalid permissions.allow configuration in ${path}.`);
576
+ }
577
+ if (Array.isArray(currentAllow) &&
578
+ currentAllow.some((item) => typeof item !== "string")) {
579
+ throw new Error(`Invalid permissions.allow rule in ${path}.`);
580
+ }
581
+ const allow = Array.isArray(currentAllow)
582
+ ? currentAllow.slice()
583
+ : [];
584
+ if (grant) {
585
+ if (!allow.includes(CLAUDE_MCP_PERMISSION)) {
586
+ allow.push(CLAUDE_MCP_PERMISSION);
587
+ }
588
+ permissions.allow = allow;
589
+ root.permissions = permissions;
590
+ }
591
+ else {
592
+ const retained = allow.filter((item) => item !== CLAUDE_MCP_PERMISSION);
593
+ if (retained.length > 0)
594
+ permissions.allow = retained;
595
+ else
596
+ delete permissions.allow;
597
+ if (Object.keys(permissions).length > 0)
598
+ root.permissions = permissions;
599
+ else
600
+ delete root.permissions;
601
+ }
602
+ await writeJsonObject(path, root);
603
+ }
604
+ async function readJsonObject(path) {
605
+ const source = await readTextFileIfExists(path);
606
+ return source.trim() ? parseJsonObject(path, source) : {};
607
+ }
608
+ function parseJsonObject(path, source) {
609
+ let parsed;
610
+ try {
611
+ parsed = JSON.parse(source);
612
+ }
613
+ catch (error) {
614
+ throw new Error(`Invalid JSON in ${path}.`, { cause: error });
615
+ }
616
+ if (!isJsonObject(parsed)) {
617
+ throw new Error(`Expected a JSON object in ${path}.`);
618
+ }
619
+ return parsed;
620
+ }
621
+ function isJsonObject(value) {
622
+ return typeof value === "object" && value !== null && !Array.isArray(value);
623
+ }
624
+ function isManagedJsonMcpServer(value) {
625
+ return isJsonObject(value) && value.url === resolveServerUrl();
626
+ }
627
+ async function writeJsonObject(path, value) {
628
+ await writeTextFileAtomic(path, `${JSON.stringify(value, null, 2)}\n`);
629
+ }
630
+ async function writeMarkedFile(options) {
631
+ let existing = await readTextFileIfExists(options.path);
632
+ const next = replaceMarkedBlock(existing, options.startMarker, options.endMarker, options.block);
633
+ if (next === null) {
634
+ existing = removeOrphanedMarkers(existing, options.startMarker, options.endMarker);
635
+ }
636
+ if (next === null && options.hasConflict?.(existing)) {
637
+ if (!options.force) {
638
+ throw new Error(options.conflictMessage ??
639
+ `Existing unmanaged configuration found in ${options.path}`);
640
+ }
641
+ existing = options.removeConflict
642
+ ? options.removeConflict(existing)
643
+ : existing;
644
+ }
645
+ await writeTextFileAtomic(options.path, next ?? appendMarkedBlock(existing, options.block));
646
+ }
647
+ async function removeMarkedFile(options) {
648
+ const existing = await readTextFileIfExists(options.path);
649
+ if (!existing) {
650
+ return;
651
+ }
652
+ const next = replaceMarkedBlock(existing, options.startMarker, options.endMarker, "") ??
653
+ removeOrphanedMarkers(existing, options.startMarker, options.endMarker);
654
+ if (next === existing) {
655
+ return;
656
+ }
657
+ await writeTextFileAtomic(options.path, next);
658
+ }
659
+ async function writeTextFileAtomic(path, content) {
660
+ const targetPath = await resolveAtomicWriteTarget(path);
661
+ await mkdir(dirname(targetPath), { recursive: true });
662
+ const mode = await fileModeIfExists(targetPath);
663
+ const temporaryPath = `${targetPath}.${process.pid}.${randomUUID()}.tmp`;
664
+ let temporaryFile;
665
+ try {
666
+ temporaryFile = await open(temporaryPath, "wx", mode);
667
+ await temporaryFile.writeFile(content, "utf8");
668
+ await temporaryFile.sync();
669
+ await temporaryFile.close();
670
+ temporaryFile = undefined;
671
+ if (mode !== undefined) {
672
+ await chmod(temporaryPath, mode);
673
+ }
674
+ await rename(temporaryPath, targetPath);
675
+ }
676
+ catch (error) {
677
+ await temporaryFile?.close().catch(() => undefined);
678
+ await unlink(temporaryPath).catch(() => undefined);
679
+ throw error;
680
+ }
681
+ }
682
+ async function resolveAtomicWriteTarget(path, visited = new Set()) {
683
+ const absolutePath = resolve(path);
684
+ if (visited.has(absolutePath)) {
685
+ throw new Error(`Cannot atomically write through circular symbolic link: ${path}`);
686
+ }
687
+ try {
688
+ const file = await lstat(absolutePath);
689
+ if (!file.isSymbolicLink()) {
690
+ return absolutePath;
691
+ }
692
+ visited.add(absolutePath);
693
+ const link = await readlink(absolutePath);
694
+ return resolveAtomicWriteTarget(resolve(dirname(absolutePath), link), visited);
695
+ }
696
+ catch (error) {
697
+ if (isNodeError(error) && error.code === "ENOENT") {
698
+ return absolutePath;
699
+ }
700
+ throw error;
701
+ }
702
+ }
703
+ async function fileModeIfExists(path) {
704
+ try {
705
+ return (await stat(path)).mode & 0o777;
706
+ }
707
+ catch (error) {
708
+ if (isNodeError(error) && error.code === "ENOENT") {
709
+ return undefined;
710
+ }
711
+ throw error;
712
+ }
713
+ }
714
+ async function readTextFileIfExists(path) {
715
+ try {
716
+ return await readFile(path, "utf8");
717
+ }
718
+ catch (error) {
719
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
720
+ return "";
721
+ }
722
+ throw error;
723
+ }
724
+ }
725
+ function isNodeError(error) {
726
+ return typeof error === "object" && error !== null && "code" in error;
727
+ }
728
+ function replaceMarkedBlock(existing, startMarker, endMarker, block) {
729
+ const lines = existing.split(/\r?\n/);
730
+ const markerLines = new Set();
731
+ const ranges = [];
732
+ let pendingStart;
733
+ for (const [index, line] of lines.entries()) {
734
+ const trimmed = line.trim();
735
+ if (trimmed === startMarker) {
736
+ markerLines.add(index);
737
+ pendingStart = index;
738
+ continue;
739
+ }
740
+ if (trimmed === endMarker) {
741
+ markerLines.add(index);
742
+ if (pendingStart !== undefined) {
743
+ ranges.push({ start: pendingStart, end: index });
744
+ pendingStart = undefined;
745
+ }
746
+ }
747
+ }
748
+ const first = ranges[0];
749
+ if (!first) {
750
+ return null;
751
+ }
752
+ const before = retainedMarkedLines(lines, 0, first.start, markerLines, [])
753
+ .join("\n")
754
+ .trimEnd();
755
+ const after = retainedMarkedLines(lines, first.end + 1, lines.length, markerLines, ranges.slice(1))
756
+ .join("\n")
757
+ .trim();
758
+ return ([before, block.trim(), after.trim()]
759
+ .filter((part) => part.length > 0)
760
+ .join("\n\n") + "\n");
761
+ }
762
+ function retainedMarkedLines(lines, start, end, markerLines, removedRanges) {
763
+ const retained = [];
764
+ for (let index = start; index < end; index += 1) {
765
+ if (markerLines.has(index)) {
766
+ continue;
767
+ }
768
+ if (removedRanges.some((range) => index >= range.start && index <= range.end)) {
769
+ continue;
770
+ }
771
+ retained.push(lines[index]);
772
+ }
773
+ return retained;
774
+ }
775
+ function removeOrphanedMarkers(existing, startMarker, endMarker) {
776
+ return (existing
777
+ .split(/\r?\n/)
778
+ .filter((line) => {
779
+ const trimmed = line.trim();
780
+ return trimmed !== startMarker && trimmed !== endMarker;
781
+ })
782
+ .join("\n")
783
+ .trimEnd() + "\n");
784
+ }
785
+ function appendMarkedBlock(existing, block) {
786
+ const prefix = existing.trimEnd();
787
+ return `${prefix.length > 0 ? `${prefix}\n\n` : ""}${block.trim()}\n`;
788
+ }
789
+ function hasCodexMcpServerConfig(existing) {
790
+ return existing.split(/\r?\n/).some((line) => {
791
+ const tableName = tomlTableName(line);
792
+ return tableName !== undefined && isCodexMcpServerTableName(tableName);
793
+ });
794
+ }
795
+ function removeCodexMcpServerConfig(existing) {
796
+ const lines = existing.split(/\r?\n/);
797
+ const kept = [];
798
+ let skipping = false;
799
+ for (const line of lines) {
800
+ const tableName = tomlTableName(line);
801
+ if (tableName !== undefined) {
802
+ skipping = isCodexMcpServerTableName(tableName);
803
+ }
804
+ if (!skipping) {
805
+ kept.push(line);
806
+ }
807
+ }
808
+ return kept.join("\n").trimEnd() + "\n";
809
+ }
810
+ function tomlTableName(line) {
811
+ return line.match(/^\s*\[([^\]]+)\]\s*(?:#.*)?$/)?.[1]?.trim();
812
+ }
813
+ function isCodexMcpServerTableName(tableName) {
814
+ return /^(?:mcp_servers|"mcp_servers"|'mcp_servers')\s*\.\s*(?:zvec_grep|"zvec_grep"|'zvec_grep')(?:\s*\.|$)/.test(tableName);
815
+ }
816
+ function codexConfigBlock(mcpToolTimeoutSeconds, tokenEnv) {
817
+ return `${ZVEC_GREP_CONFIG_START}
818
+ [mcp_servers.zvec_grep]
819
+ url = "${resolveServerUrl()}"
820
+ ${tokenEnv
821
+ ? `bearer_token_env_var = "${tokenEnv}"
822
+ `
823
+ : ""}tool_timeout_sec = ${mcpToolTimeoutSeconds}
824
+ default_tools_approval_mode = "approve"
825
+ ${ZVEC_GREP_CONFIG_END}`;
826
+ }
827
+ function agentGuidanceBlock(toolNames) {
828
+ const searchTool = toolNames?.search ?? "zvec_grep_search";
829
+ return `${ZVEC_GREP_AGENTS_START}
830
+ ## zvec-grep
831
+
832
+ Choose the initial search tool by the scope of the requested answer, not merely by whether the question contains an identifier.
833
+
834
+ Use native Grep or rg first when the answer can be obtained by locating a specific definition, reference, filename, configuration key, error message, literal, source fragment, or regex.
835
+
836
+ Use \`${searchTool}\` first when the answer requires architecture, lifecycle, system design, conceptual discovery, data or control flow, comparison across implementations, design rationale, or performance analysis.
837
+
838
+ When exact symbols are present but the answer spans multiple components, files, stages, or implementations, treat it as a mixed task: use \`${searchTool}\` with the concept and known symbols, then use native Grep or rg for focused follow-up.
839
+
840
+ Before using broad file reads or a sub-agent for conceptual repository discovery, make at least one appropriate \`${searchTool}\` call.
841
+
842
+ Do not launch a sub-agent solely to locate code. Stop discovery when the evidence covers all components requested by the question.
843
+ ${ZVEC_GREP_AGENTS_END}`;
844
+ }
845
+ //# sourceMappingURL=install.js.map