@untangle-code/cli 0.0.0-stage → 0.1.1

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 (571) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +90 -0
  3. package/README.md +451 -2
  4. package/THIRD_PARTY_LICENSES.md +152 -0
  5. package/dist/cli/args.d.ts +48 -0
  6. package/dist/cli/args.d.ts.map +1 -0
  7. package/dist/cli/args.js +167 -0
  8. package/dist/cli/args.js.map +1 -0
  9. package/dist/cli/command.d.ts +69 -0
  10. package/dist/cli/command.d.ts.map +1 -0
  11. package/dist/cli/command.js +82 -0
  12. package/dist/cli/command.js.map +1 -0
  13. package/dist/cli/deadline.d.ts +33 -0
  14. package/dist/cli/deadline.d.ts.map +1 -0
  15. package/dist/cli/deadline.js +49 -0
  16. package/dist/cli/deadline.js.map +1 -0
  17. package/dist/cli/embedder-deadline.d.ts +72 -0
  18. package/dist/cli/embedder-deadline.d.ts.map +1 -0
  19. package/dist/cli/embedder-deadline.js +117 -0
  20. package/dist/cli/embedder-deadline.js.map +1 -0
  21. package/dist/cli/exit.d.ts +71 -0
  22. package/dist/cli/exit.d.ts.map +1 -0
  23. package/dist/cli/exit.js +81 -0
  24. package/dist/cli/exit.js.map +1 -0
  25. package/dist/cli/graphs.d.ts +65 -0
  26. package/dist/cli/graphs.d.ts.map +1 -0
  27. package/dist/cli/graphs.js +108 -0
  28. package/dist/cli/graphs.js.map +1 -0
  29. package/dist/cli/index-freshness.d.ts +13 -0
  30. package/dist/cli/index-freshness.d.ts.map +1 -0
  31. package/dist/cli/index-freshness.js +226 -0
  32. package/dist/cli/index-freshness.js.map +1 -0
  33. package/dist/cli/index-refresh.d.ts +10 -0
  34. package/dist/cli/index-refresh.d.ts.map +1 -0
  35. package/dist/cli/index-refresh.js +76 -0
  36. package/dist/cli/index-refresh.js.map +1 -0
  37. package/dist/cli/index-state.d.ts +184 -0
  38. package/dist/cli/index-state.d.ts.map +1 -0
  39. package/dist/cli/index-state.js +852 -0
  40. package/dist/cli/index-state.js.map +1 -0
  41. package/dist/cli/io.d.ts +29 -0
  42. package/dist/cli/io.d.ts.map +1 -0
  43. package/dist/cli/io.js +42 -0
  44. package/dist/cli/io.js.map +1 -0
  45. package/dist/cli/language-support.d.ts +77 -0
  46. package/dist/cli/language-support.d.ts.map +1 -0
  47. package/dist/cli/language-support.js +152 -0
  48. package/dist/cli/language-support.js.map +1 -0
  49. package/dist/cli/renewing-lease.d.ts +26 -0
  50. package/dist/cli/renewing-lease.d.ts.map +1 -0
  51. package/dist/cli/renewing-lease.js +102 -0
  52. package/dist/cli/renewing-lease.js.map +1 -0
  53. package/dist/cli/search-graph-enrichment.d.ts +16 -0
  54. package/dist/cli/search-graph-enrichment.d.ts.map +1 -0
  55. package/dist/cli/search-graph-enrichment.js +428 -0
  56. package/dist/cli/search-graph-enrichment.js.map +1 -0
  57. package/dist/cli/system.d.ts +34 -0
  58. package/dist/cli/system.d.ts.map +1 -0
  59. package/dist/cli/system.js +89 -0
  60. package/dist/cli/system.js.map +1 -0
  61. package/dist/cli/vector-store-policy.d.ts +116 -0
  62. package/dist/cli/vector-store-policy.d.ts.map +1 -0
  63. package/dist/cli/vector-store-policy.js +160 -0
  64. package/dist/cli/vector-store-policy.js.map +1 -0
  65. package/dist/cli/version.d.ts +3 -0
  66. package/dist/cli/version.d.ts.map +1 -0
  67. package/dist/cli/version.js +3 -0
  68. package/dist/cli/version.js.map +1 -0
  69. package/dist/cli/workspace.d.ts +105 -0
  70. package/dist/cli/workspace.d.ts.map +1 -0
  71. package/dist/cli/workspace.js +215 -0
  72. package/dist/cli/workspace.js.map +1 -0
  73. package/dist/commands/complexity.d.ts +72 -0
  74. package/dist/commands/complexity.d.ts.map +1 -0
  75. package/dist/commands/complexity.js +580 -0
  76. package/dist/commands/complexity.js.map +1 -0
  77. package/dist/commands/doctor.d.ts +66 -0
  78. package/dist/commands/doctor.d.ts.map +1 -0
  79. package/dist/commands/doctor.js +764 -0
  80. package/dist/commands/doctor.js.map +1 -0
  81. package/dist/commands/doctor.languages.d.ts +37 -0
  82. package/dist/commands/doctor.languages.d.ts.map +1 -0
  83. package/dist/commands/doctor.languages.js +143 -0
  84. package/dist/commands/doctor.languages.js.map +1 -0
  85. package/dist/commands/doctor.storage.d.ts +17 -0
  86. package/dist/commands/doctor.storage.d.ts.map +1 -0
  87. package/dist/commands/doctor.storage.js +91 -0
  88. package/dist/commands/doctor.storage.js.map +1 -0
  89. package/dist/commands/extensions/add.d.ts +10 -0
  90. package/dist/commands/extensions/add.d.ts.map +1 -0
  91. package/dist/commands/extensions/add.js +213 -0
  92. package/dist/commands/extensions/add.js.map +1 -0
  93. package/dist/commands/extensions/configure.d.ts +5 -0
  94. package/dist/commands/extensions/configure.d.ts.map +1 -0
  95. package/dist/commands/extensions/configure.js +58 -0
  96. package/dist/commands/extensions/configure.js.map +1 -0
  97. package/dist/commands/extensions/container.d.ts +15 -0
  98. package/dist/commands/extensions/container.d.ts.map +1 -0
  99. package/dist/commands/extensions/container.js +135 -0
  100. package/dist/commands/extensions/container.js.map +1 -0
  101. package/dist/commands/extensions/context.d.ts +37 -0
  102. package/dist/commands/extensions/context.d.ts.map +1 -0
  103. package/dist/commands/extensions/context.js +72 -0
  104. package/dist/commands/extensions/context.js.map +1 -0
  105. package/dist/commands/extensions/enable.d.ts +6 -0
  106. package/dist/commands/extensions/enable.d.ts.map +1 -0
  107. package/dist/commands/extensions/enable.js +180 -0
  108. package/dist/commands/extensions/enable.js.map +1 -0
  109. package/dist/commands/extensions/environment.d.ts +74 -0
  110. package/dist/commands/extensions/environment.d.ts.map +1 -0
  111. package/dist/commands/extensions/environment.js +168 -0
  112. package/dist/commands/extensions/environment.js.map +1 -0
  113. package/dist/commands/extensions/feature-scan.d.ts +48 -0
  114. package/dist/commands/extensions/feature-scan.d.ts.map +1 -0
  115. package/dist/commands/extensions/feature-scan.js +156 -0
  116. package/dist/commands/extensions/feature-scan.js.map +1 -0
  117. package/dist/commands/extensions/invoke.d.ts +60 -0
  118. package/dist/commands/extensions/invoke.d.ts.map +1 -0
  119. package/dist/commands/extensions/invoke.js +275 -0
  120. package/dist/commands/extensions/invoke.js.map +1 -0
  121. package/dist/commands/extensions/list.d.ts +5 -0
  122. package/dist/commands/extensions/list.d.ts.map +1 -0
  123. package/dist/commands/extensions/list.js +125 -0
  124. package/dist/commands/extensions/list.js.map +1 -0
  125. package/dist/commands/extensions/logs.d.ts +5 -0
  126. package/dist/commands/extensions/logs.d.ts.map +1 -0
  127. package/dist/commands/extensions/logs.js +74 -0
  128. package/dist/commands/extensions/logs.js.map +1 -0
  129. package/dist/commands/extensions/provision.d.ts +36 -0
  130. package/dist/commands/extensions/provision.d.ts.map +1 -0
  131. package/dist/commands/extensions/provision.js +137 -0
  132. package/dist/commands/extensions/provision.js.map +1 -0
  133. package/dist/commands/extensions/remove.d.ts +5 -0
  134. package/dist/commands/extensions/remove.d.ts.map +1 -0
  135. package/dist/commands/extensions/remove.js +77 -0
  136. package/dist/commands/extensions/remove.js.map +1 -0
  137. package/dist/commands/extensions/render.d.ts +16 -0
  138. package/dist/commands/extensions/render.d.ts.map +1 -0
  139. package/dist/commands/extensions/render.js +25 -0
  140. package/dist/commands/extensions/render.js.map +1 -0
  141. package/dist/commands/extensions/run.d.ts +30 -0
  142. package/dist/commands/extensions/run.d.ts.map +1 -0
  143. package/dist/commands/extensions/run.js +292 -0
  144. package/dist/commands/extensions/run.js.map +1 -0
  145. package/dist/commands/extensions/secret-store.d.ts +15 -0
  146. package/dist/commands/extensions/secret-store.d.ts.map +1 -0
  147. package/dist/commands/extensions/secret-store.js +164 -0
  148. package/dist/commands/extensions/secret-store.js.map +1 -0
  149. package/dist/commands/extensions/setup.d.ts +17 -0
  150. package/dist/commands/extensions/setup.d.ts.map +1 -0
  151. package/dist/commands/extensions/setup.js +94 -0
  152. package/dist/commands/extensions/setup.js.map +1 -0
  153. package/dist/commands/extensions/source.d.ts +47 -0
  154. package/dist/commands/extensions/source.d.ts.map +1 -0
  155. package/dist/commands/extensions/source.js +142 -0
  156. package/dist/commands/extensions/source.js.map +1 -0
  157. package/dist/commands/extensions/state.d.ts +62 -0
  158. package/dist/commands/extensions/state.d.ts.map +1 -0
  159. package/dist/commands/extensions/state.js +177 -0
  160. package/dist/commands/extensions/state.js.map +1 -0
  161. package/dist/commands/extensions/status.d.ts +9 -0
  162. package/dist/commands/extensions/status.d.ts.map +1 -0
  163. package/dist/commands/extensions/status.js +239 -0
  164. package/dist/commands/extensions/status.js.map +1 -0
  165. package/dist/commands/extensions.d.ts +3 -0
  166. package/dist/commands/extensions.d.ts.map +1 -0
  167. package/dist/commands/extensions.js +223 -0
  168. package/dist/commands/extensions.js.map +1 -0
  169. package/dist/commands/flow/index.d.ts +3 -0
  170. package/dist/commands/flow/index.d.ts.map +1 -0
  171. package/dist/commands/flow/index.js +295 -0
  172. package/dist/commands/flow/index.js.map +1 -0
  173. package/dist/commands/flow/limits.d.ts +12 -0
  174. package/dist/commands/flow/limits.d.ts.map +1 -0
  175. package/dist/commands/flow/limits.js +13 -0
  176. package/dist/commands/flow/limits.js.map +1 -0
  177. package/dist/commands/flow/output.d.ts +8 -0
  178. package/dist/commands/flow/output.d.ts.map +1 -0
  179. package/dist/commands/flow/output.js +11 -0
  180. package/dist/commands/flow/output.js.map +1 -0
  181. package/dist/commands/flow/render.d.ts +51 -0
  182. package/dist/commands/flow/render.d.ts.map +1 -0
  183. package/dist/commands/flow/render.js +220 -0
  184. package/dist/commands/flow/render.js.map +1 -0
  185. package/dist/commands/flow/select.d.ts +31 -0
  186. package/dist/commands/flow/select.d.ts.map +1 -0
  187. package/dist/commands/flow/select.js +62 -0
  188. package/dist/commands/flow/select.js.map +1 -0
  189. package/dist/commands/graph/boundaries-input.d.ts +26 -0
  190. package/dist/commands/graph/boundaries-input.d.ts.map +1 -0
  191. package/dist/commands/graph/boundaries-input.js +54 -0
  192. package/dist/commands/graph/boundaries-input.js.map +1 -0
  193. package/dist/commands/graph/boundaries.d.ts +4 -0
  194. package/dist/commands/graph/boundaries.d.ts.map +1 -0
  195. package/dist/commands/graph/boundaries.js +141 -0
  196. package/dist/commands/graph/boundaries.js.map +1 -0
  197. package/dist/commands/graph/bounds.d.ts +16 -0
  198. package/dist/commands/graph/bounds.d.ts.map +1 -0
  199. package/dist/commands/graph/bounds.js +22 -0
  200. package/dist/commands/graph/bounds.js.map +1 -0
  201. package/dist/commands/graph/category-clusters.d.ts +20 -0
  202. package/dist/commands/graph/category-clusters.d.ts.map +1 -0
  203. package/dist/commands/graph/category-clusters.js +158 -0
  204. package/dist/commands/graph/category-clusters.js.map +1 -0
  205. package/dist/commands/graph/feature-3d.d.ts +22 -0
  206. package/dist/commands/graph/feature-3d.d.ts.map +1 -0
  207. package/dist/commands/graph/feature-3d.js +114 -0
  208. package/dist/commands/graph/feature-3d.js.map +1 -0
  209. package/dist/commands/graph/feature-clusters.d.ts +17 -0
  210. package/dist/commands/graph/feature-clusters.d.ts.map +1 -0
  211. package/dist/commands/graph/feature-clusters.js +94 -0
  212. package/dist/commands/graph/feature-clusters.js.map +1 -0
  213. package/dist/commands/graph/feature-html.d.ts +26 -0
  214. package/dist/commands/graph/feature-html.d.ts.map +1 -0
  215. package/dist/commands/graph/feature-html.js +314 -0
  216. package/dist/commands/graph/feature-html.js.map +1 -0
  217. package/dist/commands/graph/feature-map.d.ts +31 -0
  218. package/dist/commands/graph/feature-map.d.ts.map +1 -0
  219. package/dist/commands/graph/feature-map.js +217 -0
  220. package/dist/commands/graph/feature-map.js.map +1 -0
  221. package/dist/commands/graph/feature-model.d.ts +55 -0
  222. package/dist/commands/graph/feature-model.d.ts.map +1 -0
  223. package/dist/commands/graph/feature-model.js +167 -0
  224. package/dist/commands/graph/feature-model.js.map +1 -0
  225. package/dist/commands/graph/feature-untangle-motion.d.ts +33 -0
  226. package/dist/commands/graph/feature-untangle-motion.d.ts.map +1 -0
  227. package/dist/commands/graph/feature-untangle-motion.js +155 -0
  228. package/dist/commands/graph/feature-untangle-motion.js.map +1 -0
  229. package/dist/commands/graph/index.d.ts +3 -0
  230. package/dist/commands/graph/index.d.ts.map +1 -0
  231. package/dist/commands/graph/index.js +414 -0
  232. package/dist/commands/graph/index.js.map +1 -0
  233. package/dist/commands/graph/render.d.ts +63 -0
  234. package/dist/commands/graph/render.d.ts.map +1 -0
  235. package/dist/commands/graph/render.js +352 -0
  236. package/dist/commands/graph/render.js.map +1 -0
  237. package/dist/commands/graph/select.d.ts +34 -0
  238. package/dist/commands/graph/select.d.ts.map +1 -0
  239. package/dist/commands/graph/select.js +55 -0
  240. package/dist/commands/graph/select.js.map +1 -0
  241. package/dist/commands/index/index.d.ts +6 -0
  242. package/dist/commands/index/index.d.ts.map +1 -0
  243. package/dist/commands/index/index.js +461 -0
  244. package/dist/commands/index/index.js.map +1 -0
  245. package/dist/commands/index/render.d.ts +53 -0
  246. package/dist/commands/index/render.d.ts.map +1 -0
  247. package/dist/commands/index/render.js +205 -0
  248. package/dist/commands/index/render.js.map +1 -0
  249. package/dist/commands/index/target.d.ts +34 -0
  250. package/dist/commands/index/target.d.ts.map +1 -0
  251. package/dist/commands/index/target.js +97 -0
  252. package/dist/commands/index/target.js.map +1 -0
  253. package/dist/commands/index-watch.d.ts +30 -0
  254. package/dist/commands/index-watch.d.ts.map +1 -0
  255. package/dist/commands/index-watch.js +138 -0
  256. package/dist/commands/index-watch.js.map +1 -0
  257. package/dist/commands/init/command.d.ts +25 -0
  258. package/dist/commands/init/command.d.ts.map +1 -0
  259. package/dist/commands/init/command.js +198 -0
  260. package/dist/commands/init/command.js.map +1 -0
  261. package/dist/commands/init/config-draft.d.ts +48 -0
  262. package/dist/commands/init/config-draft.d.ts.map +1 -0
  263. package/dist/commands/init/config-draft.js +201 -0
  264. package/dist/commands/init/config-draft.js.map +1 -0
  265. package/dist/commands/init/diff.d.ts +33 -0
  266. package/dist/commands/init/diff.d.ts.map +1 -0
  267. package/dist/commands/init/diff.js +109 -0
  268. package/dist/commands/init/diff.js.map +1 -0
  269. package/dist/commands/init/http-probe.d.ts +26 -0
  270. package/dist/commands/init/http-probe.d.ts.map +1 -0
  271. package/dist/commands/init/http-probe.js +144 -0
  272. package/dist/commands/init/http-probe.js.map +1 -0
  273. package/dist/commands/init/ignore-rules.d.ts +70 -0
  274. package/dist/commands/init/ignore-rules.d.ts.map +1 -0
  275. package/dist/commands/init/ignore-rules.js +146 -0
  276. package/dist/commands/init/ignore-rules.js.map +1 -0
  277. package/dist/commands/init/index.d.ts +33 -0
  278. package/dist/commands/init/index.d.ts.map +1 -0
  279. package/dist/commands/init/index.js +32 -0
  280. package/dist/commands/init/index.js.map +1 -0
  281. package/dist/commands/init/integrations-apply.d.ts +50 -0
  282. package/dist/commands/init/integrations-apply.d.ts.map +1 -0
  283. package/dist/commands/init/integrations-apply.js +452 -0
  284. package/dist/commands/init/integrations-apply.js.map +1 -0
  285. package/dist/commands/init/integrations-plan.d.ts +68 -0
  286. package/dist/commands/init/integrations-plan.d.ts.map +1 -0
  287. package/dist/commands/init/integrations-plan.js +515 -0
  288. package/dist/commands/init/integrations-plan.js.map +1 -0
  289. package/dist/commands/init/integrations.d.ts +5 -0
  290. package/dist/commands/init/integrations.d.ts.map +1 -0
  291. package/dist/commands/init/integrations.js +4 -0
  292. package/dist/commands/init/integrations.js.map +1 -0
  293. package/dist/commands/init/languages.d.ts +55 -0
  294. package/dist/commands/init/languages.d.ts.map +1 -0
  295. package/dist/commands/init/languages.js +245 -0
  296. package/dist/commands/init/languages.js.map +1 -0
  297. package/dist/commands/init/product-context.d.ts +63 -0
  298. package/dist/commands/init/product-context.d.ts.map +1 -0
  299. package/dist/commands/init/product-context.js +390 -0
  300. package/dist/commands/init/product-context.js.map +1 -0
  301. package/dist/commands/init/render.d.ts +38 -0
  302. package/dist/commands/init/render.d.ts.map +1 -0
  303. package/dist/commands/init/render.js +501 -0
  304. package/dist/commands/init/render.js.map +1 -0
  305. package/dist/commands/init/report.d.ts +24 -0
  306. package/dist/commands/init/report.d.ts.map +1 -0
  307. package/dist/commands/init/report.js +163 -0
  308. package/dist/commands/init/report.js.map +1 -0
  309. package/dist/commands/init/run.d.ts +71 -0
  310. package/dist/commands/init/run.d.ts.map +1 -0
  311. package/dist/commands/init/run.js +253 -0
  312. package/dist/commands/init/run.js.map +1 -0
  313. package/dist/commands/init/services.d.ts +82 -0
  314. package/dist/commands/init/services.d.ts.map +1 -0
  315. package/dist/commands/init/services.js +209 -0
  316. package/dist/commands/init/services.js.map +1 -0
  317. package/dist/commands/init/storage.d.ts +8 -0
  318. package/dist/commands/init/storage.d.ts.map +1 -0
  319. package/dist/commands/init/storage.js +102 -0
  320. package/dist/commands/init/storage.js.map +1 -0
  321. package/dist/commands/init/toml.d.ts +65 -0
  322. package/dist/commands/init/toml.d.ts.map +1 -0
  323. package/dist/commands/init/toml.js +159 -0
  324. package/dist/commands/init/toml.js.map +1 -0
  325. package/dist/commands/init/topology.d.ts +54 -0
  326. package/dist/commands/init/topology.d.ts.map +1 -0
  327. package/dist/commands/init/topology.js +146 -0
  328. package/dist/commands/init/topology.js.map +1 -0
  329. package/dist/commands/init/types.d.ts +334 -0
  330. package/dist/commands/init/types.d.ts.map +1 -0
  331. package/dist/commands/init/types.js +31 -0
  332. package/dist/commands/init/types.js.map +1 -0
  333. package/dist/commands/init/wizard-terminal.d.ts +36 -0
  334. package/dist/commands/init/wizard-terminal.d.ts.map +1 -0
  335. package/dist/commands/init/wizard-terminal.js +163 -0
  336. package/dist/commands/init/wizard-terminal.js.map +1 -0
  337. package/dist/commands/init/wizard.d.ts +25 -0
  338. package/dist/commands/init/wizard.d.ts.map +1 -0
  339. package/dist/commands/init/wizard.js +358 -0
  340. package/dist/commands/init/wizard.js.map +1 -0
  341. package/dist/commands/mcp.d.ts +4 -0
  342. package/dist/commands/mcp.d.ts.map +1 -0
  343. package/dist/commands/mcp.js +111 -0
  344. package/dist/commands/mcp.js.map +1 -0
  345. package/dist/commands/product-test-runner.d.ts +4 -0
  346. package/dist/commands/product-test-runner.d.ts.map +1 -0
  347. package/dist/commands/product-test-runner.js +85 -0
  348. package/dist/commands/product-test-runner.js.map +1 -0
  349. package/dist/commands/product.d.ts +16 -0
  350. package/dist/commands/product.d.ts.map +1 -0
  351. package/dist/commands/product.js +262 -0
  352. package/dist/commands/product.js.map +1 -0
  353. package/dist/commands/query.d.ts +114 -0
  354. package/dist/commands/query.d.ts.map +1 -0
  355. package/dist/commands/query.js +783 -0
  356. package/dist/commands/query.js.map +1 -0
  357. package/dist/commands/scan.d.ts +10 -0
  358. package/dist/commands/scan.d.ts.map +1 -0
  359. package/dist/commands/scan.js +302 -0
  360. package/dist/commands/scan.js.map +1 -0
  361. package/dist/commands/sdd.d.ts +24 -0
  362. package/dist/commands/sdd.d.ts.map +1 -0
  363. package/dist/commands/sdd.js +195 -0
  364. package/dist/commands/sdd.js.map +1 -0
  365. package/dist/commands/unavailable.d.ts +40 -0
  366. package/dist/commands/unavailable.d.ts.map +1 -0
  367. package/dist/commands/unavailable.js +73 -0
  368. package/dist/commands/unavailable.js.map +1 -0
  369. package/dist/commands/watch/analyze.d.ts +69 -0
  370. package/dist/commands/watch/analyze.d.ts.map +1 -0
  371. package/dist/commands/watch/analyze.js +402 -0
  372. package/dist/commands/watch/analyze.js.map +1 -0
  373. package/dist/commands/watch/cli.d.ts +8 -0
  374. package/dist/commands/watch/cli.d.ts.map +1 -0
  375. package/dist/commands/watch/cli.js +97 -0
  376. package/dist/commands/watch/cli.js.map +1 -0
  377. package/dist/commands/watch/delta.d.ts +46 -0
  378. package/dist/commands/watch/delta.d.ts.map +1 -0
  379. package/dist/commands/watch/delta.js +170 -0
  380. package/dist/commands/watch/delta.js.map +1 -0
  381. package/dist/commands/watch/events.d.ts +214 -0
  382. package/dist/commands/watch/events.d.ts.map +1 -0
  383. package/dist/commands/watch/events.js +13 -0
  384. package/dist/commands/watch/events.js.map +1 -0
  385. package/dist/commands/watch/index.d.ts +19 -0
  386. package/dist/commands/watch/index.d.ts.map +1 -0
  387. package/dist/commands/watch/index.js +15 -0
  388. package/dist/commands/watch/index.js.map +1 -0
  389. package/dist/commands/watch/options.d.ts +43 -0
  390. package/dist/commands/watch/options.d.ts.map +1 -0
  391. package/dist/commands/watch/options.js +193 -0
  392. package/dist/commands/watch/options.js.map +1 -0
  393. package/dist/commands/watch/render.d.ts +26 -0
  394. package/dist/commands/watch/render.d.ts.map +1 -0
  395. package/dist/commands/watch/render.js +175 -0
  396. package/dist/commands/watch/render.js.map +1 -0
  397. package/dist/commands/watch/run.d.ts +14 -0
  398. package/dist/commands/watch/run.d.ts.map +1 -0
  399. package/dist/commands/watch/run.js +460 -0
  400. package/dist/commands/watch/run.js.map +1 -0
  401. package/dist/commands/watch/runtime.d.ts +67 -0
  402. package/dist/commands/watch/runtime.d.ts.map +1 -0
  403. package/dist/commands/watch/runtime.js +149 -0
  404. package/dist/commands/watch/runtime.js.map +1 -0
  405. package/dist/commands/watch-command.d.ts +3 -0
  406. package/dist/commands/watch-command.d.ts.map +1 -0
  407. package/dist/commands/watch-command.js +273 -0
  408. package/dist/commands/watch-command.js.map +1 -0
  409. package/dist/entry-point.d.ts +11 -0
  410. package/dist/entry-point.d.ts.map +1 -0
  411. package/dist/entry-point.js +65 -0
  412. package/dist/entry-point.js.map +1 -0
  413. package/dist/index.d.ts +38 -0
  414. package/dist/index.d.ts.map +1 -0
  415. package/dist/index.js +245 -0
  416. package/dist/index.js.map +1 -0
  417. package/dist/mcp/boundaries-schema.d.ts +262 -0
  418. package/dist/mcp/boundaries-schema.d.ts.map +1 -0
  419. package/dist/mcp/boundaries-schema.js +183 -0
  420. package/dist/mcp/boundaries-schema.js.map +1 -0
  421. package/dist/mcp/default-runtime.d.ts +16 -0
  422. package/dist/mcp/default-runtime.d.ts.map +1 -0
  423. package/dist/mcp/default-runtime.js +718 -0
  424. package/dist/mcp/default-runtime.js.map +1 -0
  425. package/dist/mcp/envelope.d.ts +13 -0
  426. package/dist/mcp/envelope.d.ts.map +1 -0
  427. package/dist/mcp/envelope.js +29 -0
  428. package/dist/mcp/envelope.js.map +1 -0
  429. package/dist/mcp/index.d.ts +8 -0
  430. package/dist/mcp/index.d.ts.map +1 -0
  431. package/dist/mcp/index.js +8 -0
  432. package/dist/mcp/index.js.map +1 -0
  433. package/dist/mcp/output-schemas.d.ts +5928 -0
  434. package/dist/mcp/output-schemas.d.ts.map +1 -0
  435. package/dist/mcp/output-schemas.js +2814 -0
  436. package/dist/mcp/output-schemas.js.map +1 -0
  437. package/dist/mcp/path-sandbox.d.ts +35 -0
  438. package/dist/mcp/path-sandbox.d.ts.map +1 -0
  439. package/dist/mcp/path-sandbox.js +128 -0
  440. package/dist/mcp/path-sandbox.js.map +1 -0
  441. package/dist/mcp/server.d.ts +155 -0
  442. package/dist/mcp/server.d.ts.map +1 -0
  443. package/dist/mcp/server.js +257 -0
  444. package/dist/mcp/server.js.map +1 -0
  445. package/dist/mcp/stdio.d.ts +20 -0
  446. package/dist/mcp/stdio.d.ts.map +1 -0
  447. package/dist/mcp/stdio.js +71 -0
  448. package/dist/mcp/stdio.js.map +1 -0
  449. package/dist/mcp/tools.d.ts +355 -0
  450. package/dist/mcp/tools.d.ts.map +1 -0
  451. package/dist/mcp/tools.js +319 -0
  452. package/dist/mcp/tools.js.map +1 -0
  453. package/dist/mcp/types.d.ts +15 -0
  454. package/dist/mcp/types.d.ts.map +1 -0
  455. package/dist/mcp/types.js +45 -0
  456. package/dist/mcp/types.js.map +1 -0
  457. package/package.json +99 -3
  458. package/src/cli/args.ts +231 -0
  459. package/src/cli/command.ts +146 -0
  460. package/src/cli/deadline.ts +56 -0
  461. package/src/cli/embedder-deadline.ts +187 -0
  462. package/src/cli/exit.ts +94 -0
  463. package/src/cli/graphs.ts +191 -0
  464. package/src/cli/index-freshness.ts +303 -0
  465. package/src/cli/index-refresh.ts +125 -0
  466. package/src/cli/index-state.ts +1217 -0
  467. package/src/cli/io.ts +56 -0
  468. package/src/cli/language-support.ts +203 -0
  469. package/src/cli/renewing-lease.ts +121 -0
  470. package/src/cli/search-graph-enrichment.ts +639 -0
  471. package/src/cli/system.ts +94 -0
  472. package/src/cli/vector-store-policy.ts +213 -0
  473. package/src/cli/version.ts +2 -0
  474. package/src/cli/workspace.ts +324 -0
  475. package/src/commands/complexity.ts +776 -0
  476. package/src/commands/doctor.languages.ts +187 -0
  477. package/src/commands/doctor.storage.ts +124 -0
  478. package/src/commands/doctor.ts +946 -0
  479. package/src/commands/extensions/add.ts +312 -0
  480. package/src/commands/extensions/configure.ts +82 -0
  481. package/src/commands/extensions/container.ts +209 -0
  482. package/src/commands/extensions/context.ts +109 -0
  483. package/src/commands/extensions/enable.ts +237 -0
  484. package/src/commands/extensions/environment.ts +218 -0
  485. package/src/commands/extensions/feature-scan.ts +232 -0
  486. package/src/commands/extensions/invoke.ts +368 -0
  487. package/src/commands/extensions/list.ts +158 -0
  488. package/src/commands/extensions/logs.ts +104 -0
  489. package/src/commands/extensions/provision.ts +206 -0
  490. package/src/commands/extensions/remove.ts +110 -0
  491. package/src/commands/extensions/render.ts +32 -0
  492. package/src/commands/extensions/run.ts +386 -0
  493. package/src/commands/extensions/secret-store.ts +223 -0
  494. package/src/commands/extensions/setup.ts +140 -0
  495. package/src/commands/extensions/source.ts +189 -0
  496. package/src/commands/extensions/state.ts +252 -0
  497. package/src/commands/extensions/status.ts +320 -0
  498. package/src/commands/extensions.ts +280 -0
  499. package/src/commands/flow/index.ts +402 -0
  500. package/src/commands/flow/limits.ts +14 -0
  501. package/src/commands/flow/output.ts +16 -0
  502. package/src/commands/flow/render.ts +318 -0
  503. package/src/commands/flow/select.ts +101 -0
  504. package/src/commands/graph/boundaries-input.ts +63 -0
  505. package/src/commands/graph/boundaries.ts +182 -0
  506. package/src/commands/graph/bounds.ts +25 -0
  507. package/src/commands/graph/category-clusters.ts +194 -0
  508. package/src/commands/graph/feature-3d.ts +141 -0
  509. package/src/commands/graph/feature-clusters.ts +125 -0
  510. package/src/commands/graph/feature-html.ts +336 -0
  511. package/src/commands/graph/feature-map.ts +270 -0
  512. package/src/commands/graph/feature-model.ts +234 -0
  513. package/src/commands/graph/feature-untangle-motion.ts +192 -0
  514. package/src/commands/graph/index.ts +562 -0
  515. package/src/commands/graph/render.ts +503 -0
  516. package/src/commands/graph/select.ts +77 -0
  517. package/src/commands/index/index.ts +595 -0
  518. package/src/commands/index/render.ts +325 -0
  519. package/src/commands/index/target.ts +136 -0
  520. package/src/commands/index-watch.ts +206 -0
  521. package/src/commands/init/command.ts +238 -0
  522. package/src/commands/init/config-draft.ts +235 -0
  523. package/src/commands/init/diff.ts +117 -0
  524. package/src/commands/init/http-probe.ts +150 -0
  525. package/src/commands/init/ignore-rules.ts +170 -0
  526. package/src/commands/init/index.ts +63 -0
  527. package/src/commands/init/integrations-apply.ts +618 -0
  528. package/src/commands/init/integrations-plan.ts +634 -0
  529. package/src/commands/init/integrations.ts +8 -0
  530. package/src/commands/init/languages.ts +320 -0
  531. package/src/commands/init/product-context.ts +576 -0
  532. package/src/commands/init/render.ts +598 -0
  533. package/src/commands/init/report.ts +204 -0
  534. package/src/commands/init/run.ts +349 -0
  535. package/src/commands/init/services.ts +271 -0
  536. package/src/commands/init/storage.ts +136 -0
  537. package/src/commands/init/toml.ts +174 -0
  538. package/src/commands/init/topology.ts +192 -0
  539. package/src/commands/init/types.ts +366 -0
  540. package/src/commands/init/wizard-terminal.ts +206 -0
  541. package/src/commands/init/wizard.ts +450 -0
  542. package/src/commands/mcp.ts +123 -0
  543. package/src/commands/product-test-runner.ts +80 -0
  544. package/src/commands/product.ts +331 -0
  545. package/src/commands/query.ts +1032 -0
  546. package/src/commands/scan.ts +360 -0
  547. package/src/commands/sdd.ts +243 -0
  548. package/src/commands/unavailable.ts +92 -0
  549. package/src/commands/watch/README.md +160 -0
  550. package/src/commands/watch/analyze.ts +600 -0
  551. package/src/commands/watch/cli.ts +108 -0
  552. package/src/commands/watch/delta.ts +186 -0
  553. package/src/commands/watch/events.ts +235 -0
  554. package/src/commands/watch/index.ts +53 -0
  555. package/src/commands/watch/options.ts +234 -0
  556. package/src/commands/watch/render.ts +240 -0
  557. package/src/commands/watch/run.ts +553 -0
  558. package/src/commands/watch/runtime.ts +167 -0
  559. package/src/commands/watch-command.ts +294 -0
  560. package/src/entry-point.ts +67 -0
  561. package/src/index.ts +291 -0
  562. package/src/mcp/boundaries-schema.ts +193 -0
  563. package/src/mcp/default-runtime.ts +1034 -0
  564. package/src/mcp/envelope.ts +57 -0
  565. package/src/mcp/index.ts +28 -0
  566. package/src/mcp/output-schemas.ts +3071 -0
  567. package/src/mcp/path-sandbox.ts +156 -0
  568. package/src/mcp/server.ts +358 -0
  569. package/src/mcp/stdio.ts +92 -0
  570. package/src/mcp/tools.ts +563 -0
  571. package/src/mcp/types.ts +66 -0
