@zvec/zvec-grep 0.1.5 → 0.1.7

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 (358) hide show
  1. package/README.md +154 -236
  2. package/README_CN.md +142 -233
  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 +338 -55
  29. package/dist/cli/args.js.map +1 -1
  30. package/dist/cli/auth.d.ts +21 -0
  31. package/dist/cli/auth.js +209 -0
  32. package/dist/cli/auth.js.map +1 -0
  33. package/dist/cli/commands.js +469 -625
  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 +4 -0
  38. package/dist/cli/format/context.js +311 -44
  39. package/dist/cli/format/context.js.map +1 -1
  40. package/dist/cli/format/debug.js +12 -6
  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 +79 -6
  46. package/dist/cli/format/status.js +341 -111
  47. package/dist/cli/format/status.js.map +1 -1
  48. package/dist/cli/help.js +395 -63
  49. package/dist/cli/help.js.map +1 -1
  50. package/dist/cli/index.d.ts +1 -1
  51. package/dist/cli/index.js +1 -1
  52. package/dist/cli/install.d.ts +4 -0
  53. package/dist/cli/install.js +963 -0
  54. package/dist/cli/install.js.map +1 -0
  55. package/dist/cli/managed-rg.d.ts +10 -0
  56. package/dist/cli/managed-rg.js +329 -0
  57. package/dist/cli/managed-rg.js.map +1 -0
  58. package/dist/cli/server-search.d.ts +3 -0
  59. package/dist/cli/server-search.js +12 -0
  60. package/dist/cli/server-search.js.map +1 -0
  61. package/dist/cli/types.d.ts +23 -6
  62. package/dist/cli/types.js.map +1 -1
  63. package/dist/client/daemon-client.d.ts +31 -0
  64. package/dist/client/daemon-client.js +203 -0
  65. package/dist/client/daemon-client.js.map +1 -0
  66. package/dist/client/mode-router.d.ts +9 -0
  67. package/dist/client/mode-router.js +28 -0
  68. package/dist/client/mode-router.js.map +1 -0
  69. package/dist/client/search-policy.d.ts +11 -0
  70. package/dist/client/search-policy.js +15 -0
  71. package/dist/client/search-policy.js.map +1 -0
  72. package/dist/daemon/backend.d.ts +77 -0
  73. package/dist/daemon/backend.js +1087 -0
  74. package/dist/daemon/backend.js.map +1 -0
  75. package/dist/daemon/change-set.d.ts +25 -0
  76. package/dist/daemon/change-set.js +101 -0
  77. package/dist/daemon/change-set.js.map +1 -0
  78. package/dist/daemon/config.d.ts +24 -0
  79. package/dist/daemon/config.js +88 -0
  80. package/dist/daemon/config.js.map +1 -0
  81. package/dist/daemon/errors.d.ts +5 -0
  82. package/dist/daemon/errors.js +11 -0
  83. package/dist/daemon/errors.js.map +1 -0
  84. package/dist/daemon/http-server.d.ts +30 -0
  85. package/dist/daemon/http-server.js +288 -0
  86. package/dist/daemon/http-server.js.map +1 -0
  87. package/dist/daemon/index-coordinator.d.ts +24 -0
  88. package/dist/daemon/index-coordinator.js +68 -0
  89. package/dist/daemon/index-coordinator.js.map +1 -0
  90. package/dist/daemon/job-scheduler.d.ts +70 -0
  91. package/dist/daemon/job-scheduler.js +366 -0
  92. package/dist/daemon/job-scheduler.js.map +1 -0
  93. package/dist/daemon/logger.d.ts +9 -0
  94. package/dist/daemon/logger.js +53 -0
  95. package/dist/daemon/logger.js.map +1 -0
  96. package/dist/daemon/model-pool.d.ts +45 -0
  97. package/dist/daemon/model-pool.js +187 -0
  98. package/dist/daemon/model-pool.js.map +1 -0
  99. package/dist/daemon/root-lease.d.ts +14 -0
  100. package/dist/daemon/root-lease.js +188 -0
  101. package/dist/daemon/root-lease.js.map +1 -0
  102. package/dist/daemon/root-runtime.d.ts +78 -0
  103. package/dist/daemon/root-runtime.js +333 -0
  104. package/dist/daemon/root-runtime.js.map +1 -0
  105. package/dist/daemon/runtime-manager.d.ts +46 -0
  106. package/dist/daemon/runtime-manager.js +246 -0
  107. package/dist/daemon/runtime-manager.js.map +1 -0
  108. package/dist/daemon/runtime.d.ts +12 -0
  109. package/dist/daemon/runtime.js +102 -0
  110. package/dist/daemon/runtime.js.map +1 -0
  111. package/dist/daemon/server-controller.d.ts +39 -0
  112. package/dist/daemon/server-controller.js +254 -0
  113. package/dist/daemon/server-controller.js.map +1 -0
  114. package/dist/daemon/watch-manager.d.ts +50 -0
  115. package/dist/daemon/watch-manager.js +293 -0
  116. package/dist/daemon/watch-manager.js.map +1 -0
  117. package/dist/daemon/workspace-read-session-cache.d.ts +31 -0
  118. package/dist/daemon/workspace-read-session-cache.js +115 -0
  119. package/dist/daemon/workspace-read-session-cache.js.map +1 -0
  120. package/dist/engine/code-formats.d.ts +3 -0
  121. package/dist/engine/code-formats.js +14 -0
  122. package/dist/engine/code-formats.js.map +1 -0
  123. package/dist/engine/config.d.ts +30 -8
  124. package/dist/engine/config.js +171 -45
  125. package/dist/engine/config.js.map +1 -1
  126. package/dist/engine/{errors/index.d.ts → errors.d.ts} +6 -1
  127. package/dist/engine/{errors/details.js → errors.js} +17 -4
  128. package/dist/engine/errors.js.map +1 -0
  129. package/dist/engine/extraction/code/adapter.d.ts +1 -1
  130. package/dist/engine/extraction/code/adapter.js +1 -1
  131. package/dist/engine/extraction/code/adapter.js.map +1 -1
  132. package/dist/engine/extraction/code/extractor.d.ts +5 -11
  133. package/dist/engine/extraction/code/extractor.js +116 -48
  134. package/dist/engine/extraction/code/extractor.js.map +1 -1
  135. package/dist/engine/extraction/code/families/c-family.js +1 -1
  136. package/dist/engine/extraction/code/families/c-family.js.map +1 -1
  137. package/dist/engine/extraction/code/families/js-ts.d.ts +1 -1
  138. package/dist/engine/extraction/code/families/metadata.d.ts +1 -1
  139. package/dist/engine/extraction/code/tree-sitter/grammar.js.map +1 -0
  140. package/dist/engine/extraction/code/tree-sitter/nodes.js.map +1 -0
  141. package/dist/engine/extraction/code/tree-sitter/parser.js.map +1 -0
  142. package/dist/engine/extraction/image/extractor.d.ts +5 -0
  143. package/dist/engine/extraction/image/extractor.js +35 -0
  144. package/dist/engine/extraction/image/extractor.js.map +1 -0
  145. package/dist/engine/extraction/index.d.ts +4 -44
  146. package/dist/engine/extraction/index.js +2 -280
  147. package/dist/engine/extraction/index.js.map +1 -1
  148. package/dist/engine/extraction/markdown/extractor.d.ts +5 -11
  149. package/dist/engine/extraction/markdown/extractor.js +38 -17
  150. package/dist/engine/extraction/markdown/extractor.js.map +1 -1
  151. package/dist/engine/extraction/runtime.d.ts +4 -0
  152. package/dist/engine/extraction/runtime.js +26 -0
  153. package/dist/engine/extraction/runtime.js.map +1 -0
  154. package/dist/engine/extraction/source.d.ts +18 -0
  155. package/dist/engine/extraction/source.js +22 -0
  156. package/dist/engine/extraction/source.js.map +1 -0
  157. package/dist/engine/extraction/text/extractor.d.ts +7 -0
  158. package/dist/engine/extraction/text/extractor.js +168 -0
  159. package/dist/engine/extraction/text/extractor.js.map +1 -0
  160. package/dist/engine/extraction/types.d.ts +4 -0
  161. package/dist/engine/{models → extraction}/types.js.map +1 -1
  162. package/dist/engine/extraction/vector-content.d.ts +5 -0
  163. package/dist/engine/extraction/vector-content.js +95 -0
  164. package/dist/engine/extraction/vector-content.js.map +1 -0
  165. package/dist/engine/file-size-policy.d.ts +6 -0
  166. package/dist/engine/file-size-policy.js +20 -0
  167. package/dist/engine/file-size-policy.js.map +1 -0
  168. package/dist/engine/file-type.d.ts +15 -0
  169. package/dist/engine/file-type.js +152 -0
  170. package/dist/engine/file-type.js.map +1 -0
  171. package/dist/engine/index-status.d.ts +9 -0
  172. package/dist/engine/index-status.js +38 -0
  173. package/dist/engine/index-status.js.map +1 -0
  174. package/dist/engine/manifest.d.ts +13 -0
  175. package/dist/engine/manifest.js +124 -0
  176. package/dist/engine/manifest.js.map +1 -0
  177. package/dist/engine/models/{providers/llama-cpp/embedding.d.ts → backends/llama-cpp.d.ts} +25 -20
  178. package/dist/engine/models/{providers/llama-cpp/embedding.js → backends/llama-cpp.js} +127 -106
  179. package/dist/engine/models/backends/llama-cpp.js.map +1 -0
  180. package/dist/engine/models/backends/model2vec-runtime.d.ts +63 -0
  181. package/dist/engine/models/backends/model2vec-runtime.js +112 -0
  182. package/dist/engine/models/backends/model2vec-runtime.js.map +1 -0
  183. package/dist/engine/models/backends/model2vec-tokenizer.d.ts +2 -0
  184. package/dist/engine/models/backends/model2vec-tokenizer.js +42 -0
  185. package/dist/engine/models/backends/model2vec-tokenizer.js.map +1 -0
  186. package/dist/engine/models/backends/model2vec-worker-pool.d.ts +25 -0
  187. package/dist/engine/models/backends/model2vec-worker-pool.js +264 -0
  188. package/dist/engine/models/backends/model2vec-worker-pool.js.map +1 -0
  189. package/dist/engine/models/backends/model2vec-worker.d.ts +1 -0
  190. package/dist/engine/models/backends/model2vec-worker.js +41 -0
  191. package/dist/engine/models/backends/model2vec-worker.js.map +1 -0
  192. package/dist/engine/models/backends/model2vec.d.ts +40 -0
  193. package/dist/engine/models/backends/model2vec.js +311 -0
  194. package/dist/engine/models/backends/model2vec.js.map +1 -0
  195. package/dist/engine/models/backends/qwen.d.ts +44 -0
  196. package/dist/engine/models/{providers/qwen/embedding.js → backends/qwen.js} +155 -94
  197. package/dist/engine/models/backends/qwen.js.map +1 -0
  198. package/dist/engine/models/backends/transformers-js.d.ts +87 -0
  199. package/dist/engine/models/backends/transformers-js.js +316 -0
  200. package/dist/engine/models/backends/transformers-js.js.map +1 -0
  201. package/dist/engine/models/catalog.d.ts +207 -23
  202. package/dist/engine/models/catalog.js +191 -25
  203. package/dist/engine/models/catalog.js.map +1 -1
  204. package/dist/engine/models/download-progress.d.ts +15 -0
  205. package/dist/engine/models/download-progress.js +48 -0
  206. package/dist/engine/models/download-progress.js.map +1 -0
  207. package/dist/engine/models/embeddings.d.ts +59 -18
  208. package/dist/engine/models/embeddings.js +52 -28
  209. package/dist/engine/models/embeddings.js.map +1 -1
  210. package/dist/engine/models/factory.d.ts +2 -5
  211. package/dist/engine/models/factory.js +41 -56
  212. package/dist/engine/models/factory.js.map +1 -1
  213. package/dist/engine/models/index.d.ts +4 -6
  214. package/dist/engine/models/index.js +4 -4
  215. package/dist/engine/models/index.js.map +1 -1
  216. package/dist/engine/models/ranking.d.ts +7 -3
  217. package/dist/engine/models/resolution.d.ts +8 -0
  218. package/dist/engine/models/resolution.js +22 -0
  219. package/dist/engine/models/resolution.js.map +1 -0
  220. package/dist/engine/pipeline/indexing/index.d.ts +9 -7
  221. package/dist/engine/pipeline/indexing/index.js +409 -165
  222. package/dist/engine/pipeline/indexing/index.js.map +1 -1
  223. package/dist/engine/pipeline/indexing/input-budget.d.ts +2 -0
  224. package/dist/engine/pipeline/indexing/input-budget.js +51 -0
  225. package/dist/engine/pipeline/indexing/input-budget.js.map +1 -0
  226. package/dist/engine/pipeline/indexing/root-paths.js +6 -6
  227. package/dist/engine/pipeline/indexing/root-paths.js.map +1 -1
  228. package/dist/engine/pipeline/indexing/scanner/index.d.ts +9 -2
  229. package/dist/engine/pipeline/indexing/scanner/index.js +291 -35
  230. package/dist/engine/pipeline/indexing/scanner/index.js.map +1 -1
  231. package/dist/engine/pipeline/search/index.d.ts +6 -6
  232. package/dist/engine/pipeline/search/index.js +8 -10
  233. package/dist/engine/pipeline/search/index.js.map +1 -1
  234. package/dist/engine/service/index.d.ts +3 -2
  235. package/dist/engine/service/index.js +1 -1
  236. package/dist/engine/service/index.js.map +1 -1
  237. package/dist/engine/service/root.d.ts +10 -12
  238. package/dist/engine/service/root.js +29 -25
  239. package/dist/engine/service/root.js.map +1 -1
  240. package/dist/engine/service/structure-enrichment.d.ts +1 -1
  241. package/dist/engine/service/structure-enrichment.js +20 -22
  242. package/dist/engine/service/structure-enrichment.js.map +1 -1
  243. package/dist/engine/service/types.d.ts +40 -38
  244. package/dist/engine/service/workspace-index.d.ts +26 -0
  245. package/dist/engine/service/workspace-index.js +157 -0
  246. package/dist/engine/service/workspace-index.js.map +1 -0
  247. package/dist/engine/service/zvec-grep.d.ts +12 -1
  248. package/dist/engine/service/zvec-grep.js +698 -489
  249. package/dist/engine/service/zvec-grep.js.map +1 -1
  250. package/dist/engine/storage/index.d.ts +30 -20
  251. package/dist/engine/storage/index.js +2 -1
  252. package/dist/engine/storage/index.js.map +1 -1
  253. package/dist/engine/storage/layout.d.ts +10 -0
  254. package/dist/engine/storage/layout.js +29 -0
  255. package/dist/engine/storage/layout.js.map +1 -0
  256. package/dist/engine/storage/zvec.d.ts +4 -67
  257. package/dist/engine/storage/zvec.js +115 -85
  258. package/dist/engine/storage/zvec.js.map +1 -1
  259. package/dist/engine/types.d.ts +29 -23
  260. package/dist/engine/types.js +1 -1
  261. package/dist/engine/types.js.map +1 -1
  262. package/dist/engine/utils/daemon-lease.d.ts +17 -0
  263. package/dist/engine/utils/daemon-lease.js +175 -0
  264. package/dist/engine/utils/daemon-lease.js.map +1 -0
  265. package/dist/engine/utils/file-selection.js +38 -1
  266. package/dist/engine/utils/file-selection.js.map +1 -1
  267. package/dist/engine/utils/lock.js +1 -1
  268. package/dist/engine/utils/lock.js.map +1 -1
  269. package/dist/index-progress.d.ts +10 -0
  270. package/dist/index-progress.js +159 -0
  271. package/dist/index-progress.js.map +1 -0
  272. package/dist/index.d.ts +4 -4
  273. package/dist/index.js +1 -1
  274. package/dist/index.js.map +1 -1
  275. package/dist/mcp/http-transport.d.ts +27 -0
  276. package/dist/mcp/http-transport.js +182 -0
  277. package/dist/mcp/http-transport.js.map +1 -0
  278. package/dist/mcp/input-normalization.d.ts +38 -0
  279. package/dist/mcp/input-normalization.js +104 -0
  280. package/dist/mcp/input-normalization.js.map +1 -0
  281. package/dist/mcp/progress-heartbeat.d.ts +17 -0
  282. package/dist/mcp/progress-heartbeat.js +46 -0
  283. package/dist/mcp/progress-heartbeat.js.map +1 -0
  284. package/dist/mcp/request-metadata.d.ts +2 -0
  285. package/dist/mcp/request-metadata.js +11 -0
  286. package/dist/mcp/request-metadata.js.map +1 -0
  287. package/dist/mcp/request-state.d.ts +40 -0
  288. package/dist/mcp/request-state.js +210 -0
  289. package/dist/mcp/request-state.js.map +1 -0
  290. package/dist/mcp/result-format.d.ts +13 -0
  291. package/dist/mcp/result-format.js +75 -0
  292. package/dist/mcp/result-format.js.map +1 -0
  293. package/dist/mcp/schemas.d.ts +672 -0
  294. package/dist/mcp/schemas.js +506 -0
  295. package/dist/mcp/schemas.js.map +1 -0
  296. package/dist/mcp/stdio-bridge.d.ts +9 -0
  297. package/dist/mcp/stdio-bridge.js +131 -0
  298. package/dist/mcp/stdio-bridge.js.map +1 -0
  299. package/dist/mcp/tools.d.ts +153 -0
  300. package/dist/mcp/tools.js +482 -0
  301. package/dist/mcp/tools.js.map +1 -0
  302. package/dist/mcp/toolset.d.ts +5 -0
  303. package/dist/mcp/toolset.js +12 -0
  304. package/dist/mcp/toolset.js.map +1 -0
  305. package/dist/observability/trace-context.d.ts +11 -0
  306. package/dist/observability/trace-context.js +138 -0
  307. package/dist/observability/trace-context.js.map +1 -0
  308. package/dist/prompts/zvec-grep-guidance.d.ts +2 -0
  309. package/dist/prompts/zvec-grep-guidance.js +9 -0
  310. package/dist/prompts/zvec-grep-guidance.js.map +1 -0
  311. package/docs/01-agents.md +132 -0
  312. package/docs/02-cli.md +239 -0
  313. package/docs/03-mcp.md +185 -0
  314. package/docs/04-pipeline.md +226 -0
  315. package/docs/05-architecture.md +86 -0
  316. package/docs/06-server.md +215 -0
  317. package/docs/07-embedding.md +182 -0
  318. package/docs/08-roadmap.md +85 -0
  319. package/docs/README.md +53 -0
  320. package/package.json +20 -11
  321. package/dist/cli/mcp.d.ts +0 -2
  322. package/dist/cli/mcp.js +0 -354
  323. package/dist/cli/mcp.js.map +0 -1
  324. package/dist/engine/collection/index.d.ts +0 -55
  325. package/dist/engine/collection/index.js +0 -710
  326. package/dist/engine/collection/index.js.map +0 -1
  327. package/dist/engine/errors/details.d.ts +0 -6
  328. package/dist/engine/errors/details.js.map +0 -1
  329. package/dist/engine/errors/index.js +0 -16
  330. package/dist/engine/errors/index.js.map +0 -1
  331. package/dist/engine/extraction/tree-sitter/grammar.js.map +0 -1
  332. package/dist/engine/extraction/tree-sitter/nodes.js.map +0 -1
  333. package/dist/engine/extraction/tree-sitter/parser.js.map +0 -1
  334. package/dist/engine/files/file-type.d.ts +0 -5
  335. package/dist/engine/files/file-type.js +0 -119
  336. package/dist/engine/files/file-type.js.map +0 -1
  337. package/dist/engine/models/providers/index.d.ts +0 -2
  338. package/dist/engine/models/providers/index.js +0 -3
  339. package/dist/engine/models/providers/index.js.map +0 -1
  340. package/dist/engine/models/providers/llama-cpp/embedding.js.map +0 -1
  341. package/dist/engine/models/providers/llama-cpp/index.d.ts +0 -1
  342. package/dist/engine/models/providers/llama-cpp/index.js +0 -2
  343. package/dist/engine/models/providers/llama-cpp/index.js.map +0 -1
  344. package/dist/engine/models/providers/qwen/embedding.d.ts +0 -42
  345. package/dist/engine/models/providers/qwen/embedding.js.map +0 -1
  346. package/dist/engine/models/providers/qwen/index.d.ts +0 -1
  347. package/dist/engine/models/providers/qwen/index.js +0 -2
  348. package/dist/engine/models/providers/qwen/index.js.map +0 -1
  349. package/dist/engine/models/types.d.ts +0 -30
  350. package/skills/zvec-grep/SKILL.md +0 -151
  351. package/skills/zvec-grep/agents/openai.yaml +0 -4
  352. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.d.ts +0 -0
  353. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/grammar.js +0 -0
  354. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.d.ts +0 -0
  355. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/nodes.js +0 -0
  356. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.d.ts +0 -0
  357. /package/dist/engine/extraction/{tree-sitter → code/tree-sitter}/parser.js +0 -0
  358. /package/dist/engine/{models → extraction}/types.js +0 -0