@@ -0,0 +1,783 @@
1
+ /**
2
+ * `untangle query` — der Befehl, um den es geht.
3
+ *
4
+ * Er verdrahtet @untangle-code/search und macht dabei ZWEI Dinge unter EINER
5
+ * Oberflaeche sichtbar (Nutzerwunsch A4):
6
+ *
7
+ * - die SEMANTISCHE Suche (hybrid aus dichtem Vektor, BM25 und exaktem
8
+ * Symbolnamen, fusioniert per RRF), und
9
+ * - die GREP-artige Suche (Literal oder regulaerer Ausdruck) mit
10
+ * Kontextzeilen, Pfad-Ein-/Ausschluss und Trefferbegrenzung.
11
+ *
12
+ * `--explain` ist kein Debug-Anhang, sondern der Kern von vision.md §1d: die
13
+ * Score-Zerlegung beantwortet „warum steht das oben?" — und damit auch die
14
+ * Gegenfrage „warum steht der richtige Treffer NICHT oben?".
15
+ *
16
+ * WICHTIG UND EHRLICH: Gesucht wird im INDEX, nicht auf der Platte. Solange
17
+ * `untangle index` fehlt (siehe dort), ist der Index leer. Dieser Befehl
18
+ * behauptet dann nicht „nichts gefunden", sondern nennt den fehlenden Index
19
+ * als Grund und endet mit Exit-Code 4.
20
+ */
21
+ import path from "node:path";
22
+ import { OfflineEmbeddingProvider } from "@untangle-code/core";
23
+ import { compareCodepoints, isUntangleError, embeddingProfileShortId, INDEX_CONTEXT_INCOMPLETE_WARNING_CODE, uniqueSortedByCodepoints, } from "@untangle-code/domain";
24
+ import { COMPLEXITY_BIASES, GREP_SORTS, NO_SUFFICIENT_MATCH_WARNING_CODE, OUTPUT_FORMATS, SEARCH_ABSTENTIONS, SEARCH_MODES, SEARCH_SORTS, formatGrepResultSet, formatHitAsText, formatSearchGraphRelationsAsText, formatSearchResultSet, } from "@untangle-code/search";
25
+ import { codeCollectionName } from "@untangle-code/storage-qdrant";
26
+ import { boolFlag, enumFlag, integerFlag, listFlag, numberFlag, stringFlag, } from "../cli/args.js";
27
+ import { withDeadline } from "../cli/deadline.js";
28
+ import { EXIT, EnvironmentError, OperationalError, UsageError } from "../cli/exit.js";
29
+ import { inspectIndexFreshness } from "../cli/index-freshness.js";
30
+ import { refreshWorkspaceIndex } from "../cli/index-refresh.js";
31
+ import { resolveIndexState, } from "../cli/index-state.js";
32
+ import { line, note } from "../cli/io.js";
33
+ import { createSearchGraphEnrichment } from "../cli/search-graph-enrichment.js";
34
+ import { systemClock } from "../cli/system.js";
35
+ import { errorMessage, loadWorkspace, wireEmbedder, wireSearchEngine, wireStorage, matchesStoredBackend, storageIndexScope, } from "../cli/workspace.js";
36
+ /**
37
+ * Frist der ganzen Anfrage.
38
+ *
39
+ * Includes retrieval and optional graph enrichment. Semantic/hybrid search
40
+ * also computes a query embedding, which can require loading a service model.
41
+ * The finite deadline keeps an unresponsive terminal from hanging indefinitely.
42
+ */
43
+ export const DEFAULT_QUERY_TIMEOUT_MS = 60_000;
44
+ const FLAGS = {
45
+ embedder: {
46
+ kind: "string",
47
+ placeholder: "auto|service|offline",
48
+ describe: "auto selects the last index run's profile; service forces the configured service, offline selects the locally built collection.",
49
+ defaultLabel: "auto",
50
+ },
51
+ root: {
52
+ kind: "string",
53
+ placeholder: "PATH",
54
+ describe: "Project directory; configuration is discovered from here.",
55
+ defaultLabel: "current directory",
56
+ },
57
+ format: {
58
+ kind: "string",
59
+ placeholder: OUTPUT_FORMATS.join("|"),
60
+ describe: "Output format. jsonl is streamable; json contains the complete result.",
61
+ defaultLabel: "text",
62
+ },
63
+ limit: { kind: "number", alias: "n", placeholder: "N", describe: "Number of results." },
64
+ explain: {
65
+ kind: "boolean",
66
+ describe: "Show each result's score breakdown (vision.md §1d).",
67
+ },
68
+ mode: {
69
+ kind: "string",
70
+ placeholder: SEARCH_MODES.join("|"),
71
+ describe: "Independent retrieval and ranking paths: lexical/symbol require no embedding.",
72
+ defaultLabel: "hybrid",
73
+ },
74
+ abstention: {
75
+ kind: "string",
76
+ placeholder: SEARCH_ABSTENTIONS.join("|"),
77
+ describe: "Behavior with insufficient evidence: strict returns no hits; evidence returns hits with the verdict.",
78
+ defaultLabel: "strict",
79
+ },
80
+ sort: {
81
+ kind: "string",
82
+ placeholder: SEARCH_SORTS.join("|"),
83
+ describe: "Result sort key.",
84
+ defaultLabel: "relevance",
85
+ },
86
+ content: { kind: "boolean", describe: "Include chunk content (token-intensive)." },
87
+ linked: {
88
+ kind: "boolean",
89
+ describe: "Direct, unambiguously resolved relationships from the persisted symbol graph.",
90
+ },
91
+ "min-score": {
92
+ kind: "number",
93
+ placeholder: "X",
94
+ describe: "Discard results below this score.",
95
+ },
96
+ "complexity-bias": {
97
+ kind: "string",
98
+ placeholder: COMPLEXITY_BIASES.join("|"),
99
+ describe: "Prefer simpler or more complex results (vision.md §1b).",
100
+ defaultLabel: "none",
101
+ },
102
+ path: {
103
+ kind: "list",
104
+ placeholder: "GLOB",
105
+ describe: "Include these paths only. Repeatable.",
106
+ },
107
+ exclude: {
108
+ kind: "list",
109
+ placeholder: "GLOB",
110
+ describe: "Exclude these paths. Repeatable.",
111
+ },
112
+ lang: { kind: "list", placeholder: "ID", describe: "Include these languages only. Repeatable." },
113
+ repo: {
114
+ kind: "list",
115
+ placeholder: "ID",
116
+ describe: "Include these repositories only. Repeatable.",
117
+ },
118
+ ref: { kind: "list", placeholder: "ID", describe: "Include these refs only. Repeatable." },
119
+ symbol: { kind: "list", placeholder: "NAME", describe: "Exact symbol names. Repeatable." },
120
+ workspace: { kind: "string", placeholder: "ID", describe: "Override workspace ID." },
121
+ timeout: {
122
+ kind: "number",
123
+ placeholder: "MS",
124
+ describe: "Deadline for the entire query. Expiry makes the query fail.",
125
+ defaultLabel: String(DEFAULT_QUERY_TIMEOUT_MS),
126
+ },
127
+ refresh: {
128
+ kind: "boolean",
129
+ describe: "Refresh stale checked-out refs before searching; progress goes to stderr.",
130
+ },
131
+ "require-fresh": {
132
+ kind: "boolean",
133
+ describe: "Search only with confirmed current content hashes; otherwise exit 4.",
134
+ },
135
+ // --- grep-Modus (Nutzerwunsch A4) ---------------------------------------
136
+ grep: {
137
+ kind: "boolean",
138
+ alias: "g",
139
+ describe: "grep mode: literal search in indexed content.",
140
+ },
141
+ regex: { kind: "boolean", alias: "e", describe: "grep mode with a regular expression." },
142
+ "ignore-case": {
143
+ kind: "boolean",
144
+ alias: "i",
145
+ describe: "grep: ignore letter case.",
146
+ },
147
+ word: {
148
+ kind: "boolean",
149
+ alias: "w",
150
+ describe: "grep: whole words only (identifier boundaries).",
151
+ },
152
+ after: {
153
+ kind: "number",
154
+ alias: "A",
155
+ placeholder: "N",
156
+ describe: "grep: context lines after the match.",
157
+ },
158
+ before: {
159
+ kind: "number",
160
+ alias: "B",
161
+ placeholder: "N",
162
+ describe: "grep: context lines before the match.",
163
+ },
164
+ context: {
165
+ kind: "boolean-or-number",
166
+ alias: "C",
167
+ placeholder: "N",
168
+ describe: "Search: direct relationships from the persisted file graph. grep: =N or -C N shows context on both sides.",
169
+ },
170
+ "max-matches": {
171
+ kind: "number",
172
+ placeholder: "N",
173
+ describe: "grep: maximum total matches.",
174
+ },
175
+ "max-per-file": { kind: "number", placeholder: "N", describe: "grep: maximum matches per file." },
176
+ "max-scanned": {
177
+ kind: "number",
178
+ placeholder: "N",
179
+ describe: "grep: maximum searched chunks.",
180
+ },
181
+ "grep-sort": {
182
+ kind: "string",
183
+ placeholder: GREP_SORTS.join("|"),
184
+ describe: "grep: match ordering.",
185
+ defaultLabel: "path",
186
+ },
187
+ };
188
+ export const queryCommand = {
189
+ spec: {
190
+ name: "query",
191
+ implementedBy: "commands/query.js",
192
+ summary: "Search the index with semantic and grep-style queries",
193
+ usage: "untangle query <text> [options]",
194
+ details: [
195
+ "Without --grep/--regex, hybrid search retrieves dense vectors, BM25 and exact symbols independently, then combines them with RRF. --mode selects independent retrieval and ranking paths; lexical/symbol need no embedding service.",
196
+ "Before each search, index freshness is checked against the full current content manifest and returned as indexFreshness. --refresh updates stale checked-out refs; --require-fresh rejects unconfirmed freshness. An outdated lexical index format requires reindexing.",
197
+ "--grep (literal) and --regex search the same index with the same filters and skip ledger. Context lines come from the same chunk and stop at its boundary.",
198
+ "--explain shows the full score breakdown: each component's raw value, weight and contribution, making the ranking inspectable.",
199
+ "Profile discovery: `untangle index` records the embedding profile per repository/ref in the local registry (.untangle/index-states-v1). Without --embedder, query uses the generation-bound current state and reports that choice on stderr. Override with --embedder=service or --embedder=offline.",
200
+ "Search reads the index, not the working tree. Unindexed content cannot be found; the result therefore includes its skip ledger and, for grep, the number of searched chunks.",
201
+ ],
202
+ flags: FLAGS,
203
+ examples: [
204
+ 'untangle query "where is the payment triggered"',
205
+ 'untangle query "charge" --mode=symbol --explain',
206
+ "untangle query --regex \"await\\\\s+fetch\\\\(\" -C 2 --path='src/**' --exclude='**/*.test.ts'",
207
+ 'untangle query "retry" --format=jsonl | jq -r .filePath',
208
+ ],
209
+ exitCodes: [
210
+ [EXIT.ok, "Search completed, including zero-hit results."],
211
+ [EXIT.operational, "Invalid configuration or a storage error."],
212
+ [EXIT.usage, "Invalid arguments."],
213
+ [
214
+ EXIT.environment,
215
+ "No compatible index, or the selected storage/embedding provider is unavailable.",
216
+ ],
217
+ [EXIT.cancelled, "Cancelled."],
218
+ ],
219
+ },
220
+ async run(ctx, args) {
221
+ const format = enumFlag(args, "format", OUTPUT_FORMATS, "text");
222
+ const isGrep = boolFlag(args, "grep") || boolFlag(args, "regex");
223
+ const text = args.positionals.join(" ").trim();
224
+ if (text.length === 0) {
225
+ throw new UsageError("Search text is required.", isGrep
226
+ ? 'Example: untangle query --regex "await\\\\s+fetch\\\\("'
227
+ : 'Example: untangle query "where is the payment triggered"');
228
+ }
229
+ const view = loadWorkspace({
230
+ cwd: args.flags["root"] === undefined ? ctx.cwd : String(args.flags["root"]),
231
+ env: ctx.env,
232
+ workspaceIdOverride: stringFlag(args, "workspace"),
233
+ strict: true,
234
+ });
235
+ if (view.load.warnings.length > 0) {
236
+ for (const warning of view.load.warnings) {
237
+ note(ctx.io, `Configuration warning: ${warning.path || "(root)"}: ${warning.message}`);
238
+ }
239
+ }
240
+ const wiring = wireStorage(view, ctx.env);
241
+ const timeoutMs = integerFlag(args, "timeout", DEFAULT_QUERY_TIMEOUT_MS);
242
+ // `untangle index --embedder=offline` legt seine Punkte in einer EIGENEN
243
+ // Sammlung ab (eigener `embedding_profile_id`, spec.md §10.1) — sonst
244
+ // mischten netzlose und echte Vektoren in einem Raum, in dem sie nicht
245
+ // vergleichbar sind. Damit dieser Index auch DURCHSUCHBAR ist, kennt
246
+ // `query` denselben Schalter.
247
+ //
248
+ // WP-229: Ihn zu KENNEN reichte aber nicht — man musste ihn auch bei jeder
249
+ // Abfrage wiederholen. `auto` liest deshalb den Indexzustand, den
250
+ // `untangle index` hinterlaesst, und nimmt von dort, WOMIT tatsaechlich
251
+ // indiziert wurde. Geraten wird nichts: gibt es keinen Zustand, gilt die
252
+ // Konfiguration wie bisher, und widersprechen sich mehrere, sagt der
253
+ // Befehl das und laesst den Nutzer entscheiden.
254
+ const selectedRepoIds = listFlag(args, "repo");
255
+ const selectedRefIds = listFlag(args, "ref");
256
+ const indexStateResolution = await resolveIndexState(indexStateRoots({
257
+ invocationRoot: args.flags["root"] === undefined
258
+ ? ctx.cwd
259
+ : path.resolve(ctx.cwd, String(args.flags["root"])),
260
+ configBaseDir: view.load.sources.configBaseDir,
261
+ repositories: view.config.repositories ?? [],
262
+ selectedRepoIds,
263
+ }), view.workspaceId, { repoIds: selectedRepoIds, refs: selectedRefIds, ...storageIndexScope(wiring) });
264
+ if (indexStateResolution.kind === "invalid") {
265
+ const details = indexStateResolution.diagnostics
266
+ .map((diagnostic) => `${diagnostic.path}: ${diagnostic.message}`)
267
+ .join("; ");
268
+ throw new EnvironmentError(`The local index state is invalid; search will not use partial or ` +
269
+ `stale provenance. ${details}`, "Rerun the affected indexing job. It publishes the repository/ref registry atomically.");
270
+ }
271
+ const automaticEmbedder = enumFlag(args, "embedder", ["auto", "service", "offline"], "auto") === "auto";
272
+ const useOffline = resolveEmbedderChoice(ctx, args, indexStateResolution);
273
+ const embedder = useOffline ? new OfflineEmbeddingProvider(systemClock) : wireEmbedder(view);
274
+ const searchView = useOffline
275
+ ? {
276
+ ...view,
277
+ profile: embedder.profile,
278
+ profileId: embedder.profileId,
279
+ profileShortId: embeddingProfileShortId(embedder.profileId),
280
+ }
281
+ : view;
282
+ const collection = useOffline
283
+ ? codeCollectionName(wiring.collectionPrefix, searchView.profileShortId)
284
+ : wiring.codeCollection;
285
+ const foundIndexStates = queryIndexStatesFromResolution(indexStateResolution, automaticEmbedder);
286
+ const compatibleIndexStates = foundIndexStates.filter(({ state }) => state.embeddingProfileId === searchView.profileId &&
287
+ state.collection === collection &&
288
+ matchesStoredBackend(state, wiring));
289
+ const freshnessCheck = await withDeadline((signal) => inspectIndexFreshness(view, compatibleIndexStates, {
290
+ signal,
291
+ expectedRepoIds: selectedRepoIds.length > 0 ? selectedRepoIds : view.repoIds,
292
+ expectedRefs: selectedRefIds,
293
+ }), timeoutMs, ctx.signal);
294
+ ctx.signal.throwIfAborted();
295
+ const indexFreshness = freshnessCheck.ok
296
+ ? freshnessCheck.value
297
+ : {
298
+ status: "unknown",
299
+ checkedAt: systemClock.nowIso(),
300
+ repositories: [],
301
+ };
302
+ if (boolFlag(args, "refresh") && indexFreshness.status !== "fresh") {
303
+ await refreshWorkspaceIndex(ctx, {
304
+ view,
305
+ repoIds: selectedRepoIds,
306
+ refIds: selectedRefIds,
307
+ embedder: useOffline ? "offline" : "auto",
308
+ });
309
+ return queryCommand.run(ctx, {
310
+ ...args,
311
+ flags: { ...args.flags, refresh: false, "require-fresh": true },
312
+ });
313
+ }
314
+ if (indexFreshness.status === "incompatible" ||
315
+ (boolFlag(args, "require-fresh") && indexFreshness.status !== "fresh")) {
316
+ throw new EnvironmentError(`The search index is ${indexFreshness.status}; this query requires a current, compatible index.`, "Run the same query with --refresh or update with `untangle index`.");
317
+ }
318
+ note(ctx.io, `Index freshness: ${indexFreshness.status} (content hashes checked ${indexFreshness.checkedAt}).`);
319
+ const indexContexts = compatibleIndexStates.flatMap(({ state }) => state.generationId !== undefined
320
+ ? [
321
+ {
322
+ repoId: state.repoId,
323
+ refId: state.refId,
324
+ generationId: state.generationId,
325
+ ...(state.corpusRevisionFingerprint === undefined || indexFreshness.status !== "fresh"
326
+ ? {}
327
+ : { corpusRevisionFingerprint: state.corpusRevisionFingerprint }),
328
+ outcome: state.outcome,
329
+ },
330
+ ]
331
+ : []);
332
+ const effectiveRefIds = queryRefIdsFromIndexStates(selectedRefIds, compatibleIndexStates);
333
+ // Der fehlende Index ist der haeufigste Fall und verdient eine eigene,
334
+ // eindeutige Antwort — nicht eine leere Trefferliste (E4).
335
+ const probe = await withDeadline((signal) => wiring.vectorStore.collectionExists(collection, { signal }), timeoutMs, ctx.signal);
336
+ if (!probe.ok) {
337
+ ctx.signal.throwIfAborted();
338
+ throw new EnvironmentError(probe.timedOut
339
+ ? `${wiring.backend === "qdrant" ? "Qdrant" : "LanceDB"} at ${wiring.storeUrl} did not answer within ${String(timeoutMs)}ms.`
340
+ : `${wiring.backend === "qdrant" ? "Qdrant" : "LanceDB"} at ${wiring.storeUrl} is unreachable: ${errorMessage(probe.error)}`, "Run `untangle doctor` for the next step specific to this failure.", { cause: probe.error });
341
+ }
342
+ if (!probe.value) {
343
+ if (boolFlag(args, "refresh")) {
344
+ await refreshWorkspaceIndex(ctx, {
345
+ view,
346
+ repoIds: selectedRepoIds,
347
+ refIds: selectedRefIds,
348
+ embedder: useOffline ? "offline" : "auto",
349
+ });
350
+ return queryCommand.run(ctx, {
351
+ ...args,
352
+ flags: { ...args.flags, refresh: false, "require-fresh": true },
353
+ });
354
+ }
355
+ throw new EnvironmentError(`No index exists for this embedding profile: collection "${collection}" ` +
356
+ `is absent from ${wiring.storeUrl}. Nothing was searched; this does not ` +
357
+ `mean there are no results.`, useOffline
358
+ ? "Run `untangle index --embedder=offline` to build this collection."
359
+ : "Run `untangle index`. Without an available embedding service, use `untangle index --embedder=offline` and select `--embedder=offline` here too.");
360
+ }
361
+ const engine = wireSearchEngine({
362
+ view: searchView,
363
+ vectorStore: wiring.vectorStore,
364
+ collection,
365
+ embedder,
366
+ indexContexts,
367
+ ...(!isGrep && (boolFlag(args, "context") || boolFlag(args, "linked"))
368
+ ? { graphEnrichment: createSearchGraphEnrichment(wiring.storage.graphStore) }
369
+ : {}),
370
+ });
371
+ if (isGrep) {
372
+ const request = buildGrepRequest(args, view.workspaceId, text, effectiveRefIds);
373
+ const outcome = await withDeadline((signal) => engine.grep(request, { signal }), timeoutMs, ctx.signal);
374
+ if (!outcome.ok) {
375
+ ctx.signal.throwIfAborted();
376
+ throw toRuntimeError(outcome, wiring.storeUrl, timeoutMs, "grep", useOffline);
377
+ }
378
+ outcome.value.indexFreshness = indexFreshness;
379
+ addFreshnessWarning(outcome.value, indexFreshness);
380
+ renderGrep(ctx, outcome.value, format);
381
+ assertEverythingWasSearched(ctx, outcome.value.skipped, wiring.backend);
382
+ return EXIT.ok;
383
+ }
384
+ const request = buildSearchRequest(args, view.workspaceId, text, selectedRefIds.length === 0 ? undefined : effectiveRefIds);
385
+ const outcome = await withDeadline((signal) => engine.search(request, { signal }), timeoutMs, ctx.signal);
386
+ if (!outcome.ok) {
387
+ ctx.signal.throwIfAborted();
388
+ throw toRuntimeError(outcome, wiring.storeUrl, timeoutMs, request, useOffline);
389
+ }
390
+ outcome.value.indexFreshness = indexFreshness;
391
+ addFreshnessWarning(outcome.value, indexFreshness);
392
+ renderSearch(ctx, outcome.value, format, boolFlag(args, "explain"));
393
+ assertEverythingWasSearched(ctx, outcome.value.skipped, wiring.backend);
394
+ return EXIT.ok;
395
+ },
396
+ };
397
+ /* --------------------------------------------------------------------- */
398
+ export function addFreshnessWarning(result, freshness) {
399
+ if (freshness.status === "fresh")
400
+ return;
401
+ const warning = {
402
+ code: INDEX_CONTEXT_INCOMPLETE_WARNING_CODE,
403
+ message: `Indexfrische ${freshness.status}: results describe an unconfirmed or stale snapshot. Update with --refresh. This query is not reliable product-complexity evidence.`,
404
+ details: {
405
+ status: freshness.status,
406
+ checkedAt: freshness.checkedAt,
407
+ reasons: freshness.repositories.map((entry) => entry.reason),
408
+ },
409
+ };
410
+ const existingIndex = result.warnings.findIndex((entry) => entry.code === INDEX_CONTEXT_INCOMPLETE_WARNING_CODE);
411
+ const existing = result.warnings[existingIndex];
412
+ if (existing === undefined)
413
+ result.warnings.push(warning);
414
+ else
415
+ result.warnings[existingIndex] = {
416
+ ...existing,
417
+ message: `${existing.message} ${warning.message}`,
418
+ details: { ...existing.details, indexFreshness: warning.details },
419
+ };
420
+ }
421
+ /**
422
+ * Welcher Einbetter durchsucht wird — und woher diese Entscheidung stammt
423
+ * (WP-229).
424
+ *
425
+ * `--embedder=offline` und `--embedder=service` sind ausdrueckliche
426
+ * Anweisungen und gewinnen immer. `auto` fragt den Indexzustand: er ist die
427
+ * einzige Quelle, die WEISS, womit gebaut wurde. Was dabei entschieden wird,
428
+ * steht auf stderr — eine Wahl, die der Nutzer nicht sieht, ist eine Wahl,
429
+ * die er nicht ueberstimmen kann.
430
+ */
431
+ export function resolveEmbedderChoice(ctx, args, resolution) {
432
+ const flag = enumFlag(args, "embedder", ["auto", "service", "offline"], "auto");
433
+ if (flag === "offline")
434
+ return true;
435
+ if (flag === "service")
436
+ return false;
437
+ if (resolution.kind === "none") {
438
+ // Kein Zustand heisst: es wurde hier noch nicht indiziert, oder mit einer
439
+ // aelteren Fassung. Dann gilt die Konfiguration — und wenn dazu kein Index
440
+ // existiert, meldet das der Aufrufer mit der Begruendung, die es schon gab.
441
+ return false;
442
+ }
443
+ if (resolution.kind === "ambiguous") {
444
+ const states = resolution.found
445
+ .map((entry) => `${entry.state.repoId}/${entry.state.refName}: ${entry.state.embedder}`)
446
+ .join(", ");
447
+ throw new UsageError("The current repository/ref states use different embedders; `auto` " +
448
+ `would search only a subset (${states}). Select --embedder=service or ` +
449
+ "--embedder=offline explicitly.", "An explicit selection searches only locally registered refs for that profile.");
450
+ }
451
+ if (resolution.kind === "invalid") {
452
+ // The command rejects this case before selecting an embedder. Keeping the
453
+ // guard here makes the helper exhaustive if it is reused independently.
454
+ throw new EnvironmentError("The local index state is invalid; the embedding profile will not be guessed.", "Rerun the affected indexing job.");
455
+ }
456
+ const state = resolution.found.state;
457
+ note(ctx.io, `Embedding profile from the last index run: ${describeEmbedder(state.embedder)} ` +
458
+ `(${resolution.found.statePath}). ` +
459
+ "Override with --embedder=service or --embedder=offline.");
460
+ if (state.outcome !== "completed") {
461
+ note(ctx.io, `Warning: this indexing run ended as "${state.outcome}". Anything it could not finish ` +
462
+ "cannot be found here either.");
463
+ }
464
+ return state.embedder === "offline";
465
+ }
466
+ /**
467
+ * Wo nach dem Indexzustand gesucht wird. Ohne Repo-Filter gilt die bisherige
468
+ * Reihenfolge: Aufrufswurzel, Konfigurationswurzel, dann alle konfigurierten
469
+ * Repositories codepoint-sortiert. Mit `--repo` duerfen dagegen nur die
470
+ * tatsaechlich ausgewaehlten Repository-Wurzeln die Auto-Embedder-Wahl
471
+ * beeinflussen; ein unbeteiligtes Repository darf keine Ambiguitaet erzeugen.
472
+ */
473
+ export function indexStateRoots(input) {
474
+ const selected = new Set(input.selectedRepoIds);
475
+ const roots = selected.size === 0 || input.repositories.length === 0
476
+ ? [input.invocationRoot, input.configBaseDir]
477
+ : [];
478
+ const repositories = [...input.repositories]
479
+ .filter((repository) => selected.size === 0 || selected.has(repository.id))
480
+ .sort((a, b) => compareCodepoints(a.id, b.id));
481
+ for (const repository of repositories) {
482
+ roots.push(path.resolve(input.configBaseDir, repository.path));
483
+ }
484
+ return roots;
485
+ }
486
+ /**
487
+ * Resolves an omitted ref scope to the refs for which the selected collection
488
+ * has local index state. Explicit canonical IDs remain authoritative; an
489
+ * explicit human ref name expands to every compatible canonical ID carrying
490
+ * that name (for example `main` in two selected repositories).
491
+ *
492
+ * The grep path receives these IDs directly. Semantic search receives the
493
+ * richer index contexts and derives the same scope inside the engine, where
494
+ * it can still distinguish an implicit scope for provenance validation. This
495
+ * is deliberately based on profile/collection-compatible states supplied by
496
+ * the caller: an old state for another embedding space must not widen a scan.
497
+ */
498
+ export function queryRefIdsFromIndexStates(requestedRefIds, compatibleIndexStates) {
499
+ if (requestedRefIds.length === 0) {
500
+ return uniqueSortedByCodepoints(compatibleIndexStates.map(({ state }) => state.refId));
501
+ }
502
+ const canonicalIds = new Set(compatibleIndexStates.map(({ state }) => state.refId));
503
+ const resolved = [];
504
+ for (const requested of requestedRefIds) {
505
+ if (canonicalIds.has(requested)) {
506
+ resolved.push(requested);
507
+ continue;
508
+ }
509
+ const nameMatches = compatibleIndexStates
510
+ .filter(({ state }) => state.refName === requested)
511
+ .map(({ state }) => state.refId);
512
+ // Keep an unknown explicit value. It will remain a restrictive store
513
+ // filter and cannot silently fall back to the implicit/all-ref scope.
514
+ resolved.push(...(nameMatches.length === 0 ? [requested] : nameMatches));
515
+ }
516
+ return uniqueSortedByCodepoints(resolved);
517
+ }
518
+ /**
519
+ * Auto-routing follows only the generation-checked current pointer of every
520
+ * selected repo/ref. An explicit embedder selection may intentionally reopen
521
+ * an older retained profile and therefore receives the complete registry.
522
+ */
523
+ export function queryIndexStatesFromResolution(resolution, automaticEmbedder) {
524
+ if (resolution.kind === "none")
525
+ return [];
526
+ const all = resolution.all;
527
+ return automaticEmbedder ? all.filter((entry) => entry.current) : all;
528
+ }
529
+ function describeEmbedder(choice) {
530
+ return choice === "offline" ? "offline (local, in-process)" : "the configured service";
531
+ }
532
+ /**
533
+ * Ziele, die ueberhaupt nicht durchsucht werden konnten.
534
+ *
535
+ * DIESE UNTERSCHEIDUNG IST DER KERN VON E4 AN DIESER OBERFLAECHE. Der
536
+ * Abrufkern degradiert bewusst sichtbar: faellt ein Embedding-Profil aus (weil
537
+ * Ollama nicht antwortet), meldet er das als Warnung UND als Ledger-Eintrag
538
+ * und liefert die uebrigen Profile trotzdem. Fuer den Aufrufer sieht das
539
+ * Ergebnis dann aus wie „null Treffer" — und genau das waere die Luege:
540
+ * gesucht wurde nichts.
541
+ *
542
+ * Gemessen an einem blockierten Ollama gab diese Oberflaeche vor der
543
+ * Einfuehrung dieser Pruefung „Keine Treffer." mit Exit-Code 0 aus, obwohl im
544
+ * Ledger `provider_unavailable` stand. Jetzt endet derselbe Fall mit
545
+ * Exit-Code 4 und der Begruendung aus dem Ledger.
546
+ *
547
+ * Erkannt wird der Ausfall an der Kombination, die der Abrufkern EXAKT fuer
548
+ * diesen Fall schreibt: `subjectKind === "search_candidate"` zusammen mit
549
+ * `reason === "provider_unavailable"`. Ein wegen Filtern oder Budget
550
+ * ausgelassenes Ziel traegt stattdessen `excluded_by_configuration` und ist
551
+ * kein Ausfall.
552
+ */
553
+ export function failedTargets(skipped) {
554
+ return skipped.filter((entry) => entry.subjectKind === "search_candidate" && entry.reason === "provider_unavailable");
555
+ }
556
+ /** Wirft, wenn ein Ziel ausgefallen ist — „nichts durchsucht" ist kein Erfolg. */
557
+ function assertEverythingWasSearched(ctx, skipped, backend) {
558
+ const failed = failedTargets(skipped);
559
+ if (failed.length === 0)
560
+ return;
561
+ for (const entry of failed) {
562
+ note(ctx.io, `Unavailable target: ${entry.detail}`);
563
+ }
564
+ throw new EnvironmentError(`${String(failed.length)} search target(s) did not respond. The result above is ` +
565
+ "incomplete; this does not mean nothing was found.", `Run \`untangle doctor\` to check Ollama and ${backend === "lancedb" ? "LanceDB" : "Qdrant"} independently with separate deadlines.`);
566
+ }
567
+ export function buildSearchRequest(args, workspaceId, text, refIdsOverride) {
568
+ if (typeof args.flags["context"] === "number") {
569
+ throw new UsageError('Option "--context=N" applies only in grep mode.', 'For semantic search, use "--context" without a number.');
570
+ }
571
+ const limit = numberFlag(args, "limit");
572
+ const minScore = numberFlag(args, "min-score");
573
+ const paths = listFlag(args, "path");
574
+ const excludes = listFlag(args, "exclude");
575
+ const languages = listFlag(args, "lang");
576
+ const repositories = listFlag(args, "repo");
577
+ const refs = refIdsOverride === undefined ? listFlag(args, "ref") : uniqueSortedByCodepoints(refIdsOverride);
578
+ const symbolNames = listFlag(args, "symbol");
579
+ return {
580
+ query: text,
581
+ workspaceId,
582
+ ...(limit === undefined ? {} : { limit }),
583
+ ...(minScore === undefined ? {} : { minScore }),
584
+ ...(paths.length === 0 ? {} : { pathGlob: paths }),
585
+ ...(excludes.length === 0 ? {} : { pathExclude: excludes }),
586
+ ...(languages.length === 0 ? {} : { languages }),
587
+ ...(repositories.length === 0 ? {} : { repositories }),
588
+ ...(refs.length === 0 ? {} : { refs }),
589
+ ...(symbolNames.length === 0 ? {} : { symbolNames }),
590
+ mode: enumFlag(args, "mode", SEARCH_MODES, "hybrid"),
591
+ abstention: enumFlag(args, "abstention", SEARCH_ABSTENTIONS, "strict"),
592
+ sort: enumFlag(args, "sort", SEARCH_SORTS, "relevance"),
593
+ complexityBias: enumFlag(args, "complexity-bias", COMPLEXITY_BIASES, "none"),
594
+ includeContent: boolFlag(args, "content"),
595
+ includeContext: boolFlag(args, "context"),
596
+ includeLinked: boolFlag(args, "linked"),
597
+ };
598
+ }
599
+ export function buildGrepRequest(args, workspaceId, pattern, refIdsOverride) {
600
+ if (args.flags["context"] === true) {
601
+ throw new UsageError('Option "--context" requires a non-negative integer in grep mode.', 'Example: "--context=2" or "-C 2".');
602
+ }
603
+ const both = integerFlag(args, "context", 0);
604
+ const before = integerFlag(args, "before", both);
605
+ const after = integerFlag(args, "after", both);
606
+ const paths = listFlag(args, "path");
607
+ const excludes = listFlag(args, "exclude");
608
+ const languages = listFlag(args, "lang");
609
+ const repositories = listFlag(args, "repo");
610
+ const refs = refIdsOverride === undefined ? listFlag(args, "ref") : uniqueSortedByCodepoints(refIdsOverride);
611
+ const maxMatches = numberFlag(args, "max-matches");
612
+ const maxPerFile = numberFlag(args, "max-per-file");
613
+ const maxScanned = numberFlag(args, "max-scanned");
614
+ return {
615
+ pattern,
616
+ regex: boolFlag(args, "regex"),
617
+ // grep ist per Vorgabe gross-/kleinschreibungsempfindlich, wie das Werkzeug,
618
+ // dessen Namen der Modus traegt. `-i` hebt das auf.
619
+ caseSensitive: !boolFlag(args, "ignore-case"),
620
+ wholeWord: boolFlag(args, "word"),
621
+ workspaceId,
622
+ ...(repositories.length === 0 ? {} : { repositories }),
623
+ ...(refs.length === 0 ? {} : { refs }),
624
+ ...(languages.length === 0 ? {} : { languages }),
625
+ ...(paths.length === 0 ? {} : { pathGlob: paths }),
626
+ ...(excludes.length === 0 ? {} : { pathExclude: excludes }),
627
+ contextLinesBefore: before,
628
+ contextLinesAfter: after,
629
+ ...(maxMatches === undefined ? {} : { maxMatches }),
630
+ ...(maxPerFile === undefined ? {} : { maxMatchesPerFile: maxPerFile }),
631
+ ...(maxScanned === undefined ? {} : { maxScannedChunks: maxScanned }),
632
+ sort: enumFlag(args, "grep-sort", GREP_SORTS, "path"),
633
+ };
634
+ }
635
+ /* --------------------------------------------------------------------- */
636
+ export function renderSearch(ctx, set, format, explain) {
637
+ if (format !== "text") {
638
+ // WP-230: `line` und nicht `out`. Die Formatierer liefern ihren Text OHNE
639
+ // abschliessenden Zeilenumbruch; ohne ihn klebte der Ledger-Hinweis an der
640
+ // letzten Ausgabezeile, und bei `jsonl` haette die letzte Zeile keinen
641
+ // Abschluss — beides macht eine maschinenlesbare Ausgabe unlesbar.
642
+ line(ctx.io, formatSearchResultSet(set, format));
643
+ reportLedger(ctx, set.skipped.length, set.warnings.length);
644
+ return;
645
+ }
646
+ // Die Enthaltung wird VOR dem Leer-Zweig bestimmt und unabhaengig von ihm
647
+ // gemeldet. Frueher stand sie ausschliesslich in `if (totalHits === 0)` —
648
+ // eine Enthaltung wurde also aus der Listenlaenge erschlossen. Sobald
649
+ // Treffer trotz Ablehnung stehenbleiben, haette dieser Zweig geschwiegen und
650
+ // eine selbstbewusst aussehende Trefferliste gedruckt.
651
+ const insufficient = set.warnings.some((warning) => warning.code === NO_SUFFICIENT_MATCH_WARNING_CODE);
652
+ if (set.totalHits === 0) {
653
+ note(ctx.io, failedTargets(set.skipped).length > 0
654
+ ? "No results, but the search was also incomplete (see below)."
655
+ : insufficient
656
+ ? "No sufficiently relevant results found."
657
+ : "No results.");
658
+ reportLedger(ctx, set.skipped.length, set.warnings.length);
659
+ if (set.skipped.length > 0) {
660
+ note(ctx.io, "Skipped candidates appear in the --format=json skip ledger.");
661
+ }
662
+ return;
663
+ }
664
+ if (insufficient) {
665
+ note(ctx.io, "No sufficiently relevant results found.");
666
+ }
667
+ for (const group of set.groups) {
668
+ if (set.profileSeparation) {
669
+ note(ctx.io, `# Profile ${group.embeddingProfileId} (${group.repoIds.join(", ")})`);
670
+ }
671
+ // Vorbehalte unbedingt drucken. Sie standen bisher NUR unter
672
+ // `profileSeparation`, und das ist im ausgelieferten CLI nie wahr:
673
+ // `wireSearchEngine` baut genau ein Profilziel. Der Vorbehalt traegt die
674
+ // drei gemessenen Werte samt Schwellen — er war damit im Textmodus
675
+ // unsichtbar.
676
+ for (const caveat of group.caveats)
677
+ note(ctx.io, `# Qualification: ${caveat}`);
678
+ for (const hit of group.hits) {
679
+ if (explain) {
680
+ // WP-230: `formatHitAsText` endet ohne Zeilenumbruch. Mit `out` klebte
681
+ // der naechste Treffer — und am Ende der Ledger-Hinweis — an der
682
+ // letzten Zeile der Score-Zerlegung.
683
+ line(ctx.io, formatHitAsText(hit));
684
+ }
685
+ else {
686
+ line(ctx.io, compactHitLine(hit));
687
+ }
688
+ }
689
+ }
690
+ reportLedger(ctx, set.skipped.length, set.warnings.length);
691
+ }
692
+ /** Eine Zeile je Treffer — Rang, Ort, Symbol, Score. */
693
+ function compactHitLine(hit) {
694
+ const where = `${hit.filePath}:${String(hit.range.startLine)}-${String(hit.range.endLine)}`;
695
+ const symbol = hit.symbolName === undefined ? "" : ` ${hit.symbolName}`;
696
+ const incomplete = hit.incompletePayloadFields === undefined || hit.incompletePayloadFields.length === 0
697
+ ? ""
698
+ : ` [Fallback values: ${[...hit.incompletePayloadFields].sort(compareCodepoints).join(",")}]`;
699
+ const lines = [
700
+ `${String(hit.rank).padStart(3)} ${hit.score.final.toFixed(4)} ${where}${symbol}${incomplete}`,
701
+ ];
702
+ if (hit.graphContext !== undefined) {
703
+ lines.push(...formatSearchGraphRelationsAsText("context", hit.graphContext));
704
+ }
705
+ if (hit.linkedSymbols !== undefined) {
706
+ lines.push(...formatSearchGraphRelationsAsText("linked", hit.linkedSymbols));
707
+ }
708
+ return lines.join("\n");
709
+ }
710
+ export function renderGrep(ctx, set, format) {
711
+ if (format !== "text") {
712
+ // WP-230, dieselbe Ursache wie oben.
713
+ line(ctx.io, formatGrepResultSet(set, format));
714
+ reportGrepTail(ctx, set);
715
+ return;
716
+ }
717
+ for (const match of set.matches) {
718
+ for (const before of match.before) {
719
+ line(ctx.io, `${match.filePath}-${String(before.line)}-${before.text}`);
720
+ }
721
+ line(ctx.io, `${match.filePath}:${String(match.line)}:${String(match.column)}:${match.lineText}`);
722
+ for (const after of match.after) {
723
+ line(ctx.io, `${match.filePath}-${String(after.line)}-${after.text}`);
724
+ }
725
+ }
726
+ reportGrepTail(ctx, set);
727
+ }
728
+ function reportGrepTail(ctx, set) {
729
+ note(ctx.io, `${String(set.totalMatches)} results, ${String(set.scannedChunks)} chunks searched.`);
730
+ if (set.truncated) {
731
+ note(ctx.io, `Truncated; reason: ${set.truncationReason ?? "unbenannt"}.`);
732
+ }
733
+ reportLedger(ctx, set.skipped.length, set.warnings.length);
734
+ }
735
+ /**
736
+ * Der Ledger-Hinweis. Er steht auf stderr, weil er Diagnose ist — aber er
737
+ * steht IMMER, wenn es etwas zu melden gibt. Ein Ledger, den niemand sieht,
738
+ * ist kein Ledger.
739
+ */
740
+ function reportLedger(ctx, skipped, warnings) {
741
+ if (skipped === 0 && warnings === 0)
742
+ return;
743
+ note(ctx.io, `Note: ${String(skipped)} skipped candidates, ${String(warnings)} warning(s). ` +
744
+ "Both are fully available in --format=json.");
745
+ }
746
+ export function toRuntimeError(outcome, qdrantUrl, timeoutMs, request, useOffline) {
747
+ const backendLabel = qdrantUrl.startsWith("file:") ? "LanceDB" : "Qdrant";
748
+ if (outcome.timedOut) {
749
+ const mode = request === "grep" ? "grep" : (request.mode ?? "hybrid");
750
+ const usesEmbedding = mode === "semantic" || mode === "hybrid";
751
+ const stages = [`Search retrieval from ${backendLabel} at ${qdrantUrl}`];
752
+ if (usesEmbedding)
753
+ stages.push(useOffline ? "local query embedding" : "Query embedding through Ollama");
754
+ const graphFlags = [];
755
+ if (request !== "grep" && request.includeContext)
756
+ graphFlags.push("--context");
757
+ if (request !== "grep" && request.includeLinked)
758
+ graphFlags.push("--linked");
759
+ if (graphFlags.length > 0)
760
+ stages.push(`Graph enrichment (${graphFlags.join(" ")}) from ${backendLabel}`);
761
+ return new EnvironmentError(`The query was cancelled after ${String(timeoutMs)}ms; no result is available. ` +
762
+ `Mode "${mode}" covers ${stages.join("; ")}.`, `Run \`untangle doctor\` to check ${backendLabel}${usesEmbedding && !useOffline ? " and Ollama" : ""} with separate deadlines.` +
763
+ (graphFlags.length > 0
764
+ ? " Compare the runtime with the same query without graph enrichment."
765
+ : ""), { cause: outcome.error });
766
+ }
767
+ const error = outcome.error;
768
+ const message = errorMessage(error);
769
+ if ((isUntangleError(error) &&
770
+ (error.code === "QDRANT_UNAVAILABLE" ||
771
+ error.code === "LANCEDB_UNAVAILABLE" ||
772
+ error.code === "LANCEDB_SCHEMA_INCOMPATIBLE")) ||
773
+ /QDRANT_UNAVAILABLE|LANCEDB_UNAVAILABLE|fetch failed|ECONNREFUSED|ENOTFOUND|timed out/iu.test(message)) {
774
+ return new EnvironmentError(`The store at ${qdrantUrl} did not answer the query: ${message}`, `Run \`untangle doctor\` to check ${backendLabel} and Ollama independently.`, { cause: error });
775
+ }
776
+ if (/EMBEDDING|OLLAMA|model/iu.test(message)) {
777
+ return new EnvironmentError(`Could not create the query embedding: ${message}`, "Run `untangle doctor` to check whether Ollama is running and has the model.", { cause: error });
778
+ }
779
+ return new OperationalError(`Search failed: ${message}`, undefined, {
780
+ cause: error,
781
+ });
782
+ }
783
+ //# sourceMappingURL=query.js.map