@@ -1,29 +1,24 @@
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";
1
+ import { resolve } from "node:path";
5
2
  import { createInterface } from "node:readline/promises";
6
3
  import { createZvecGrep, } from "../index.js";
7
- import { globalConfigPath, updateGlobalConfigFromExplicitOptions, } from "../engine/config.js";
8
- import { findNearestAnonymousWorkspace } from "../engine/service/root.js";
9
- import { contextWarningLines, printAgentContextResult, printHumanContextResult, } from "./format/context.js";
4
+ import { globalConfigPath, updateGlobalConfig } from "../engine/config.js";
5
+ import { listEmbeddingModels } from "../engine/models/index.js";
6
+ import { DaemonClient } from "../client/daemon-client.js";
7
+ import { resolveDirectSearchPolicy, resolveServerSearchPolicy, } from "../client/search-policy.js";
8
+ import { resolveClientMode, resolveServerUrl, routeByMode, } from "../client/mode-router.js";
9
+ import { serverStatus } from "../daemon/server-controller.js";
10
+ import { findNearestWorkspace } from "../engine/service/root.js";
11
+ import { contextWarningLines, printCliContextResult, } from "./format/context.js";
10
12
  import { printDebug } from "./format/debug.js";
11
13
  import { createIndexProgressReporter } from "./format/progress.js";
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;
14
+ import { printWorkspaceInfo, printIndexPathFilterTip, printIndexResult, printIndexScanDiagnostics, printNoIndexableFilesTip, printServerIndexInfo, } from "./format/status.js";
15
+ import { planRemoteIndexAuthorization, planRemoteSearchAuthorization, } from "../authorization/index.js";
16
+ import { indexCompletionFromStatus, indexStatusNeedsRefresh, } from "../engine/index-status.js";
17
+ import { indexProgressFromMessage } from "../index-progress.js";
18
+ import { normalizeManagedRgInput } from "./managed-rg.js";
19
+ import { INCOMPATIBLE_SERVER_SEARCH_MESSAGE, parseServerSearchResponse, } from "./server-search.js";
20
+ import { runInstall, runUninstall } from "./install.js";
21
+ import { runAuth, authorizationStore, authorizeCliPlan, resolveAuthorizationSchema, embeddingModelInfo, configuredEmbeddingReference, workspaceRuntimeFromInfo, assertEmbeddingModelCompatible, assertRequestedEndpointCompatible, requireEmbeddingModelCatalogEntry, unsupportedRemoteEmbeddingProvider, withRemoteEmbeddingOperationPermit, } from "./auth.js";
27
22
  export async function runParsedCommand(parsed) {
28
23
  switch (parsed.command) {
29
24
  case "query":
@@ -35,174 +30,107 @@ export async function runParsedCommand(parsed) {
35
30
  case "status":
36
31
  await runStatus(parsed);
37
32
  return;
38
- case "collections":
39
- await runCollections(parsed);
40
- return;
41
33
  case "install":
42
34
  await runInstall(parsed);
43
35
  return;
44
36
  case "uninstall":
45
37
  await runUninstall(parsed);
46
38
  return;
47
- case "serve":
48
- await runServe(parsed);
39
+ case "config":
40
+ await runConfig(parsed);
41
+ return;
42
+ case "auth":
43
+ await runAuth(parsed);
44
+ return;
45
+ case "server":
46
+ await runServer(parsed);
49
47
  return;
50
48
  case "help":
51
49
  case "version":
52
50
  throw new Error(`${parsed.command} must be handled before dispatch`);
53
51
  }
54
52
  }
55
- async function runInstall(parsed) {
56
- const installers = await resolveInstallers(parsed, "install");
57
- if (installers.length === 0) {
58
- console.log("No agents selected.");
59
- return;
53
+ async function runConfig(parsed) {
54
+ if (parsed.positionals.length !== 1) {
55
+ throw new Error(`zg config ${parsed.options.configAction === "provider-set" ? "provider" : "model"} set requires exactly one reference`);
60
56
  }
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}`);
57
+ const reference = parsed.positionals[0];
58
+ if (parsed.options.configAction === "provider-set") {
59
+ if (!/^[a-z][a-z0-9_-]*$/.test(reference)) {
60
+ throw unsupportedRemoteEmbeddingProvider(reference, "Invalid embedding provider");
71
61
  }
72
- }
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.");
82
- return;
83
- }
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}`);
62
+ if (reference === "local" ||
63
+ !listEmbeddingModels().some((entry) => entry.provider === reference)) {
64
+ throw unsupportedRemoteEmbeddingProvider(reference);
65
+ }
66
+ if (parsed.options.apiKey === undefined) {
67
+ throw new Error("zg config provider set requires --api-key");
90
68
  }
69
+ updateGlobalConfig({
70
+ providers: {
71
+ [reference]: {
72
+ apiKey: parsed.options.apiKey,
73
+ },
74
+ },
75
+ });
76
+ console.log(`Provider config: ${reference}`);
77
+ console.log(`Global config: ${globalConfigPath()}`);
78
+ return;
91
79
  }
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,
80
+ if (parsed.options.configAction !== "model-set") {
81
+ throw new Error("zg config requires provider set or model set");
82
+ }
83
+ const catalogEntry = requireEmbeddingModelCatalogEntry(reference);
84
+ if (parsed.options.endpoint === undefined &&
85
+ parsed.options.device === undefined &&
86
+ !parsed.options.defaultModel) {
87
+ throw new Error("zg config model set requires --endpoint, --device, or --default");
88
+ }
89
+ if (catalogEntry.provider === "local" &&
90
+ parsed.options.endpoint !== undefined) {
91
+ throw new Error("--endpoint is only supported for remote embedding models");
92
+ }
93
+ if (catalogEntry.provider !== "local" &&
94
+ parsed.options.device !== undefined) {
95
+ throw new Error("--device is only supported for local embedding models");
96
+ }
97
+ if (parsed.options.endpoint !== undefined) {
98
+ assertHttpEndpoint(parsed.options.endpoint);
99
+ }
100
+ updateGlobalConfig({
101
+ ...(parsed.options.endpoint !== undefined ||
102
+ parsed.options.device !== undefined
103
+ ? {
104
+ models: {
105
+ [reference]: {
106
+ ...(parsed.options.endpoint !== undefined
107
+ ? { endpoint: parsed.options.endpoint }
108
+ : {}),
109
+ ...(parsed.options.device !== undefined
110
+ ? { device: parsed.options.device }
111
+ : {}),
112
+ },
113
+ },
114
+ }
115
+ : {}),
116
+ ...(parsed.options.defaultModel
117
+ ? { defaults: { embedding: reference } }
118
+ : {}),
130
119
  });
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);
120
+ console.log(`Model config: ${reference}`);
121
+ console.log(`Global config: ${globalConfigPath()}`);
147
122
  }
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
- });
123
+ function assertHttpEndpoint(endpoint) {
124
+ let parsed;
159
125
  try {
160
- const answer = await readline.question("Agents [codex]: ");
161
- const normalized = answer.trim();
162
- return installersFromTokens(normalized.length > 0 ? splitTargetTokens(normalized) : ["codex"]);
126
+ parsed = new URL(endpoint);
163
127
  }
164
- finally {
165
- readline.close();
128
+ catch {
129
+ throw new Error("--endpoint must be a valid HTTP(S) URL");
166
130
  }
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);
131
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
132
+ throw new Error("--endpoint must be a valid HTTP(S) URL");
198
133
  }
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);
206
134
  }
207
135
  async function runIndex(parsed) {
208
136
  const explicitRoot = parsed.positionals.length > 0;
@@ -215,11 +143,125 @@ async function runIndex(parsed) {
215
143
  await runDropIndex(parsed, rootPath.absolutePath);
216
144
  return;
217
145
  }
218
- const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, rootPath.absolutePath));
219
- const progress = createIndexProgressReporter();
146
+ if (parsed.options.embedding) {
147
+ requireEmbeddingModelCatalogEntry(parsed.options.embedding);
148
+ }
149
+ const mode = resolveClientMode(parsed.options.mode);
150
+ await routeByMode({
151
+ mode,
152
+ serverAvailable: () => daemonIsReady(parsed.options.home),
153
+ server: async () => {
154
+ const client = daemonClient(parsed.options);
155
+ const progress = createIndexProgressReporter({
156
+ color: parsed.options.color,
157
+ });
158
+ let result;
159
+ try {
160
+ result = await client.callTool("zvec_grep_index", {
161
+ root: rootPath.absolutePath,
162
+ embedding: parsed.options.embedding,
163
+ apiKey: parsed.options.apiKey,
164
+ endpoint: parsed.options.endpoint,
165
+ device: parsed.options.device,
166
+ rebuild: parsed.options.rebuild,
167
+ resetPaths: parsed.options.resetPaths,
168
+ globs: parsed.options.globs,
169
+ insensitiveGlobs: parsed.options.insensitiveGlobs,
170
+ fileTypes: parsed.options.fileTypes,
171
+ excludedFileTypes: parsed.options.excludedFileTypes,
172
+ hidden: parsed.options.hidden,
173
+ noIgnore: parsed.options.noIgnore,
174
+ ignoreFiles: parsed.options.ignoreFiles,
175
+ maxDepth: parsed.options.maxDepth,
176
+ maxFileSizeBytes: parsed.options.maxFileSizeBytes,
177
+ follow: parsed.options.follow,
178
+ embeddingConcurrency: parsed.options.embeddingConcurrency,
179
+ debug: parsed.options.debug,
180
+ wait: true,
181
+ }, {
182
+ onProgress: (event) => {
183
+ const update = indexProgressFromMessage(event.message);
184
+ if (update) {
185
+ progress.report(update.progress);
186
+ }
187
+ },
188
+ embeddingEnvironment: process.env.ZVEC_GREP_EMBEDDING?.trim(),
189
+ });
190
+ }
191
+ finally {
192
+ progress.finish();
193
+ }
194
+ console.log(`Workspace index: ${String(result.state ?? "submitted")}`);
195
+ console.log(`Root: ${String(result.root ?? rootPath.absolutePath)}`);
196
+ console.log(`Job: ${String(result.job_id ?? "unknown")}`);
197
+ if (parsed.options.debug) {
198
+ printIndexScanDiagnostics(result.scan_diagnostics);
199
+ }
200
+ if (result.state === "failed") {
201
+ throw new Error(serverIndexFailureMessage(result));
202
+ }
203
+ if (result.state === "succeeded") {
204
+ const status = (await client
205
+ .callTool("zvec_grep_index_status", {
206
+ root: rootPath.absolutePath,
207
+ })
208
+ .catch(() => undefined));
209
+ if (status?.persistent.files?.scanned === 0) {
210
+ printNoIndexableFilesTip(parsed.options);
211
+ }
212
+ }
213
+ },
214
+ direct: () => runDirectIndex(parsed, rootPath, explicitRoot),
215
+ });
216
+ }
217
+ function serverIndexFailureMessage(result) {
218
+ const error = result.error;
219
+ if (error && typeof error === "object") {
220
+ const code = error.code;
221
+ const message = error.message;
222
+ if (typeof message === "string" && message.length > 0) {
223
+ if (typeof code !== "string" ||
224
+ code.length === 0 ||
225
+ message.includes(`[${code}]`)) {
226
+ return message;
227
+ }
228
+ return `[${code}] ${message}`;
229
+ }
230
+ if (typeof code === "string" && code.length > 0) {
231
+ return `[${code}] Index job failed.`;
232
+ }
233
+ }
234
+ return `Index job ${String(result.job_id ?? "unknown")} failed. Run zg status --mode server for details.`;
235
+ }
236
+ async function runDirectIndex(parsed, rootPath, explicitRoot) {
237
+ const serviceOptions = createServiceOptions(parsed.options, rootPath.absolutePath);
238
+ const zvecGrep = await createZvecGrep(serviceOptions);
239
+ const progress = createIndexProgressReporter({ color: parsed.options.color });
220
240
  try {
241
+ const infoBefore = await zvecGrep.info({
242
+ root: rootPath.absolutePath,
243
+ includeStatus: parsed.options.rebuild !== true,
244
+ });
245
+ const schema = resolveAuthorizationSchema(configuredEmbeddingReference(parsed.options, infoBefore.workspaceIndex?.embedding), infoBefore.workspaceIndex?.embedding);
246
+ assertEmbeddingModelCompatible(infoBefore.workspaceIndex?.embedding, schema, parsed.options.rebuild === true);
247
+ const workspaceRuntime = workspaceRuntimeFromInfo(infoBefore);
248
+ assertRequestedEndpointCompatible(infoBefore, workspaceRuntime, parsed.options.endpoint, parsed.options.rebuild === true);
249
+ const modelInfo = schema?.provider === "qwen"
250
+ ? await embeddingModelInfo(schema, serviceOptions, workspaceRuntime)
251
+ : undefined;
252
+ const plan = modelInfo
253
+ ? await planRemoteIndexAuthorization({
254
+ info: infoBefore,
255
+ model: modelInfo,
256
+ rebuild: parsed.options.rebuild,
257
+ store: authorizationStore(parsed.options),
258
+ })
259
+ : undefined;
260
+ const authorizationResolution = plan
261
+ ? await authorizeCliPlan(plan, parsed.options)
262
+ : {};
221
263
  printIndexPathFilterTip(parsed.options);
222
- const result = await zvecGrep.index({
264
+ const result = await withRemoteEmbeddingOperationPermit(authorizationResolution.authorization, () => zvecGrep.index({
223
265
  root: rootPath.absolutePath,
224
266
  rootPaths: explicitRoot ? [rootPath] : undefined,
225
267
  rebuild: parsed.options.rebuild,
@@ -236,11 +278,10 @@ async function runIndex(parsed) {
236
278
  follow: parsed.options.follow,
237
279
  embeddingConcurrency: parsed.options.embeddingConcurrency,
238
280
  onProgress: progress.report,
239
- });
281
+ }));
240
282
  progress.finish();
241
283
  const info = await zvecGrep.info({ root: rootPath.absolutePath });
242
- printIndexResult("Indexed anonymous workspace", result, parsed.options, info.collection?.rootPaths);
243
- persistExplicitGlobalConfig(parsed.options, info.collection?.embedding?.provider);
284
+ printIndexResult("Workspace index", result, parsed.options, info.workspaceIndex?.rootPaths);
244
285
  }
245
286
  catch (error) {
246
287
  progress.finish();
@@ -255,14 +296,26 @@ async function runDropIndex(parsed, root) {
255
296
  console.log("Index drop cancelled.");
256
297
  return;
257
298
  }
258
- const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
259
- try {
260
- const removed = await zvecGrep.dropIndex({ root });
299
+ const printResult = (removed) => {
261
300
  console.log(removed ? `Dropped index for ${root}` : `No index found for ${root}`);
262
- }
263
- finally {
264
- await zvecGrep.close();
265
- }
301
+ };
302
+ await routeByMode({
303
+ mode: resolveClientMode(parsed.options.mode),
304
+ serverAvailable: () => daemonIsReady(parsed.options.home),
305
+ server: async () => {
306
+ const result = await daemonClient(parsed.options).callTool("zvec_grep_index_drop", { root });
307
+ printResult(result.removed === true);
308
+ },
309
+ direct: async () => {
310
+ const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
311
+ try {
312
+ printResult(await zvecGrep.dropIndex({ root }));
313
+ }
314
+ finally {
315
+ await zvecGrep.close();
316
+ }
317
+ },
318
+ });
266
319
  }
267
320
  async function confirmIndexDrop(root, accepted) {
268
321
  if (accepted) {
@@ -283,163 +336,89 @@ async function confirmIndexDrop(root, accepted) {
283
336
  readline.close();
284
337
  }
285
338
  }
286
- async function runServe(parsed) {
339
+ async function runServer(parsed) {
287
340
  if (parsed.positionals.length > 0) {
288
- throw new Error("zg serve --mcp does not accept positional arguments");
341
+ throw new Error(`zg server ${parsed.options.serverStdio ? "--stdio" : parsed.options.serverAction} does not accept positional arguments`);
342
+ }
343
+ const { readPackageVersion } = await import("./version.js");
344
+ if (parsed.options.serverStdio) {
345
+ const { runStdioBootstrapBridge } = await import("../mcp/stdio-bridge.js");
346
+ await runStdioBootstrapBridge({
347
+ cliPath: process.argv[1],
348
+ version: readPackageVersion(),
349
+ home: parsed.options.home,
350
+ tokenFile: parsed.options.serverTokenFile,
351
+ listen: parsed.options.listen,
352
+ mcpToolset: parsed.options.mcpToolset,
353
+ });
354
+ return;
289
355
  }
290
- const { runMcpServer } = await import("./mcp.js");
291
- await runMcpServer(createServiceOptions(parsed.options, process.cwd()));
356
+ if (parsed.options.serverAction === "on") {
357
+ const { startServer } = await import("../daemon/server-controller.js");
358
+ const status = await startServer({
359
+ cliPath: process.argv[1],
360
+ listen: parsed.options.listen,
361
+ tokenFile: parsed.options.serverTokenFile,
362
+ home: parsed.options.home,
363
+ mcpToolset: parsed.options.mcpToolset,
364
+ });
365
+ printServerControlStatus(status);
366
+ return;
367
+ }
368
+ if (parsed.options.serverAction === "off") {
369
+ const { stopServer } = await import("../daemon/server-controller.js");
370
+ printServerControlStatus(await stopServer(parsed.options.home, 30_000, parsed.options.serverTokenFile));
371
+ return;
372
+ }
373
+ if (parsed.options.serverAction === "status") {
374
+ const status = await serverStatus(parsed.options.home);
375
+ printServerControlStatus(status);
376
+ if (parsed.options.checkReady && !status.ready) {
377
+ throw new Error("zvec-grep server is not ready");
378
+ }
379
+ return;
380
+ }
381
+ const { runDaemonForeground } = await import("../daemon/runtime.js");
382
+ await runDaemonForeground({
383
+ version: readPackageVersion(),
384
+ listen: parsed.options.listen,
385
+ tokenFile: parsed.options.serverTokenFile,
386
+ home: parsed.options.home,
387
+ mcpToolset: parsed.options.mcpToolset,
388
+ serviceOptions: createServiceOptions(parsed.options, process.cwd()),
389
+ });
292
390
  }
293
391
  async function runStatus(parsed) {
294
392
  const root = parsed.positionals[0] ?? process.cwd();
295
393
  if (parsed.positionals.length > 1) {
296
394
  throw new Error("zg status accepts at most one root path");
297
395
  }
298
- const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
299
- try {
300
- const info = await zvecGrep.info({ root });
301
- printAnonymousInfo(info, parsed.options);
302
- }
303
- finally {
304
- await zvecGrep.close();
305
- }
306
- }
307
- async function runCollections(parsed) {
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
- }
314
- const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, undefined));
315
- try {
316
- if (action === "list") {
317
- if (parsed.options.resetPaths) {
318
- throw new Error("--reset-paths can only be used with zg collections index");
319
- }
320
- printCollectionList(await zvecGrep.collections.list(), parsed.options);
321
- return;
322
- }
323
- if (action === "info") {
324
- if (parsed.options.resetPaths) {
325
- throw new Error("--reset-paths can only be used with zg collections index");
326
- }
327
- if (!name) {
328
- throw new Error("zg collections info requires <name>");
329
- }
330
- const [info, status] = await Promise.all([
331
- zvecGrep.collections.info(name),
332
- zvecGrep.collections.status(name),
333
- ]);
334
- if (!info) {
335
- throw new Error(`Collection not found: ${name}`);
336
- }
337
- printCollectionInfo(info, status, parsed.options);
338
- return;
339
- }
340
- if (action === "index") {
341
- if (!name) {
342
- throw new Error("zg collections index requires <name>");
343
- }
344
- const explicitRoot = root !== undefined;
345
- const rootPath = indexRootPath(root ?? process.cwd(), parsed.options);
346
- const rootPaths = explicitRoot ? rootPath : undefined;
347
- const progress = createIndexProgressReporter();
396
+ const mode = resolveClientMode(parsed.options.mode);
397
+ const state = await routeByMode({
398
+ mode,
399
+ serverAvailable: () => daemonIsReady(parsed.options.home),
400
+ server: async () => {
401
+ const result = await daemonClient(parsed.options).callTool("zvec_grep_index_status", { root: resolve(root) });
402
+ return printServerIndexInfo(result, parsed.options);
403
+ },
404
+ direct: async () => {
405
+ const zvecGrep = await createZvecGrep(createServiceOptions(parsed.options, root));
348
406
  try {
349
- const result = await zvecGrep.collections.index(name, rootPaths, {
350
- rebuild: parsed.options.rebuild,
351
- resetPaths: parsed.options.resetPaths,
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,
362
- embeddingConcurrency: parsed.options.embeddingConcurrency,
363
- onProgress: progress.report,
364
- });
365
- progress.finish();
366
- const info = await zvecGrep.collections.info(name);
367
- printIndexResult(`Indexed collection ${name}`, result, parsed.options, info?.rootPaths);
368
- persistExplicitGlobalConfig(parsed.options, info?.embedding?.provider);
407
+ return printWorkspaceInfo(await zvecGrep.info({ root }), parsed.options);
369
408
  }
370
- catch (error) {
371
- progress.finish();
372
- throw error;
373
- }
374
- return;
375
- }
376
- if (action === "remove") {
377
- if (parsed.options.resetPaths) {
378
- throw new Error("--reset-paths can only be used with zg collections index");
409
+ finally {
410
+ await zvecGrep.close();
379
411
  }
380
- if (!name) {
381
- throw new Error("zg collections remove requires <name>");
382
- }
383
- const removed = await zvecGrep.collections.remove(name);
384
- printCollectionRemoveResult(name, removed, parsed.options);
385
- return;
386
- }
387
- if (parsed.options.resetPaths) {
388
- throw new Error("--reset-paths can only be used with zg collections index");
389
- }
390
- throw new Error(`Unknown collections action: ${action}`);
391
- }
392
- finally {
393
- await zvecGrep.close();
394
- }
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;
412
+ },
413
+ });
414
+ if (parsed.options.checkReady && state !== "ready") {
415
+ throw new Error(`Workspace index is not ready (state: ${state})`);
414
416
  }
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
417
  }
441
418
  async function runQuery(parsed) {
442
- const rgInput = parsed.options.rg ? normalizeRgInput(parsed) : undefined;
419
+ const rgInput = parsed.options.rg
420
+ ? normalizeManagedRgInput(parsed)
421
+ : undefined;
443
422
  const commandOptions = rgInput?.options ?? parsed.options;
444
423
  const queries = (rgInput?.queries ?? [
445
424
  ...parsed.positionals,
@@ -455,24 +434,64 @@ async function runQuery(parsed) {
455
434
  ? "zg query --rg requires a pattern. Use zg help query for examples."
456
435
  : "zg query requires text or --hybrid/--fts/--vector routes. Use zg help query for examples.");
457
436
  }
458
- const zvecGrep = await createZvecGrep(createServiceOptions(commandOptions, undefined));
459
- const progress = createIndexProgressReporter();
437
+ if (!commandOptions.rg) {
438
+ const mode = resolveClientMode(commandOptions.mode);
439
+ if (mode !== "direct") {
440
+ await routeByMode({
441
+ mode,
442
+ serverAvailable: () => daemonIsReady(commandOptions.home),
443
+ server: () => runServerQuery(commandOptions, queries, routes),
444
+ direct: () => runDirectQuery(commandOptions, queries),
445
+ });
446
+ return;
447
+ }
448
+ }
449
+ await runDirectQuery(commandOptions, queries);
450
+ }
451
+ async function runDirectQuery(commandOptions, queries) {
452
+ if (commandOptions.refresh === "background") {
453
+ console.error("warning: --refresh background requires Server mode; Direct mode uses --refresh off");
454
+ }
455
+ const serviceOptions = createServiceOptions(commandOptions, undefined);
456
+ const zvecGrep = await createZvecGrep(serviceOptions);
457
+ const progress = createIndexProgressReporter({
458
+ color: commandOptions.color,
459
+ });
460
460
  try {
461
- const result = await zvecGrep.context(contextOptions(commandOptions, queries, (progressEvent) => {
462
- if (progressEvent.phase !== "done") {
461
+ const contextRequest = contextOptions(commandOptions, queries, (progressEvent) => {
462
+ if (progressEvent.phase !== "done")
463
463
  progress.report(progressEvent);
464
- }
465
- }));
464
+ });
465
+ const info = await directQueryInfo(zvecGrep);
466
+ const schema = info.workspaceIndex?.embedding;
467
+ const workspaceRuntime = workspaceRuntimeFromInfo(info);
468
+ const modelInfo = !commandOptions.rg && schema?.provider === "qwen"
469
+ ? await embeddingModelInfo(schema, createServiceOptions(commandOptions, info.root), workspaceRuntime)
470
+ : undefined;
471
+ const plan = modelInfo
472
+ ? await planRemoteSearchAuthorization({
473
+ info,
474
+ model: modelInfo,
475
+ search: normalizedDirectSearchInput(commandOptions, queries, info.root),
476
+ store: authorizationStore(commandOptions),
477
+ })
478
+ : undefined;
479
+ const authorizationResolution = plan
480
+ ? await authorizeCliPlan(plan, commandOptions, "local_search")
481
+ : {};
482
+ const effectiveContextRequest = authorizationResolution.alternative === "local_search"
483
+ ? ftsFallbackContextRequest(contextRequest)
484
+ : contextRequest;
485
+ const result = await withRemoteEmbeddingOperationPermit(authorizationResolution.authorization, () => zvecGrep.context(effectiveContextRequest));
466
486
  progress.finish();
467
- if (commandOptions.human) {
468
- printHumanContextResult(result, commandOptions);
469
- }
470
- else {
471
- printAgentContextResult(result, commandOptions);
472
- }
487
+ printCliContextResult(result, commandOptions);
473
488
  for (const line of contextWarningLines(result)) {
474
489
  console.error(line);
475
490
  }
491
+ if (effectiveContextRequest.autoUpdate !== true &&
492
+ indexStatusNeedsRefresh(info.status)) {
493
+ printStaleIndexStatus("idle", indexCompletionFromStatus(info.status));
494
+ }
476
495
  if (commandOptions.debug) {
477
496
  printDebug(result, {
478
497
  trace: commandOptions.trace === true,
@@ -487,7 +506,113 @@ async function runQuery(parsed) {
487
506
  await zvecGrep.close();
488
507
  }
489
508
  }
509
+ async function runServerQuery(options, queries, routes) {
510
+ const searchPolicy = resolveServerSearchPolicy(options);
511
+ const structuredContent = await daemonClient(options).callTool("zvec_grep_search", {
512
+ root: resolve(process.cwd()),
513
+ apiKey: options.apiKey,
514
+ device: options.device,
515
+ queries: queries.length ? queries : undefined,
516
+ routes: routes.length ? routes : undefined,
517
+ fuse: options.fuse,
518
+ limit: options.limit,
519
+ trace: options.trace,
520
+ preferSymbol: options.preferSymbol,
521
+ symbolTypes: options.symbolTypes,
522
+ globs: options.globs,
523
+ insensitiveGlobs: options.insensitiveGlobs,
524
+ fileTypes: options.fileTypes,
525
+ excludedFileTypes: options.excludedFileTypes,
526
+ hidden: options.hidden,
527
+ noIgnore: options.noIgnore,
528
+ ignoreFiles: options.ignoreFiles,
529
+ maxDepth: options.maxDepth,
530
+ maxFileSizeBytes: options.maxFileSizeBytes,
531
+ follow: options.follow,
532
+ embeddingConcurrency: options.embeddingConcurrency,
533
+ modifiedAfter: options.modifiedAfter,
534
+ modifiedBefore: options.modifiedBefore,
535
+ freshness: searchPolicy.freshness,
536
+ autoUpdate: searchPolicy.autoUpdate,
537
+ }, {
538
+ toolContract: {
539
+ inputProperties: ["routes"],
540
+ outputProperties: ["result"],
541
+ errorMessage: INCOMPATIBLE_SERVER_SEARCH_MESSAGE,
542
+ },
543
+ });
544
+ const response = parseServerSearchResponse(structuredContent);
545
+ printCliContextResult(response.result, options);
546
+ for (const line of contextWarningLines(response.result)) {
547
+ console.error(line);
548
+ }
549
+ if (response.freshness === "possibly_stale") {
550
+ printStaleIndexStatus(response.indexing?.state, response.indexing);
551
+ }
552
+ if (options.debug) {
553
+ printDebug(response.result, { trace: options.trace === true });
554
+ }
555
+ }
556
+ function printStaleIndexStatus(state, completion) {
557
+ console.error("status: possibly_stale");
558
+ if (!state)
559
+ return;
560
+ const progress = completion?.completed === undefined || completion.total === undefined
561
+ ? ""
562
+ : ` (${completion.completed}/${completion.total})`;
563
+ console.error("results: served_from_current_index");
564
+ console.error(`background_refresh: ${state}${progress}`);
565
+ }
566
+ function daemonClient(options) {
567
+ return new DaemonClient({
568
+ serverUrl: resolveServerUrl(),
569
+ home: options.home,
570
+ tokenFile: options.serverTokenFile,
571
+ allowRemote: options.allowRemote,
572
+ });
573
+ }
574
+ function ftsFallbackContextRequest(request) {
575
+ const queries = [
576
+ ...(request.queries ?? []),
577
+ ...(request.query ? [request.query] : []),
578
+ ...(request.routes ?? []).map((route) => route.query),
579
+ ];
580
+ return {
581
+ ...request,
582
+ query: undefined,
583
+ queries: undefined,
584
+ routes: queries.map((query) => ({ mode: "fts", query })),
585
+ autoUpdate: false,
586
+ };
587
+ }
588
+ async function directQueryInfo(service) {
589
+ return await service.info({ root: process.cwd() });
590
+ }
591
+ function normalizedDirectSearchInput(options, queries, root) {
592
+ const policy = resolveDirectSearchPolicy(options);
593
+ return {
594
+ root,
595
+ apiKey: options.apiKey,
596
+ device: options.device,
597
+ queries: !options.rg && queries.length > 0 ? [...queries] : undefined,
598
+ routes: [...(options.routes ?? [])],
599
+ ...policy,
600
+ };
601
+ }
602
+ async function daemonIsReady(home) {
603
+ return (await serverStatus(home)).ready;
604
+ }
605
+ function printServerControlStatus(status) {
606
+ console.log(`Server: ${status.running ? (status.ready ? "ready" : "starting") : "stopped"}`);
607
+ if (status.pid)
608
+ console.log(`PID: ${status.pid}`);
609
+ if (status.serverUrl)
610
+ console.log(`URL: ${status.serverUrl}`);
611
+ if (status.mcpToolset)
612
+ console.log(`MCP toolset: ${status.mcpToolset}`);
613
+ }
490
614
  function contextOptions(options, queries, onAutoUpdateProgress) {
615
+ const policy = resolveDirectSearchPolicy(options);
491
616
  return {
492
617
  queries: queries.length > 0 ? queries : undefined,
493
618
  rg: options.rg,
@@ -495,9 +620,8 @@ function contextOptions(options, queries, onAutoUpdateProgress) {
495
620
  rgPaths: options.rgPaths,
496
621
  routes: options.routes,
497
622
  fuse: options.fuse,
498
- collection: options.collection,
499
623
  limit: options.limit,
500
- autoUpdate: !options.noAutoUpdate,
624
+ autoUpdate: policy.autoUpdate,
501
625
  onAutoUpdateProgress,
502
626
  trace: options.trace,
503
627
  preferSymbol: options.preferSymbol,
@@ -517,303 +641,23 @@ function contextOptions(options, queries, onAutoUpdateProgress) {
517
641
  embeddingConcurrency: options.embeddingConcurrency,
518
642
  };
519
643
  }
520
- function normalizeRgInput(parsed) {
521
- const explicitPatterns = parsed.options.rgOptions?.patterns ?? [];
522
- const hasPatternFiles = (parsed.options.rgOptions?.patternFiles?.length ?? 0) > 0;
523
- const queries = explicitPatterns.length > 0 || hasPatternFiles
524
- ? explicitPatterns
525
- : parsed.positionals.slice(0, 1);
526
- const paths = explicitPatterns.length > 0 || hasPatternFiles
527
- ? parsed.positionals
528
- : parsed.positionals.slice(1);
529
- return {
530
- queries,
531
- options: {
532
- ...parsed.options,
533
- rgPaths: paths.length > 0 ? paths : undefined,
534
- },
535
- };
536
- }
537
644
  export function createServiceOptions(options, root) {
538
- const embedding = options.embedding ?? process.env.ZVEC_GREP_EMBEDDING;
539
- const apiKey = options.apiKey ??
540
- process.env.ZVEC_GREP_API_KEY ??
541
- process.env.DASHSCOPE_API_KEY ??
542
- process.env.QWEN_API_KEY;
543
- const endpoint = options.endpoint ?? process.env.ZVEC_GREP_ENDPOINT;
544
645
  return {
545
646
  root,
546
647
  home: options.home ?? process.env.ZVEC_GREP_HOME,
547
- embedding,
548
- apiKey,
549
- endpoint,
550
- modelCacheDir: options.modelCacheDir ?? process.env.ZVEC_GREP_MODEL_CACHE,
551
- llamaGpu: options.llamaGpu ?? parseEnvLlamaGpu(process.env.ZVEC_GREP_LLAMA_GPU),
552
- embeddingParallelism: options.embeddingParallelism ??
553
- parseEnvPositiveInteger(process.env.ZVEC_GREP_EMBED_PARALLELISM),
648
+ embedding: options.embedding,
649
+ apiKey: options.apiKey,
650
+ endpoint: options.endpoint,
651
+ modelCacheDir: options.modelCacheDir,
652
+ device: options.device,
653
+ authorizationSigningKeyPath: process.env.ZVEC_GREP_AUTHORIZATION_KEY_FILE,
554
654
  };
555
655
  }
556
- function persistExplicitGlobalConfig(options, indexedProvider) {
557
- if (!updateGlobalConfigFromExplicitOptions(options, indexedProvider)) {
558
- return;
559
- }
560
- console.log(`Global config: ${globalConfigPath()}`);
561
- }
562
- function parseEnvLlamaGpu(value) {
563
- const normalized = value?.trim().toLowerCase() ?? "";
564
- if (!normalized) {
565
- return undefined;
566
- }
567
- if (normalized === "auto" ||
568
- normalized === "metal" ||
569
- normalized === "vulkan" ||
570
- normalized === "cuda") {
571
- return normalized;
572
- }
573
- if (["false", "off", "none", "disable", "disabled", "0"].includes(normalized)) {
574
- return false;
575
- }
576
- return undefined;
577
- }
578
- function parseEnvPositiveInteger(value) {
579
- const normalized = value?.trim() ?? "";
580
- if (!/^\d+$/.test(normalized)) {
581
- return undefined;
582
- }
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}`;
811
- }
812
656
  function resolveIndexRoot(root) {
813
657
  if (root !== undefined) {
814
658
  return root;
815
659
  }
816
- return findNearestAnonymousWorkspace(process.cwd())?.root ?? process.cwd();
660
+ return findNearestWorkspace(process.cwd())?.root ?? process.cwd();
817
661
  }
818
662
  function indexRootPath(path, options) {
819
663
  return {