scip-query 0.1.0

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 (330) hide show
  1. package/IMPROVEMENTS.md +143 -0
  2. package/PLAN.md +320 -0
  3. package/README.md +1213 -0
  4. package/dist/chunk-2QZ23IBN.js +55 -0
  5. package/dist/chunk-2QZ23IBN.js.map +1 -0
  6. package/dist/chunk-36OMT7ZJ.js +144 -0
  7. package/dist/chunk-36OMT7ZJ.js.map +1 -0
  8. package/dist/chunk-3E2X7RIE.js +101 -0
  9. package/dist/chunk-3E2X7RIE.js.map +1 -0
  10. package/dist/chunk-3UOUTZQT.js +45 -0
  11. package/dist/chunk-3UOUTZQT.js.map +1 -0
  12. package/dist/chunk-3ZZJVBIO.js +88 -0
  13. package/dist/chunk-3ZZJVBIO.js.map +1 -0
  14. package/dist/chunk-4TYLS5XX.js +10 -0
  15. package/dist/chunk-4TYLS5XX.js.map +1 -0
  16. package/dist/chunk-5FGUEU7N.js +101 -0
  17. package/dist/chunk-5FGUEU7N.js.map +1 -0
  18. package/dist/chunk-5WTJAXY2.js +61 -0
  19. package/dist/chunk-5WTJAXY2.js.map +1 -0
  20. package/dist/chunk-6NBLIDF4.js +24 -0
  21. package/dist/chunk-6NBLIDF4.js.map +1 -0
  22. package/dist/chunk-6SXADWLW.js +43 -0
  23. package/dist/chunk-6SXADWLW.js.map +1 -0
  24. package/dist/chunk-6VJ6Q7IE.js +65 -0
  25. package/dist/chunk-6VJ6Q7IE.js.map +1 -0
  26. package/dist/chunk-7OZPA5OO.js +258 -0
  27. package/dist/chunk-7OZPA5OO.js.map +1 -0
  28. package/dist/chunk-BEPIEVLR.js +76 -0
  29. package/dist/chunk-BEPIEVLR.js.map +1 -0
  30. package/dist/chunk-BFSCMC22.js +42 -0
  31. package/dist/chunk-BFSCMC22.js.map +1 -0
  32. package/dist/chunk-BP2ATLK2.js +110 -0
  33. package/dist/chunk-BP2ATLK2.js.map +1 -0
  34. package/dist/chunk-CM454WL3.js +114 -0
  35. package/dist/chunk-CM454WL3.js.map +1 -0
  36. package/dist/chunk-DCKMSTJ4.js +74 -0
  37. package/dist/chunk-DCKMSTJ4.js.map +1 -0
  38. package/dist/chunk-DEZKCZXD.js +40 -0
  39. package/dist/chunk-DEZKCZXD.js.map +1 -0
  40. package/dist/chunk-DVWGWHFW.js +99 -0
  41. package/dist/chunk-DVWGWHFW.js.map +1 -0
  42. package/dist/chunk-EMDQWNYR.js +102 -0
  43. package/dist/chunk-EMDQWNYR.js.map +1 -0
  44. package/dist/chunk-FFSWWE5O.js +33 -0
  45. package/dist/chunk-FFSWWE5O.js.map +1 -0
  46. package/dist/chunk-FGXRVW7G.js +73 -0
  47. package/dist/chunk-FGXRVW7G.js.map +1 -0
  48. package/dist/chunk-FUHJCHS4.js +158 -0
  49. package/dist/chunk-FUHJCHS4.js.map +1 -0
  50. package/dist/chunk-GJFURBEW.js +64 -0
  51. package/dist/chunk-GJFURBEW.js.map +1 -0
  52. package/dist/chunk-GTILYBH6.js +102 -0
  53. package/dist/chunk-GTILYBH6.js.map +1 -0
  54. package/dist/chunk-JJP7KQND.js +1 -0
  55. package/dist/chunk-JJP7KQND.js.map +1 -0
  56. package/dist/chunk-JKP5GH6T.js +213 -0
  57. package/dist/chunk-JKP5GH6T.js.map +1 -0
  58. package/dist/chunk-KCBMVQL5.js +38 -0
  59. package/dist/chunk-KCBMVQL5.js.map +1 -0
  60. package/dist/chunk-KVSW5KYP.js +78 -0
  61. package/dist/chunk-KVSW5KYP.js.map +1 -0
  62. package/dist/chunk-LAWMH22O.js +172 -0
  63. package/dist/chunk-LAWMH22O.js.map +1 -0
  64. package/dist/chunk-LB7OS35Q.js +72 -0
  65. package/dist/chunk-LB7OS35Q.js.map +1 -0
  66. package/dist/chunk-LUSIFBXO.js +57 -0
  67. package/dist/chunk-LUSIFBXO.js.map +1 -0
  68. package/dist/chunk-MBVNHJVN.js +44 -0
  69. package/dist/chunk-MBVNHJVN.js.map +1 -0
  70. package/dist/chunk-MGNMHKX3.js +15 -0
  71. package/dist/chunk-MGNMHKX3.js.map +1 -0
  72. package/dist/chunk-N5KEREIA.js +41 -0
  73. package/dist/chunk-N5KEREIA.js.map +1 -0
  74. package/dist/chunk-NDSQYIWT.js +71 -0
  75. package/dist/chunk-NDSQYIWT.js.map +1 -0
  76. package/dist/chunk-NUZ4OMU3.js +28 -0
  77. package/dist/chunk-NUZ4OMU3.js.map +1 -0
  78. package/dist/chunk-QOV2R2WT.js +170 -0
  79. package/dist/chunk-QOV2R2WT.js.map +1 -0
  80. package/dist/chunk-SEFSL2GF.js +78 -0
  81. package/dist/chunk-SEFSL2GF.js.map +1 -0
  82. package/dist/chunk-T6ARFSBZ.js +103 -0
  83. package/dist/chunk-T6ARFSBZ.js.map +1 -0
  84. package/dist/chunk-TBP6BICL.js +46 -0
  85. package/dist/chunk-TBP6BICL.js.map +1 -0
  86. package/dist/chunk-TDNNOR6D.js +97 -0
  87. package/dist/chunk-TDNNOR6D.js.map +1 -0
  88. package/dist/chunk-TSPZOMHC.js +195 -0
  89. package/dist/chunk-TSPZOMHC.js.map +1 -0
  90. package/dist/chunk-UNTPVD36.js +55 -0
  91. package/dist/chunk-UNTPVD36.js.map +1 -0
  92. package/dist/chunk-VRUJH4BO.js +88 -0
  93. package/dist/chunk-VRUJH4BO.js.map +1 -0
  94. package/dist/chunk-VZ7AMAFL.js +76 -0
  95. package/dist/chunk-VZ7AMAFL.js.map +1 -0
  96. package/dist/chunk-XFXDXEUN.js +24 -0
  97. package/dist/chunk-XFXDXEUN.js.map +1 -0
  98. package/dist/chunk-YZAA4LYG.js +169 -0
  99. package/dist/chunk-YZAA4LYG.js.map +1 -0
  100. package/dist/chunk-Z73NYSBZ.js +92 -0
  101. package/dist/chunk-Z73NYSBZ.js.map +1 -0
  102. package/dist/chunk-ZJRYBOEE.js +125 -0
  103. package/dist/chunk-ZJRYBOEE.js.map +1 -0
  104. package/dist/cli.js +5798 -0
  105. package/dist/cli.js.map +1 -0
  106. package/dist/db-BxaevAyc.d.ts +683 -0
  107. package/dist/index.d.ts +254 -0
  108. package/dist/index.js +1271 -0
  109. package/dist/index.js.map +1 -0
  110. package/dist/postinstall.js +167 -0
  111. package/dist/postinstall.js.map +1 -0
  112. package/dist/queries/affected.d.ts +14 -0
  113. package/dist/queries/affected.js +9 -0
  114. package/dist/queries/affected.js.map +1 -0
  115. package/dist/queries/bottlenecks.d.ts +18 -0
  116. package/dist/queries/bottlenecks.js +8 -0
  117. package/dist/queries/bottlenecks.js.map +1 -0
  118. package/dist/queries/by-kind.d.ts +20 -0
  119. package/dist/queries/by-kind.js +10 -0
  120. package/dist/queries/by-kind.js.map +1 -0
  121. package/dist/queries/call-graph.d.ts +13 -0
  122. package/dist/queries/call-graph.js +9 -0
  123. package/dist/queries/call-graph.js.map +1 -0
  124. package/dist/queries/change-surface.d.ts +10 -0
  125. package/dist/queries/change-surface.js +9 -0
  126. package/dist/queries/change-surface.js.map +1 -0
  127. package/dist/queries/clean-signature.d.ts +9 -0
  128. package/dist/queries/clean-signature.js +7 -0
  129. package/dist/queries/clean-signature.js.map +1 -0
  130. package/dist/queries/code.d.ts +17 -0
  131. package/dist/queries/code.js +9 -0
  132. package/dist/queries/code.js.map +1 -0
  133. package/dist/queries/complexity-hotspots.d.ts +19 -0
  134. package/dist/queries/complexity-hotspots.js +9 -0
  135. package/dist/queries/complexity-hotspots.js.map +1 -0
  136. package/dist/queries/complexity.d.ts +13 -0
  137. package/dist/queries/complexity.js +9 -0
  138. package/dist/queries/complexity.js.map +1 -0
  139. package/dist/queries/convergence.d.ts +11 -0
  140. package/dist/queries/convergence.js +9 -0
  141. package/dist/queries/convergence.js.map +1 -0
  142. package/dist/queries/coupling.d.ts +17 -0
  143. package/dist/queries/coupling.js +9 -0
  144. package/dist/queries/coupling.js.map +1 -0
  145. package/dist/queries/cycles.d.ts +16 -0
  146. package/dist/queries/cycles.js +8 -0
  147. package/dist/queries/cycles.js.map +1 -0
  148. package/dist/queries/dataflow.d.ts +19 -0
  149. package/dist/queries/dataflow.js +9 -0
  150. package/dist/queries/dataflow.js.map +1 -0
  151. package/dist/queries/dead.d.ts +10 -0
  152. package/dist/queries/dead.js +9 -0
  153. package/dist/queries/dead.js.map +1 -0
  154. package/dist/queries/deep-chains.d.ts +16 -0
  155. package/dist/queries/deep-chains.js +8 -0
  156. package/dist/queries/deep-chains.js.map +1 -0
  157. package/dist/queries/deps.d.ts +9 -0
  158. package/dist/queries/deps.js +9 -0
  159. package/dist/queries/deps.js.map +1 -0
  160. package/dist/queries/diff-impact.d.ts +13 -0
  161. package/dist/queries/diff-impact.js +9 -0
  162. package/dist/queries/diff-impact.js.map +1 -0
  163. package/dist/queries/doc-coverage.d.ts +14 -0
  164. package/dist/queries/doc-coverage.js +8 -0
  165. package/dist/queries/doc-coverage.js.map +1 -0
  166. package/dist/queries/drift.d.ts +25 -0
  167. package/dist/queries/drift.js +8 -0
  168. package/dist/queries/drift.js.map +1 -0
  169. package/dist/queries/extract-candidates.d.ts +25 -0
  170. package/dist/queries/extract-candidates.js +9 -0
  171. package/dist/queries/extract-candidates.js.map +1 -0
  172. package/dist/queries/fan.d.ts +29 -0
  173. package/dist/queries/fan.js +14 -0
  174. package/dist/queries/fan.js.map +1 -0
  175. package/dist/queries/files.d.ts +6 -0
  176. package/dist/queries/files.js +7 -0
  177. package/dist/queries/files.js.map +1 -0
  178. package/dist/queries/health.d.ts +18 -0
  179. package/dist/queries/health.js +21 -0
  180. package/dist/queries/health.js.map +1 -0
  181. package/dist/queries/hierarchy.d.ts +13 -0
  182. package/dist/queries/hierarchy.js +8 -0
  183. package/dist/queries/hierarchy.js.map +1 -0
  184. package/dist/queries/hotspots.d.ts +13 -0
  185. package/dist/queries/hotspots.js +8 -0
  186. package/dist/queries/hotspots.js.map +1 -0
  187. package/dist/queries/imports.d.ts +19 -0
  188. package/dist/queries/imports.js +12 -0
  189. package/dist/queries/imports.js.map +1 -0
  190. package/dist/queries/index.d.ts +47 -0
  191. package/dist/queries/index.js +207 -0
  192. package/dist/queries/index.js.map +1 -0
  193. package/dist/queries/isolated.d.ts +14 -0
  194. package/dist/queries/isolated.js +9 -0
  195. package/dist/queries/isolated.js.map +1 -0
  196. package/dist/queries/members.d.ts +10 -0
  197. package/dist/queries/members.js +8 -0
  198. package/dist/queries/members.js.map +1 -0
  199. package/dist/queries/methods.d.ts +6 -0
  200. package/dist/queries/methods.js +8 -0
  201. package/dist/queries/methods.js.map +1 -0
  202. package/dist/queries/outline.d.ts +10 -0
  203. package/dist/queries/outline.js +8 -0
  204. package/dist/queries/outline.js.map +1 -0
  205. package/dist/queries/passthrough-candidates.d.ts +18 -0
  206. package/dist/queries/passthrough-candidates.js +9 -0
  207. package/dist/queries/passthrough-candidates.js.map +1 -0
  208. package/dist/queries/redundant-reexports.d.ts +22 -0
  209. package/dist/queries/redundant-reexports.js +8 -0
  210. package/dist/queries/redundant-reexports.js.map +1 -0
  211. package/dist/queries/refs.d.ts +6 -0
  212. package/dist/queries/refs.js +7 -0
  213. package/dist/queries/refs.js.map +1 -0
  214. package/dist/queries/similar-chains.d.ts +29 -0
  215. package/dist/queries/similar-chains.js +8 -0
  216. package/dist/queries/similar-chains.js.map +1 -0
  217. package/dist/queries/similar-files.d.ts +19 -0
  218. package/dist/queries/similar-files.js +8 -0
  219. package/dist/queries/similar-files.js.map +1 -0
  220. package/dist/queries/similar-signatures.d.ts +21 -0
  221. package/dist/queries/similar-signatures.js +8 -0
  222. package/dist/queries/similar-signatures.js.map +1 -0
  223. package/dist/queries/similar.d.ts +34 -0
  224. package/dist/queries/similar.js +11 -0
  225. package/dist/queries/similar.js.map +1 -0
  226. package/dist/queries/slice.d.ts +21 -0
  227. package/dist/queries/slice.js +9 -0
  228. package/dist/queries/slice.js.map +1 -0
  229. package/dist/queries/stale-abstractions.d.ts +18 -0
  230. package/dist/queries/stale-abstractions.js +9 -0
  231. package/dist/queries/stale-abstractions.js.map +1 -0
  232. package/dist/queries/stats.d.ts +6 -0
  233. package/dist/queries/stats.js +7 -0
  234. package/dist/queries/stats.js.map +1 -0
  235. package/dist/queries/surface.d.ts +7 -0
  236. package/dist/queries/surface.js +8 -0
  237. package/dist/queries/surface.js.map +1 -0
  238. package/dist/queries/symbols.d.ts +6 -0
  239. package/dist/queries/symbols.js +9 -0
  240. package/dist/queries/symbols.js.map +1 -0
  241. package/dist/queries/system.d.ts +7 -0
  242. package/dist/queries/system.js +9 -0
  243. package/dist/queries/system.js.map +1 -0
  244. package/dist/queries/test-coverage.d.ts +22 -0
  245. package/dist/queries/test-coverage.js +11 -0
  246. package/dist/queries/test-coverage.js.map +1 -0
  247. package/dist/queries/trace.d.ts +6 -0
  248. package/dist/queries/trace.js +8 -0
  249. package/dist/queries/trace.js.map +1 -0
  250. package/dist/queries/wrapper-candidates.d.ts +17 -0
  251. package/dist/queries/wrapper-candidates.js +9 -0
  252. package/dist/queries/wrapper-candidates.js.map +1 -0
  253. package/dist/reindex-worker.js +368 -0
  254. package/dist/reindex-worker.js.map +1 -0
  255. package/docs/AGENT_GUIDE.md +359 -0
  256. package/package.json +70 -0
  257. package/reports/debloat/2026-04-10-scip-query-self-audit.md +161 -0
  258. package/skills/concrete-plan/SKILL.md +318 -0
  259. package/skills/scip-debloat/SKILL.md +413 -0
  260. package/skills/scip-explore/SKILL.md +235 -0
  261. package/skills/scip-verify/SKILL.md +323 -0
  262. package/src/cli.ts +1480 -0
  263. package/src/config.ts +117 -0
  264. package/src/db.ts +127 -0
  265. package/src/gitignore-filter.ts +143 -0
  266. package/src/index.ts +11 -0
  267. package/src/postinstall.ts +8 -0
  268. package/src/queries/affected.ts +86 -0
  269. package/src/queries/bottlenecks.ts +67 -0
  270. package/src/queries/by-kind.ts +204 -0
  271. package/src/queries/call-graph.ts +66 -0
  272. package/src/queries/change-surface.ts +110 -0
  273. package/src/queries/clean-signature.ts +22 -0
  274. package/src/queries/code.ts +101 -0
  275. package/src/queries/complexity-hotspots.ts +119 -0
  276. package/src/queries/complexity.ts +152 -0
  277. package/src/queries/convergence.ts +82 -0
  278. package/src/queries/coupling.ts +99 -0
  279. package/src/queries/cycles.ts +78 -0
  280. package/src/queries/dataflow.ts +128 -0
  281. package/src/queries/dead.ts +122 -0
  282. package/src/queries/deep-chains.ts +59 -0
  283. package/src/queries/deps.ts +46 -0
  284. package/src/queries/diff-impact.ts +204 -0
  285. package/src/queries/doc-coverage.ts +86 -0
  286. package/src/queries/drift.ts +224 -0
  287. package/src/queries/extract-candidates.ts +167 -0
  288. package/src/queries/fan.ts +148 -0
  289. package/src/queries/files.ts +16 -0
  290. package/src/queries/health.ts +324 -0
  291. package/src/queries/hierarchy.ts +49 -0
  292. package/src/queries/hotspots.ts +53 -0
  293. package/src/queries/imports.ts +95 -0
  294. package/src/queries/index.ts +45 -0
  295. package/src/queries/isolated.ts +67 -0
  296. package/src/queries/members.ts +54 -0
  297. package/src/queries/methods.ts +27 -0
  298. package/src/queries/outline.ts +52 -0
  299. package/src/queries/passthrough-candidates.ts +94 -0
  300. package/src/queries/redundant-reexports.ts +170 -0
  301. package/src/queries/refs.ts +27 -0
  302. package/src/queries/similar-chains.ts +314 -0
  303. package/src/queries/similar-files.ts +140 -0
  304. package/src/queries/similar-signatures.ts +151 -0
  305. package/src/queries/similar.ts +305 -0
  306. package/src/queries/slice.ts +154 -0
  307. package/src/queries/stale-abstractions.ts +82 -0
  308. package/src/queries/stats.ts +22 -0
  309. package/src/queries/surface.ts +34 -0
  310. package/src/queries/symbols.ts +39 -0
  311. package/src/queries/system.ts +86 -0
  312. package/src/queries/test-coverage.ts +106 -0
  313. package/src/queries/trace.ts +55 -0
  314. package/src/queries/wrapper-candidates.ts +112 -0
  315. package/src/query-support.ts +226 -0
  316. package/src/reindex/detect.ts +58 -0
  317. package/src/reindex/index.ts +153 -0
  318. package/src/reindex/indexers.ts +220 -0
  319. package/src/reindex/install.ts +125 -0
  320. package/src/reindex-worker.ts +35 -0
  321. package/src/setup.ts +202 -0
  322. package/src/symbol-parser.ts +278 -0
  323. package/src/types.ts +654 -0
  324. package/src/watch.ts +274 -0
  325. package/tests/gitignore-filter.test.ts +48 -0
  326. package/tests/queries.test.ts +300 -0
  327. package/tests/symbol-parser.test.ts +157 -0
  328. package/tsconfig.json +20 -0
  329. package/tsup.config.ts +40 -0
  330. package/vitest.config.ts +7 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/db.ts","../src/gitignore-filter.ts","../src/reindex/index.ts","../src/reindex/detect.ts","../src/reindex/indexers.ts","../src/reindex/install.ts","../src/config.ts","../src/watch.ts","../src/setup.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { statSync } from 'node:fs';\nimport type { PathFilter } from './gitignore-filter.js';\nimport type { ScipQueryConfig } from './types.js';\n\n/**\n * Thin wrapper around better-sqlite3 with a pre-configured connection\n * and helper methods for the SCIP SQLite schema.\n *\n * The schema is produced by `scip expt-convert` and is identical\n * regardless of source language (TypeScript, Rust, Python, etc.).\n *\n * Tables:\n * documents — indexed files (id, language, relative_path)\n * global_symbols — all symbols (id, symbol, display_name, kind, documentation)\n * defn_enclosing_ranges — definition locations (document_id, symbol_id, start/end line/char)\n * mentions — references & definitions (chunk_id, symbol_id, role)\n * chunks — code segments (document_id, chunk_index, start/end line, occurrences)\n */\nexport class ScipDatabase {\n readonly db: Database.Database;\n readonly config: ScipQueryConfig;\n private pathFilter: PathFilter | null;\n\n constructor(config: ScipQueryConfig, pathFilter?: PathFilter) {\n this.config = config;\n this.pathFilter = pathFilter ?? null;\n this.db = new Database(config.dbPath, { readonly: true });\n this.db.pragma('busy_timeout = 5000');\n }\n\n /** Attach a gitignore-based path filter for query results */\n setPathFilter(filter: PathFilter): void {\n this.pathFilter = filter;\n }\n\n /** Check if a path should be excluded based on .gitignore rules */\n isIgnored(relativePath: string): boolean {\n return this.pathFilter?.isIgnored(relativePath) ?? false;\n }\n\n /** Filter an array of paths using the gitignore filter */\n filterPaths(paths: string[]): string[] {\n return this.pathFilter?.filter(paths) ?? paths;\n }\n\n /**\n * The local-symbol predicate: only match symbols that are defined\n * in files NOT excluded by gitignore. This replaces the old hardcoded\n * `NOT LIKE 'node_modules/%'` check.\n *\n * Since SQLite can't evaluate JS gitignore rules inline, we use a\n * simpler approach: query broadly, then filter in JS. For queries\n * that need SQL-level filtering, use excludedPathPatterns().\n */\n get localSymbolPredicate(): string {\n // Basic SQL-level exclusions for the most common cases.\n // JS-level gitignore filtering handles the rest post-query.\n return `EXISTS (\n SELECT 1\n FROM defn_enclosing_ranges local_der\n JOIN documents local_d ON local_der.document_id = local_d.id\n WHERE local_der.symbol_id = gs.id\n ${this.pathExclusionsFor('local_d').trimStart()}\n )`;\n }\n\n /**\n * SQL WHERE clause fragments to exclude common build/dependency paths.\n * Complements the JS-level gitignore filtering for performance.\n */\n get pathExclusions(): string {\n return this.pathExclusionsFor('d');\n }\n\n /** Reusable SQL fragment: filter out synthetic/internal symbol noise */\n get symbolNoise(): string {\n return this.symbolNoiseFor('gs');\n }\n\n /** Build SQL path exclusions for one or more document table aliases */\n pathExclusionsFor(...aliases: string[]): string {\n return aliases\n .flatMap((alias) => [\n `AND ${alias}.relative_path NOT LIKE 'node_modules/%'`,\n `AND ${alias}.relative_path NOT LIKE '.git/%'`,\n ])\n .join('\\n ');\n }\n\n /** Build SQL symbol exclusions for the given global_symbols alias */\n symbolNoiseFor(alias: string): string {\n return `AND ${alias}.symbol NOT LIKE '%().(%' AND ${alias}.symbol NOT LIKE '%typeLiteral%'`;\n }\n\n /** Run a raw SQL query and return all rows */\n all<T = Record<string, unknown>>(sql: string, ...params: unknown[]): T[] {\n return this.db.prepare(sql).all(...params) as T[];\n }\n\n /** Run a raw SQL query and return the first row */\n get<T = Record<string, unknown>>(sql: string, ...params: unknown[]): T | undefined {\n return this.db.prepare(sql).get(...params) as T | undefined;\n }\n\n /** Get the database file size in bytes */\n sizeBytes(): number {\n try {\n return statSync(this.config.dbPath).size;\n } catch {\n return 0;\n }\n }\n\n /** Get the last modification time of the database file */\n lastModified(): Date | null {\n try {\n return statSync(this.config.dbPath).mtime;\n } catch {\n return null;\n }\n }\n\n close(): void {\n this.db.close();\n }\n}\n","import ignore, { type Ignore } from 'ignore';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\n/**\n * Builds a gitignore-based path filter from .gitignore files found\n * in the project directory tree. This replaces hardcoded path exclusions\n * like \"node_modules/\", \"dist/\", \"target/\", \"__pycache__/\" — instead,\n * we respect whatever the project already ignores.\n *\n * Falls back to sensible defaults if no .gitignore is found.\n */\nexport function createGitignoreFilter(projectRoot: string): PathFilter {\n const ig = ignore();\n let loaded = false;\n\n // Walk up from project root looking for .gitignore files\n // (nested .gitignore files apply to their subdirectory)\n const gitignorePaths = findGitignoreFiles(projectRoot);\n\n for (const gitignorePath of gitignorePaths) {\n try {\n const content = readFileSync(gitignorePath, 'utf-8');\n ig.add(content);\n loaded = true;\n } catch {\n // Skip unreadable files\n }\n }\n\n // If no .gitignore found, use universal defaults\n if (!loaded) {\n ig.add(DEFAULT_IGNORES);\n }\n\n return {\n isIgnored: (relativePath: string) => ig.ignores(relativePath),\n filter: (paths: string[]) => paths.filter((p) => !ig.ignores(p)),\n };\n}\n\nexport interface PathFilter {\n /** Returns true if this path should be excluded from results */\n isIgnored: (relativePath: string) => boolean;\n /** Filter an array of paths, keeping only non-ignored ones */\n filter: (paths: string[]) => string[];\n}\n\n/**\n * Find all .gitignore files from project root (including nested ones).\n * We look at the root .gitignore and any in immediate subdirectories\n * but don't recursively walk the entire tree (too expensive for large repos).\n */\nfunction findGitignoreFiles(projectRoot: string): string[] {\n const files: string[] = [];\n\n // Root .gitignore\n const rootGitignore = join(projectRoot, '.gitignore');\n if (existsSync(rootGitignore)) {\n files.push(rootGitignore);\n }\n\n // Also check parent directories (for monorepo setups where .gitignore\n // is at the repo root but the project is in a subdirectory)\n let dir = dirname(projectRoot);\n let depth = 0;\n while (dir !== dirname(dir) && depth < 5) {\n const parentGitignore = join(dir, '.gitignore');\n if (existsSync(parentGitignore)) {\n files.push(parentGitignore);\n }\n // Stop if we find a .git directory — that's the repo root\n if (existsSync(join(dir, '.git'))) break;\n dir = dirname(dir);\n depth++;\n }\n\n return files;\n}\n\n/**\n * Universal defaults when no .gitignore exists.\n * Covers build artifacts, dependency directories, and virtual environments\n * across all SCIP-supported languages.\n */\nconst DEFAULT_IGNORES = `\n# Dependencies\nnode_modules/\nvendor/\n.bundle/\n\n# Build output\ndist/\nbuild/\nout/\ntarget/\nbin/\nobj/\n\n# Python\n__pycache__/\n*.pyc\n*.pyo\n.venv/\nvenv/\n.env/\nenv/\n*.egg-info/\n\n# Rust\ntarget/\n\n# Java / Kotlin / Scala\n*.class\n.gradle/\n.mvn/\n\n# C# / .NET\nbin/\nobj/\npackages/\n\n# Go\nvendor/\n\n# Dart\n.dart_tool/\nbuild/\n\n# PHP\nvendor/\n\n# IDE / OS\n.idea/\n.vscode/\n*.swp\n*.swo\n.DS_Store\nThumbs.db\n\n# Type definitions (often noise in queries)\n*.d.ts\n`;\n","import { execFileSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { SupportedLanguage } from '../types.js';\nimport { detectLanguages } from './detect.js';\nimport { getIndexerConfig } from './indexers.js';\nimport { isBinaryAvailable, isIndexerInstalled, tryInstallIndexer, tryInstallScipCli } from './install.js';\n\nexport interface ReindexOptions {\n projectRoot: string;\n /** Override language detection — index only these languages */\n languages?: SupportedLanguage[];\n /** Path for the SCIP protobuf output (default: <projectRoot>/index.scip) */\n outputScip?: string;\n /** Path for the SQLite output (default: <projectRoot>/index.db) */\n outputDb?: string;\n /** Max Node.js heap size in MB (default: 8192) */\n maxHeapMb?: number;\n /** Callback for status updates */\n onStatus?: (message: string) => void;\n /** Extra flags for pnpm-workspace-aware TS indexing */\n pnpmWorkspaces?: boolean;\n /** Skip auto-install prompts */\n skipAutoInstall?: boolean;\n}\n\nexport interface ReindexResult {\n languages: SupportedLanguage[];\n indexPath: string;\n dbPath: string;\n durationMs: number;\n}\n\n/**\n * Reindex a project: detect languages, run the appropriate SCIP indexer(s),\n * and convert the output to SQLite.\n */\nexport async function reindex(opts: ReindexOptions): Promise<ReindexResult> {\n const {\n projectRoot,\n maxHeapMb = 8192,\n onStatus = console.log,\n skipAutoInstall = false,\n } = opts;\n\n const outputScip = opts.outputScip ?? join(projectRoot, 'index.scip');\n const outputDb = opts.outputDb ?? join(projectRoot, 'index.db');\n const start = Date.now();\n\n // Detect or use provided languages\n const languages = opts.languages ?? detectLanguages(projectRoot);\n if (languages.length === 0) {\n throw new Error(\n 'No supported languages detected in this project. ' +\n 'Looked for: tsconfig.json, Cargo.toml, go.mod, pyproject.toml, etc.',\n );\n }\n\n onStatus(`Detected languages: ${languages.join(', ')}`);\n\n // Check that the scip CLI is available, auto-install if needed\n if (!isBinaryAvailable('scip')) {\n if (skipAutoInstall) {\n throw new Error(\n 'The scip CLI is required but not found on PATH.\\n' +\n 'Install from: https://github.com/sourcegraph/scip/releases',\n );\n }\n onStatus('scip CLI not found on PATH. Attempting auto-install...');\n if (!tryInstallScipCli(onStatus)) {\n throw new Error(\n 'The scip CLI is required but could not be installed.\\n' +\n 'Install manually from: https://github.com/sourcegraph/scip/releases',\n );\n }\n }\n\n const env = {\n ...process.env,\n NODE_OPTIONS: `--max-old-space-size=${maxHeapMb}`,\n };\n\n // Index each language\n for (const lang of languages) {\n const config = getIndexerConfig(lang);\n\n // Check if indexer is installed, auto-install if needed\n if (!isIndexerInstalled(config)) {\n if (skipAutoInstall) {\n throw new Error(\n `${config.indexerBinary} is required to index ${lang} but not found on PATH.\\n` +\n (config.installUrl ? `Install from: ${config.installUrl}` : `Make sure ${config.indexerBinary} is installed and available on PATH.`),\n );\n }\n onStatus(`${config.indexerBinary} not found. Attempting auto-install...`);\n if (!tryInstallIndexer(config, onStatus)) {\n throw new Error(\n `${config.indexerBinary} is required to index ${lang} but could not be installed.\\n` +\n (config.installUrl ? `Install manually from: ${config.installUrl}` : `Make sure ${config.indexerBinary} is installed and available on PATH.`),\n );\n }\n }\n\n onStatus(`Indexing ${lang} with ${config.indexerBinary}...`);\n\n const { binary, args } = config.indexArgs({\n projectRoot,\n outputPath: outputScip,\n pnpmWorkspaces: opts.pnpmWorkspaces,\n });\n\n try {\n execFileSync(binary, args, {\n cwd: projectRoot,\n env,\n stdio: 'pipe',\n maxBuffer: 50 * 1024 * 1024,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Failed to index ${lang} with ${config.indexerBinary}: ${msg}\\n` +\n `Make sure ${config.indexerBinary} is installed and available on PATH.`,\n );\n }\n }\n\n // Convert SCIP protobuf to SQLite\n onStatus('Converting to SQLite...');\n if (!existsSync(outputScip)) {\n throw new Error(`SCIP index not found at ${outputScip} after indexing`);\n }\n\n try {\n execFileSync('scip', ['expt-convert', '--output', outputDb, outputScip], {\n env,\n stdio: 'pipe',\n maxBuffer: 50 * 1024 * 1024,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to convert SCIP index to SQLite: ${msg}`);\n }\n\n const durationMs = Date.now() - start;\n onStatus(`Done in ${(durationMs / 1000).toFixed(1)}s`);\n\n return { languages, indexPath: outputScip, dbPath: outputDb, durationMs };\n}\n\nexport { detectLanguages } from './detect.js';\nexport { getIndexerConfig, INDEXER_CONFIGS } from './indexers.js';\nexport { isBinaryAvailable, isIndexerInstalled, tryInstallIndexer, tryInstallScipCli } from './install.js';\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { SupportedLanguage } from '../types.js';\n\ninterface LanguageMarker {\n language: SupportedLanguage;\n files: string[];\n}\n\n/**\n * Marker files that indicate a language is present in a project.\n * Ordered roughly by specificity — more specific markers first.\n */\nconst LANGUAGE_MARKERS: LanguageMarker[] = [\n { language: 'typescript', files: ['tsconfig.json', 'tsconfig.base.json'] },\n { language: 'rust', files: ['Cargo.toml'] },\n { language: 'go', files: ['go.mod'] },\n { language: 'java', files: ['pom.xml', 'build.gradle', 'build.gradle.kts'] },\n { language: 'kotlin', files: ['build.gradle.kts'] },\n { language: 'scala', files: ['build.sbt'] },\n { language: 'python', files: ['pyproject.toml', 'setup.py', 'setup.cfg', 'Pipfile'] },\n { language: 'ruby', files: ['Gemfile'] },\n { language: 'csharp', files: ['*.csproj', '*.sln'] },\n { language: 'dart', files: ['pubspec.yaml'] },\n { language: 'php', files: ['composer.json'] },\n { language: 'javascript', files: ['package.json'] }, // Last — very common, low specificity\n];\n\n/**\n * Detect which languages are present in a project directory\n * by checking for marker files.\n */\nexport function detectLanguages(projectRoot: string): SupportedLanguage[] {\n const detected: SupportedLanguage[] = [];\n\n for (const marker of LANGUAGE_MARKERS) {\n for (const file of marker.files) {\n if (file.includes('*')) {\n // Glob patterns — skip for now, basic detection only\n continue;\n }\n if (existsSync(join(projectRoot, file))) {\n if (!detected.includes(marker.language)) {\n detected.push(marker.language);\n }\n break;\n }\n }\n }\n\n // If we found TypeScript, don't also report JavaScript (it's implied)\n if (detected.includes('typescript')) {\n const jsIdx = detected.indexOf('javascript');\n if (jsIdx !== -1) detected.splice(jsIdx, 1);\n }\n\n return detected;\n}\n","import type { SupportedLanguage, IndexerConfig } from '../types.js';\n\n/**\n * Indexer configurations for each supported language.\n * Each entry describes how to produce a SCIP index for that language.\n *\n * The `scip` CLI binary is required for all languages (to convert protobuf -> SQLite).\n * Each language also needs its own SCIP indexer installed.\n */\nexport const INDEXER_CONFIGS: Record<SupportedLanguage, IndexerConfig> = {\n typescript: {\n language: 'typescript',\n indexerBinary: 'scip-typescript',\n checkCommand: 'npx scip-typescript --version',\n indexArgs: ({ outputPath, pnpmWorkspaces }) => {\n const args = ['scip-typescript', 'index', '--infer-tsconfig', '--output', outputPath, '--no-progress-bar'];\n if (pnpmWorkspaces) args.splice(2, 0, '--pnpm-workspaces');\n return { binary: 'npx', args };\n },\n markerFiles: ['tsconfig.json'],\n installMethods: [\n { label: 'npm', prerequisite: 'npm', binary: 'npm', args: ['install', '-g', '@sourcegraph/scip-typescript'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-typescript',\n },\n\n javascript: {\n language: 'javascript',\n indexerBinary: 'scip-typescript',\n checkCommand: 'npx scip-typescript --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'npx',\n args: ['scip-typescript', 'index', '--infer-tsconfig', '--output', outputPath, '--no-progress-bar'],\n }),\n markerFiles: ['package.json'],\n installMethods: [\n { label: 'npm', prerequisite: 'npm', binary: 'npm', args: ['install', '-g', '@sourcegraph/scip-typescript'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-typescript',\n },\n\n java: {\n language: 'java',\n indexerBinary: 'scip-java',\n checkCommand: 'scip-java --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-java',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: ['pom.xml', 'build.gradle'],\n installMethods: [\n { label: 'coursier', prerequisite: 'cs', binary: 'cs', args: ['install', 'scip-java'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-java/releases',\n },\n\n scala: {\n language: 'scala',\n indexerBinary: 'scip-java',\n checkCommand: 'scip-java --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-java',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: ['build.sbt'],\n installMethods: [\n { label: 'coursier', prerequisite: 'cs', binary: 'cs', args: ['install', 'scip-java'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-java/releases',\n },\n\n kotlin: {\n language: 'kotlin',\n indexerBinary: 'scip-java',\n checkCommand: 'scip-java --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-java',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: ['build.gradle.kts'],\n installMethods: [\n { label: 'coursier', prerequisite: 'cs', binary: 'cs', args: ['install', 'scip-java'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-java/releases',\n },\n\n rust: {\n language: 'rust',\n indexerBinary: 'rust-analyzer',\n checkCommand: 'rust-analyzer --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'rust-analyzer',\n args: ['scip', '.', '--output', outputPath],\n }),\n markerFiles: ['Cargo.toml'],\n installMethods: [\n { label: 'rustup', prerequisite: 'rustup', binary: 'rustup', args: ['component', 'add', 'rust-analyzer'] },\n ],\n installUrl: 'https://github.com/rust-lang/rust-analyzer',\n },\n\n python: {\n language: 'python',\n indexerBinary: 'scip-python',\n checkCommand: 'scip-python --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-python',\n args: ['index', '--output', outputPath, '--project-name', 'project'],\n }),\n markerFiles: ['pyproject.toml', 'setup.py'],\n installMethods: [\n { label: 'npm', prerequisite: 'npm', binary: 'npm', args: ['install', '-g', 'scip-python-plus'] },\n ],\n installUrl: 'https://github.com/PlunderStruck/scip-python',\n },\n\n ruby: {\n language: 'ruby',\n indexerBinary: 'scip-ruby',\n checkCommand: 'scip-ruby --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-ruby',\n args: ['--output', outputPath],\n }),\n markerFiles: ['Gemfile'],\n installMethods: [],\n installUrl: 'https://github.com/sourcegraph/scip-ruby/releases',\n },\n\n go: {\n language: 'go',\n indexerBinary: 'scip-go',\n checkCommand: 'scip-go --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-go',\n args: ['--output', outputPath],\n }),\n markerFiles: ['go.mod'],\n installMethods: [\n { label: 'go install', prerequisite: 'go', binary: 'go', args: ['install', 'github.com/sourcegraph/scip-go@latest'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-go',\n },\n\n cpp: {\n language: 'cpp',\n indexerBinary: 'scip-clang',\n checkCommand: 'scip-clang --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-clang',\n args: ['--output', outputPath],\n }),\n markerFiles: ['CMakeLists.txt', 'Makefile'],\n installMethods: [],\n installUrl: 'https://github.com/sourcegraph/scip-clang/releases',\n },\n\n c: {\n language: 'c',\n indexerBinary: 'scip-clang',\n checkCommand: 'scip-clang --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-clang',\n args: ['--output', outputPath],\n }),\n markerFiles: ['CMakeLists.txt', 'Makefile'],\n installMethods: [],\n installUrl: 'https://github.com/sourcegraph/scip-clang/releases',\n },\n\n csharp: {\n language: 'csharp',\n indexerBinary: 'scip-dotnet',\n checkCommand: 'scip-dotnet --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-dotnet',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: [],\n installMethods: [\n { label: 'dotnet', prerequisite: 'dotnet', binary: 'dotnet', args: ['tool', 'install', '--global', 'scip-dotnet'] },\n ],\n installUrl: 'https://github.com/sourcegraph/scip-dotnet/releases',\n },\n\n dart: {\n language: 'dart',\n indexerBinary: 'scip-dart',\n checkCommand: 'scip-dart --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-dart',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: ['pubspec.yaml'],\n installMethods: [\n { label: 'dart pub', prerequisite: 'dart', binary: 'dart', args: ['pub', 'global', 'activate', 'scip_dart'] },\n ],\n installUrl: 'https://github.com/Workiva/scip-dart/releases',\n },\n\n php: {\n language: 'php',\n indexerBinary: 'scip-php',\n checkCommand: 'scip-php --version',\n indexArgs: ({ outputPath }) => ({\n binary: 'scip-php',\n args: ['index', '--output', outputPath],\n }),\n markerFiles: ['composer.json'],\n installMethods: [\n { label: 'composer', prerequisite: 'composer', binary: 'composer', args: ['global', 'require', 'davidrjenni/scip-php'] },\n ],\n installUrl: 'https://github.com/davidrjenni/scip-php/releases',\n },\n};\n\n/** Get the indexer config for a language */\nexport function getIndexerConfig(language: SupportedLanguage): IndexerConfig {\n return INDEXER_CONFIGS[language];\n}\n","import { execFileSync } from 'node:child_process';\nimport { platform } from 'node:os';\nimport type { IndexerConfig } from '../types.js';\n\nconst IS_WINDOWS = platform() === 'win32';\n\n/**\n * Check if a binary is available on PATH.\n */\nexport function isBinaryAvailable(name: string): boolean {\n const cmd = IS_WINDOWS ? 'where' : 'which';\n try {\n execFileSync(cmd, [name], { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if an indexer's binary is available on PATH.\n */\nexport function isIndexerInstalled(config: IndexerConfig): boolean {\n return isBinaryAvailable(config.indexerBinary);\n}\n\n/**\n * Attempt to auto-install an indexer using its configured install methods.\n * Tries each method in order, checking prerequisites first.\n * Returns true if installation succeeded.\n */\nexport function tryInstallIndexer(\n config: IndexerConfig,\n onStatus: (msg: string) => void,\n): boolean {\n const methods = config.installMethods;\n if (!methods?.length) {\n onStatus(`No auto-install method available for ${config.indexerBinary}.`);\n if (config.installUrl) {\n onStatus(`Install manually from: ${config.installUrl}`);\n }\n return false;\n }\n\n for (const method of methods) {\n if (!isBinaryAvailable(method.prerequisite)) {\n continue;\n }\n\n onStatus(`Installing ${config.indexerBinary} via ${method.label}...`);\n try {\n execFileSync(method.binary, method.args, {\n stdio: 'inherit',\n timeout: 300_000,\n env: process.env,\n });\n\n if (isIndexerInstalled(config)) {\n onStatus(`Successfully installed ${config.indexerBinary} via ${method.label}`);\n return true;\n }\n onStatus(`${method.label} command completed but ${config.indexerBinary} not found on PATH`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onStatus(`${method.label} install failed: ${msg}`);\n }\n }\n\n onStatus(`Could not auto-install ${config.indexerBinary}.`);\n if (config.installUrl) {\n onStatus(`Install manually from: ${config.installUrl}`);\n }\n return false;\n}\n\n/**\n * Attempt to auto-install the `scip` CLI binary.\n * Tries brew (macOS), then go install, then prints manual instructions.\n * Returns true if installation succeeded.\n */\nexport function tryInstallScipCli(\n onStatus: (msg: string) => void,\n): boolean {\n // macOS: try Homebrew first\n if (platform() === 'darwin' && isBinaryAvailable('brew')) {\n onStatus('Installing scip CLI via Homebrew...');\n try {\n execFileSync('brew', ['install', 'sourcegraph/scip/scip'], {\n stdio: 'inherit',\n timeout: 300_000,\n env: process.env,\n });\n if (isBinaryAvailable('scip')) {\n onStatus('Successfully installed scip CLI via Homebrew');\n return true;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onStatus(`Homebrew install failed: ${msg}`);\n }\n }\n\n // Any platform: try go install\n if (isBinaryAvailable('go')) {\n onStatus('Installing scip CLI via go install...');\n try {\n execFileSync('go', ['install', 'github.com/sourcegraph/scip/cmd/scip@latest'], {\n stdio: 'inherit',\n timeout: 300_000,\n env: process.env,\n });\n if (isBinaryAvailable('scip')) {\n onStatus('Successfully installed scip CLI via go install');\n return true;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n onStatus(`go install failed: ${msg}`);\n }\n }\n\n onStatus('Could not auto-install scip CLI.');\n onStatus('Install manually from: https://github.com/sourcegraph/scip/releases');\n return false;\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport type { ProjectConfig, WatchConfig } from './types.js';\n\nconst CONFIG_FILENAME = '.scipquery.json';\n\nconst DEFAULT_WATCH: Required<WatchConfig> = {\n enabled: false,\n debounceMs: 30_000,\n cooldownMs: 60_000,\n ignore: [],\n};\n\n/**\n * Load project config from .scipquery.json in the project root.\n * Returns defaults for anything not specified.\n */\nexport function loadProjectConfig(projectRoot: string): ProjectConfig {\n const configPath = join(projectRoot, CONFIG_FILENAME);\n\n if (!existsSync(configPath)) {\n return {};\n }\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as ProjectConfig;\n } catch {\n return {};\n }\n}\n\n/** Resolve watch config with defaults applied */\nexport function resolveWatchConfig(config: ProjectConfig): Required<WatchConfig> {\n return {\n ...DEFAULT_WATCH,\n ...config.watch,\n };\n}\n\n/**\n * Resolve the cache directory for a project's SCIP index.\n *\n * Default: ~/.cache/scip-query/projects/<hash>/\n * Override: project config dbPath, or SCIP_QUERY_DB_PATH env var\n *\n * The hash is derived from the absolute project path so each\n * project gets its own isolated index storage.\n */\nexport function resolveCacheDir(projectRoot: string, config?: ProjectConfig): string {\n // CLI/env override\n const envOverride = process.env['SCIP_QUERY_CACHE_DIR'];\n if (envOverride) return ensureDir(envOverride);\n\n // Project config override\n if (config?.dbPath) return ensureDir(resolve(projectRoot, config.dbPath));\n\n // Default: XDG cache dir / fallback to ~/.cache\n const xdgCache = process.env['XDG_CACHE_HOME'];\n const cacheBase = xdgCache || join(homedir(), '.cache');\n const projectHash = createHash('sha256')\n .update(resolve(projectRoot))\n .digest('hex')\n .slice(0, 12);\n\n const dir = join(cacheBase, 'scip-query', 'projects', projectHash);\n return ensureDir(dir);\n}\n\n/**\n * Resolve all paths for a project's index files.\n */\nexport function resolveIndexPaths(projectRoot: string, config?: ProjectConfig): {\n cacheDir: string;\n dbPath: string;\n indexPath: string;\n metaPath: string;\n} {\n const cacheDir = resolveCacheDir(projectRoot, config);\n return {\n cacheDir,\n dbPath: join(cacheDir, 'index.db'),\n indexPath: join(cacheDir, 'index.scip'),\n metaPath: join(cacheDir, 'meta.json'),\n };\n}\n\n/**\n * Scaffold a default .scipquery.json in the project root.\n * Does not overwrite an existing config.\n */\nexport function initProjectConfig(projectRoot: string, languages: string[]): string {\n const configPath = join(projectRoot, CONFIG_FILENAME);\n\n if (existsSync(configPath)) {\n return configPath;\n }\n\n const config: ProjectConfig = {\n languages: languages as ProjectConfig['languages'],\n watch: {\n enabled: false,\n debounceMs: 30_000,\n cooldownMs: 60_000,\n },\n };\n\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n');\n return configPath;\n}\n\nfunction ensureDir(dir: string): string {\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n","import { watch } from 'node:fs';\nimport { readFileSync, existsSync, renameSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport { fork } from 'node:child_process';\nimport ignore from 'ignore';\nimport type { WatcherStatus, ProjectConfig, SupportedLanguage } from './types.js';\nimport { resolveWatchConfig, resolveIndexPaths } from './config.js';\nimport { createGitignoreFilter } from './gitignore-filter.js';\n\nexport interface WatcherOptions {\n projectRoot: string;\n config: ProjectConfig;\n languages?: SupportedLanguage[];\n onStatus?: (status: WatcherStatus) => void;\n onReindexComplete?: (durationMs: number) => void;\n onError?: (error: Error) => void;\n}\n\n/**\n * File watcher that triggers single-flight background reindexing.\n *\n * Design:\n * - Debounce: waits 30s (configurable) after the last file change\n * - Single-flight: only one reindex runs at a time, never queued\n * - Dirty flag: changes during reindex schedule ONE follow-up\n * - Cooldown: minimum interval between reindex completions\n * - Atomic swap: writes to index.db.tmp, renames on success\n */\nexport class Watcher {\n private projectRoot: string;\n private watchConfig: Required<NonNullable<ProjectConfig['watch']>>;\n private indexPaths: ReturnType<typeof resolveIndexPaths>;\n private languages?: SupportedLanguage[];\n private pnpmWorkspaces: boolean;\n\n private onStatus: (status: WatcherStatus) => void;\n private onReindexComplete: (durationMs: number) => void;\n private onError: (error: Error) => void;\n\n // State machine\n private status: WatcherStatus = { state: 'idle' };\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private cooldownTimer: ReturnType<typeof setTimeout> | null = null;\n private dirty = false;\n private changedFiles = 0;\n private reindexInFlight = false;\n private lastReindexEnd = 0;\n\n // fs.watch watchers (one per watched directory)\n private fsWatchers: ReturnType<typeof watch>[] = [];\n private gitignoreFilter: ReturnType<typeof createGitignoreFilter>;\n private extraIgnore: ReturnType<typeof ignore>;\n private stopped = false;\n\n constructor(opts: WatcherOptions) {\n this.projectRoot = opts.projectRoot;\n this.watchConfig = resolveWatchConfig(opts.config);\n this.indexPaths = resolveIndexPaths(opts.projectRoot, opts.config);\n this.languages = opts.languages;\n this.pnpmWorkspaces = opts.config.indexer?.typescript?.pnpmWorkspaces ?? false;\n\n this.onStatus = opts.onStatus ?? (() => {});\n this.onReindexComplete = opts.onReindexComplete ?? (() => {});\n this.onError = opts.onError ?? ((e) => console.error(e.message));\n\n this.gitignoreFilter = createGitignoreFilter(opts.projectRoot);\n this.extraIgnore = ignore();\n if (this.watchConfig.ignore.length > 0) {\n this.extraIgnore.add(this.watchConfig.ignore);\n }\n }\n\n /** Start watching for file changes */\n start(): void {\n this.stopped = false;\n this.setStatus({ state: 'idle' });\n\n // Use recursive fs.watch on the project root\n // This is supported on macOS (FSEvents) and Windows\n // On Linux, falls back to inotify (may need per-directory watchers for large trees)\n try {\n const watcher = watch(\n this.projectRoot,\n { recursive: true },\n (_event, filename) => {\n if (filename && !this.stopped) {\n this.handleFileChange(filename);\n }\n },\n );\n this.fsWatchers.push(watcher);\n } catch {\n this.onError(new Error(\n 'Failed to start file watcher. On Linux, you may need to increase inotify limits: ' +\n 'sysctl -w fs.inotify.max_user_watches=524288',\n ));\n }\n }\n\n /** Stop watching and clean up */\n stop(): void {\n this.stopped = true;\n for (const w of this.fsWatchers) w.close();\n this.fsWatchers = [];\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.cooldownTimer) clearTimeout(this.cooldownTimer);\n this.setStatus({ state: 'idle' });\n }\n\n /** Get current watcher status */\n getStatus(): WatcherStatus {\n return this.status;\n }\n\n // ── Internal ─────────────────────────────────────────────\n\n private handleFileChange(filename: string): void {\n // Filter: skip gitignored files and extra ignore patterns\n const rel = relative(this.projectRoot, join(this.projectRoot, filename));\n if (this.gitignoreFilter.isIgnored(rel)) return;\n if (this.extraIgnore.ignores(rel)) return;\n\n // Skip the index files themselves\n if (filename.endsWith('index.db') || filename.endsWith('index.scip') ||\n filename.endsWith('index.db.tmp') || filename.endsWith('.scipquery.json')) {\n return;\n }\n\n this.changedFiles++;\n\n if (this.reindexInFlight) {\n // Reindex is running — just mark dirty, don't schedule anything\n this.dirty = true;\n this.setStatus({\n state: 'indexing',\n startedAt: (this.status as { startedAt: number }).startedAt,\n });\n return;\n }\n\n if (this.status.state === 'cooldown') {\n // In cooldown — mark dirty, the cooldown handler will pick it up\n this.dirty = true;\n this.setStatus({ state: 'cooldown', until: (this.status as { until: number }).until, dirty: true });\n return;\n }\n\n // Reset the debounce timer — every new change pushes the trigger out\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n\n const reindexAt = Date.now() + this.watchConfig.debounceMs;\n this.setStatus({ state: 'waiting', changedFiles: this.changedFiles, reindexAt });\n\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.triggerReindex();\n }, this.watchConfig.debounceMs);\n }\n\n private triggerReindex(): void {\n if (this.reindexInFlight || this.stopped) return;\n\n // Check cooldown\n const timeSinceLastReindex = Date.now() - this.lastReindexEnd;\n if (this.lastReindexEnd > 0 && timeSinceLastReindex < this.watchConfig.cooldownMs) {\n const remaining = this.watchConfig.cooldownMs - timeSinceLastReindex;\n this.dirty = true;\n const until = Date.now() + remaining;\n this.setStatus({ state: 'cooldown', until, dirty: true });\n\n this.cooldownTimer = setTimeout(() => {\n this.cooldownTimer = null;\n if (this.dirty && !this.stopped) {\n this.dirty = false;\n this.triggerReindex();\n }\n }, remaining);\n return;\n }\n\n this.reindexInFlight = true;\n this.dirty = false;\n this.changedFiles = 0;\n const startedAt = Date.now();\n this.setStatus({ state: 'indexing', startedAt });\n\n // Run reindex in a child process so it doesn't block the watcher\n this.runReindex()\n .then((durationMs) => {\n this.reindexInFlight = false;\n this.lastReindexEnd = Date.now();\n this.onReindexComplete(durationMs);\n\n if (this.dirty && !this.stopped) {\n // Changes arrived during reindex — enter cooldown then reindex again\n const until = Date.now() + this.watchConfig.cooldownMs;\n this.setStatus({ state: 'cooldown', until, dirty: true });\n\n this.cooldownTimer = setTimeout(() => {\n this.cooldownTimer = null;\n if (this.dirty && !this.stopped) {\n this.dirty = false;\n this.triggerReindex();\n } else {\n this.setStatus({ state: 'idle' });\n }\n }, this.watchConfig.cooldownMs);\n } else {\n this.setStatus({ state: 'idle' });\n }\n })\n .catch((err) => {\n this.reindexInFlight = false;\n this.lastReindexEnd = Date.now();\n this.onError(err instanceof Error ? err : new Error(String(err)));\n this.setStatus({ state: 'idle' });\n });\n }\n\n /**\n * Run the reindex in a forked child process.\n * Writes to index.db.tmp, then atomically renames to index.db.\n */\n private runReindex(): Promise<number> {\n return new Promise((resolve, reject) => {\n const start = Date.now();\n const tmpDb = this.indexPaths.dbPath + '.tmp';\n const tmpScip = this.indexPaths.indexPath + '.tmp';\n\n // Fork a child that runs the reindex\n const child = fork(\n new URL('./reindex-worker.js', import.meta.url).pathname,\n [],\n {\n env: {\n ...process.env,\n SCIP_REINDEX_PROJECT_ROOT: this.projectRoot,\n SCIP_REINDEX_OUTPUT_SCIP: tmpScip,\n SCIP_REINDEX_OUTPUT_DB: tmpDb,\n SCIP_REINDEX_LANGUAGES: this.languages?.join(',') ?? '',\n SCIP_REINDEX_PNPM_WORKSPACES: this.pnpmWorkspaces ? '1' : '',\n },\n stdio: 'pipe',\n },\n );\n\n child.on('exit', (code) => {\n if (code === 0) {\n // Atomic swap\n try {\n if (existsSync(tmpDb)) {\n renameSync(tmpDb, this.indexPaths.dbPath);\n }\n if (existsSync(tmpScip)) {\n renameSync(tmpScip, this.indexPaths.indexPath);\n }\n resolve(Date.now() - start);\n } catch (err) {\n reject(new Error(`Atomic swap failed: ${err}`));\n }\n } else {\n reject(new Error(`Reindex worker exited with code ${code}`));\n }\n });\n\n child.on('error', reject);\n });\n }\n\n private setStatus(status: WatcherStatus): void {\n this.status = status;\n this.onStatus(status);\n }\n}\n","import {\n existsSync, mkdirSync, symlinkSync, readlinkSync,\n unlinkSync, chmodSync, createWriteStream,\n} from 'node:fs';\nimport { join, dirname, resolve } from 'node:path';\nimport { homedir, platform, arch } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { get as httpsGet } from 'node:https';\nimport { tryInstallScipCli } from './reindex/install.js';\n\nconst IS_WINDOWS = platform() === 'win32';\nconst SKILLS = ['concrete-plan', 'scip-explore', 'scip-debloat', 'scip-verify'];\nconst SCIP_VERSION = 'v0.7.0';\n\n// ── Skills Installation ────────────────────────────────────\n\nexport interface InstallSkillsResult {\n installed: string[];\n skipped: string[];\n alreadyLinked: string[];\n}\n\n/**\n * Install scip-query skills into both Claude Code (~/.claude/skills/)\n * and Codex (~/.codex/skills/). Uses symlinks (junctions on Windows)\n * so skills auto-update when the package updates.\n */\nexport function installSkills(\n opts: { quiet?: boolean } = {},\n): InstallSkillsResult {\n const log = opts.quiet ? () => {} : console.log;\n const thisFile = fileURLToPath(import.meta.url);\n const skillsSource = resolve(dirname(thisFile), '..', 'skills');\n\n const targets = [\n join(homedir(), '.claude', 'skills'),\n join(homedir(), '.codex', 'skills'),\n ];\n\n const result: InstallSkillsResult = {\n installed: [],\n skipped: [],\n alreadyLinked: [],\n };\n\n for (const targetDir of targets) {\n // Only install if the parent directory exists (tool is installed)\n const parentDir = dirname(targetDir);\n if (!existsSync(parentDir)) {\n continue;\n }\n\n mkdirSync(targetDir, { recursive: true });\n const toolName = targetDir.includes('.codex') ? 'Codex' : 'Claude';\n\n for (const skill of SKILLS) {\n const source = join(skillsSource, skill);\n const target = join(targetDir, skill);\n\n if (!existsSync(source)) {\n result.skipped.push(`${toolName}/${skill}`);\n continue;\n }\n\n if (existsSync(target)) {\n try {\n const existing = readlinkSync(target);\n if (resolve(existing) === resolve(source)) {\n result.alreadyLinked.push(`${toolName}/${skill}`);\n log(` ok: ${skill} → ${toolName} (already linked)`);\n continue;\n }\n } catch {\n // Not a symlink — don't overwrite user's custom skill\n result.skipped.push(`${toolName}/${skill}`);\n log(` skip: ${skill} → ${toolName} (exists, not a symlink)`);\n continue;\n }\n unlinkSync(target);\n }\n\n // Use 'junction' on Windows (doesn't need admin), 'dir' elsewhere\n symlinkSync(source, target, IS_WINDOWS ? 'junction' : 'dir');\n result.installed.push(`${toolName}/${skill}`);\n log(` done: ${skill} → ${toolName}`);\n }\n }\n\n return result;\n}\n\n// ── SCIP CLI Binary Detection & Installation ───────────────\n\n/**\n * Check if the `scip` CLI binary is available on PATH.\n */\nexport function isScipInstalled(): boolean {\n try {\n const cmd = IS_WINDOWS ? 'where' : 'which';\n execFileSync(cmd, ['scip'], { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the scip CLI version if installed.\n */\nexport function getScipVersion(): string | null {\n try {\n const output = execFileSync('scip', ['--version'], { stdio: 'pipe' }).toString().trim();\n return output;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the download URL for the scip CLI binary for this platform.\n */\nfunction getScipDownloadUrl(): { url: string; filename: string } | null {\n const os = platform();\n const cpu = arch();\n\n let osName: string;\n let archName: string;\n let ext: string;\n\n switch (os) {\n case 'darwin': osName = 'darwin'; ext = 'tar.gz'; break;\n case 'linux': osName = 'linux'; ext = 'tar.gz'; break;\n case 'win32': osName = 'windows'; ext = 'zip'; break;\n default: return null;\n }\n\n switch (cpu) {\n case 'arm64': archName = 'arm64'; break;\n case 'x64': archName = 'amd64'; break;\n default: return null;\n }\n\n const filename = `scip-${osName}-${archName}.${ext}`;\n const url = `https://github.com/sourcegraph/scip/releases/download/${SCIP_VERSION}/${filename}`;\n return { url, filename };\n}\n\n/**\n * Print instructions for installing the scip CLI binary.\n */\nexport function printScipInstallInstructions(): void {\n const download = getScipDownloadUrl();\n\n console.log('\\nThe `scip` CLI is required but not found on PATH.\\n');\n\n if (platform() === 'darwin') {\n console.log('Install via Homebrew:');\n console.log(' brew install sourcegraph/scip/scip\\n');\n console.log('Or download manually:');\n } else {\n console.log('Download from:');\n }\n\n if (download) {\n console.log(` ${download.url}\\n`);\n } else {\n console.log(` https://github.com/sourcegraph/scip/releases/tag/${SCIP_VERSION}\\n`);\n }\n\n console.log('After installing, ensure `scip` is on your PATH and run `scip-query reindex`.');\n}\n\n// ── First-Run Setup ────────────────────────────────────────\n\n/**\n * Run first-time setup: install skills and check for scip binary.\n * Called from the postinstall script.\n */\nexport function postinstall(): void {\n console.log('scip-query: installing skills...');\n const result = installSkills({ quiet: false });\n\n const total = result.installed.length + result.alreadyLinked.length;\n if (total > 0) {\n console.log(`\\n${result.installed.length} skill(s) installed, ${result.alreadyLinked.length} already linked.`);\n }\n\n // Check for scip binary — auto-install if missing\n if (!isScipInstalled()) {\n console.log('\\nscip CLI not found on PATH. Attempting auto-install...');\n const installed = tryInstallScipCli(console.log);\n if (!installed) {\n printScipInstallInstructions();\n }\n } else {\n const version = getScipVersion();\n console.log(`\\nscip CLI: ${version ?? 'installed'}`);\n }\n\n console.log('');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,cAAc;AACrB,SAAS,gBAAgB;AAkBlB,IAAM,eAAN,MAAmB;AAAA,EACf;AAAA,EACA;AAAA,EACD;AAAA,EAER,YAAY,QAAyB,YAAyB;AAC5D,SAAK,SAAS;AACd,SAAK,aAAa,cAAc;AAChC,SAAK,KAAK,IAAI,SAAS,OAAO,QAAQ,EAAE,UAAU,KAAK,CAAC;AACxD,SAAK,GAAG,OAAO,qBAAqB;AAAA,EACtC;AAAA;AAAA,EAGA,cAAc,QAA0B;AACtC,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGA,UAAU,cAA+B;AACvC,WAAO,KAAK,YAAY,UAAU,YAAY,KAAK;AAAA,EACrD;AAAA;AAAA,EAGA,YAAY,OAA2B;AACrC,WAAO,KAAK,YAAY,OAAO,KAAK,KAAK;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IAAI,uBAA+B;AAGjC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,UAKD,KAAK,kBAAkB,SAAS,EAAE,UAAU,CAAC;AAAA;AAAA,EAErD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,kBAAkB,GAAG;AAAA,EACnC;AAAA;AAAA,EAGA,IAAI,cAAsB;AACxB,WAAO,KAAK,eAAe,IAAI;AAAA,EACjC;AAAA;AAAA,EAGA,qBAAqB,SAA2B;AAC9C,WAAO,QACJ,QAAQ,CAAC,UAAU;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,IACd,CAAC,EACA,KAAK,UAAU;AAAA,EACpB;AAAA;AAAA,EAGA,eAAe,OAAuB;AACpC,WAAO,OAAO,KAAK,iCAAiC,KAAK;AAAA,EAC3D;AAAA;AAAA,EAGA,IAAiC,QAAgB,QAAwB;AACvE,WAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAAA,EAC3C;AAAA;AAAA,EAGA,IAAiC,QAAgB,QAAkC;AACjF,WAAO,KAAK,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AAAA,EAC3C;AAAA;AAAA,EAGA,YAAoB;AAClB,QAAI;AACF,aAAO,SAAS,KAAK,OAAO,MAAM,EAAE;AAAA,IACtC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,eAA4B;AAC1B,QAAI;AACF,aAAO,SAAS,KAAK,OAAO,MAAM,EAAE;AAAA,IACtC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AACF;;;AC9HA,OAAO,YAA6B;AACpC,SAAS,cAAc,kBAAkB;AACzC,SAAS,MAAM,eAAe;AAUvB,SAAS,sBAAsB,aAAiC;AACrE,QAAM,KAAK,OAAO;AAClB,MAAI,SAAS;AAIb,QAAM,iBAAiB,mBAAmB,WAAW;AAErD,aAAW,iBAAiB,gBAAgB;AAC1C,QAAI;AACF,YAAM,UAAU,aAAa,eAAe,OAAO;AACnD,SAAG,IAAI,OAAO;AACd,eAAS;AAAA,IACX,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,MAAI,CAAC,QAAQ;AACX,OAAG,IAAI,eAAe;AAAA,EACxB;AAEA,SAAO;AAAA,IACL,WAAW,CAAC,iBAAyB,GAAG,QAAQ,YAAY;AAAA,IAC5D,QAAQ,CAAC,UAAoB,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC;AAAA,EACjE;AACF;AAcA,SAAS,mBAAmB,aAA+B;AACzD,QAAMA,SAAkB,CAAC;AAGzB,QAAM,gBAAgB,KAAK,aAAa,YAAY;AACpD,MAAI,WAAW,aAAa,GAAG;AAC7B,IAAAA,OAAM,KAAK,aAAa;AAAA,EAC1B;AAIA,MAAI,MAAM,QAAQ,WAAW;AAC7B,MAAI,QAAQ;AACZ,SAAO,QAAQ,QAAQ,GAAG,KAAK,QAAQ,GAAG;AACxC,UAAM,kBAAkB,KAAK,KAAK,YAAY;AAC9C,QAAI,WAAW,eAAe,GAAG;AAC/B,MAAAA,OAAM,KAAK,eAAe;AAAA,IAC5B;AAEA,QAAI,WAAW,KAAK,KAAK,MAAM,CAAC,EAAG;AACnC,UAAM,QAAQ,GAAG;AACjB;AAAA,EACF;AAEA,SAAOA;AACT;AAOA,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACrFxB,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;;;ACFrB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAYrB,IAAM,mBAAqC;AAAA,EACzC,EAAE,UAAU,cAAc,OAAO,CAAC,iBAAiB,oBAAoB,EAAE;AAAA,EACzE,EAAE,UAAU,QAAQ,OAAO,CAAC,YAAY,EAAE;AAAA,EAC1C,EAAE,UAAU,MAAM,OAAO,CAAC,QAAQ,EAAE;AAAA,EACpC,EAAE,UAAU,QAAQ,OAAO,CAAC,WAAW,gBAAgB,kBAAkB,EAAE;AAAA,EAC3E,EAAE,UAAU,UAAU,OAAO,CAAC,kBAAkB,EAAE;AAAA,EAClD,EAAE,UAAU,SAAS,OAAO,CAAC,WAAW,EAAE;AAAA,EAC1C,EAAE,UAAU,UAAU,OAAO,CAAC,kBAAkB,YAAY,aAAa,SAAS,EAAE;AAAA,EACpF,EAAE,UAAU,QAAQ,OAAO,CAAC,SAAS,EAAE;AAAA,EACvC,EAAE,UAAU,UAAU,OAAO,CAAC,YAAY,OAAO,EAAE;AAAA,EACnD,EAAE,UAAU,QAAQ,OAAO,CAAC,cAAc,EAAE;AAAA,EAC5C,EAAE,UAAU,OAAO,OAAO,CAAC,eAAe,EAAE;AAAA,EAC5C,EAAE,UAAU,cAAc,OAAO,CAAC,cAAc,EAAE;AAAA;AACpD;AAMO,SAAS,gBAAgB,aAA0C;AACxE,QAAM,WAAgC,CAAC;AAEvC,aAAW,UAAU,kBAAkB;AACrC,eAAW,QAAQ,OAAO,OAAO;AAC/B,UAAI,KAAK,SAAS,GAAG,GAAG;AAEtB;AAAA,MACF;AACA,UAAID,YAAWC,MAAK,aAAa,IAAI,CAAC,GAAG;AACvC,YAAI,CAAC,SAAS,SAAS,OAAO,QAAQ,GAAG;AACvC,mBAAS,KAAK,OAAO,QAAQ;AAAA,QAC/B;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,SAAS,YAAY,GAAG;AACnC,UAAM,QAAQ,SAAS,QAAQ,YAAY;AAC3C,QAAI,UAAU,GAAI,UAAS,OAAO,OAAO,CAAC;AAAA,EAC5C;AAEA,SAAO;AACT;;;AChDO,IAAM,kBAA4D;AAAA,EACvE,YAAY;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,YAAY,eAAe,MAAM;AAC7C,YAAM,OAAO,CAAC,mBAAmB,SAAS,oBAAoB,YAAY,YAAY,mBAAmB;AACzG,UAAI,eAAgB,MAAK,OAAO,GAAG,GAAG,mBAAmB;AACzD,aAAO,EAAE,QAAQ,OAAO,KAAK;AAAA,IAC/B;AAAA,IACA,aAAa,CAAC,eAAe;AAAA,IAC7B,gBAAgB;AAAA,MACd,EAAE,OAAO,OAAO,cAAc,OAAO,QAAQ,OAAO,MAAM,CAAC,WAAW,MAAM,8BAA8B,EAAE;AAAA,IAC9G;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,YAAY;AAAA,IACV,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,mBAAmB,SAAS,oBAAoB,YAAY,YAAY,mBAAmB;AAAA,IACpG;AAAA,IACA,aAAa,CAAC,cAAc;AAAA,IAC5B,gBAAgB;AAAA,MACd,EAAE,OAAO,OAAO,cAAc,OAAO,QAAQ,OAAO,MAAM,CAAC,WAAW,MAAM,8BAA8B,EAAE;AAAA,IAC9G;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC,WAAW,cAAc;AAAA,IACvC,gBAAgB;AAAA,MACd,EAAE,OAAO,YAAY,cAAc,MAAM,QAAQ,MAAM,MAAM,CAAC,WAAW,WAAW,EAAE;AAAA,IACxF;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,OAAO;AAAA,IACL,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC,WAAW;AAAA,IACzB,gBAAgB;AAAA,MACd,EAAE,OAAO,YAAY,cAAc,MAAM,QAAQ,MAAM,MAAM,CAAC,WAAW,WAAW,EAAE;AAAA,IACxF;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,QAAQ;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC,kBAAkB;AAAA,IAChC,gBAAgB;AAAA,MACd,EAAE,OAAO,YAAY,cAAc,MAAM,QAAQ,MAAM,MAAM,CAAC,WAAW,WAAW,EAAE;AAAA,IACxF;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,QAAQ,KAAK,YAAY,UAAU;AAAA,IAC5C;AAAA,IACA,aAAa,CAAC,YAAY;AAAA,IAC1B,gBAAgB;AAAA,MACd,EAAE,OAAO,UAAU,cAAc,UAAU,QAAQ,UAAU,MAAM,CAAC,aAAa,OAAO,eAAe,EAAE;AAAA,IAC3G;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,QAAQ;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,YAAY,kBAAkB,SAAS;AAAA,IACrE;AAAA,IACA,aAAa,CAAC,kBAAkB,UAAU;AAAA,IAC1C,gBAAgB;AAAA,MACd,EAAE,OAAO,OAAO,cAAc,OAAO,QAAQ,OAAO,MAAM,CAAC,WAAW,MAAM,kBAAkB,EAAE;AAAA,IAClG;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,aAAa,CAAC,SAAS;AAAA,IACvB,gBAAgB,CAAC;AAAA,IACjB,YAAY;AAAA,EACd;AAAA,EAEA,IAAI;AAAA,IACF,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,aAAa,CAAC,QAAQ;AAAA,IACtB,gBAAgB;AAAA,MACd,EAAE,OAAO,cAAc,cAAc,MAAM,QAAQ,MAAM,MAAM,CAAC,WAAW,uCAAuC,EAAE;AAAA,IACtH;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,KAAK;AAAA,IACH,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,aAAa,CAAC,kBAAkB,UAAU;AAAA,IAC1C,gBAAgB,CAAC;AAAA,IACjB,YAAY;AAAA,EACd;AAAA,EAEA,GAAG;AAAA,IACD,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,YAAY,UAAU;AAAA,IAC/B;AAAA,IACA,aAAa,CAAC,kBAAkB,UAAU;AAAA,IAC1C,gBAAgB,CAAC;AAAA,IACjB,YAAY;AAAA,EACd;AAAA,EAEA,QAAQ;AAAA,IACN,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC;AAAA,IACd,gBAAgB;AAAA,MACd,EAAE,OAAO,UAAU,cAAc,UAAU,QAAQ,UAAU,MAAM,CAAC,QAAQ,WAAW,YAAY,aAAa,EAAE;AAAA,IACpH;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,MAAM;AAAA,IACJ,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC,cAAc;AAAA,IAC5B,gBAAgB;AAAA,MACd,EAAE,OAAO,YAAY,cAAc,QAAQ,QAAQ,QAAQ,MAAM,CAAC,OAAO,UAAU,YAAY,WAAW,EAAE;AAAA,IAC9G;AAAA,IACA,YAAY;AAAA,EACd;AAAA,EAEA,KAAK;AAAA,IACH,UAAU;AAAA,IACV,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW,CAAC,EAAE,WAAW,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,MAAM,CAAC,SAAS,YAAY,UAAU;AAAA,IACxC;AAAA,IACA,aAAa,CAAC,eAAe;AAAA,IAC7B,gBAAgB;AAAA,MACd,EAAE,OAAO,YAAY,cAAc,YAAY,QAAQ,YAAY,MAAM,CAAC,UAAU,WAAW,sBAAsB,EAAE;AAAA,IACzH;AAAA,IACA,YAAY;AAAA,EACd;AACF;AAGO,SAAS,iBAAiB,UAA4C;AAC3E,SAAO,gBAAgB,QAAQ;AACjC;;;AC3NA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AAGzB,IAAM,aAAa,SAAS,MAAM;AAK3B,SAAS,kBAAkB,MAAuB;AACvD,QAAM,MAAM,aAAa,UAAU;AACnC,MAAI;AACF,iBAAa,KAAK,CAAC,IAAI,GAAG,EAAE,OAAO,OAAO,CAAC;AAC3C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,mBAAmB,QAAgC;AACjE,SAAO,kBAAkB,OAAO,aAAa;AAC/C;AAOO,SAAS,kBACd,QACA,UACS;AACT,QAAMC,WAAU,OAAO;AACvB,MAAI,CAACA,UAAS,QAAQ;AACpB,aAAS,wCAAwC,OAAO,aAAa,GAAG;AACxE,QAAI,OAAO,YAAY;AACrB,eAAS,0BAA0B,OAAO,UAAU,EAAE;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAEA,aAAW,UAAUA,UAAS;AAC5B,QAAI,CAAC,kBAAkB,OAAO,YAAY,GAAG;AAC3C;AAAA,IACF;AAEA,aAAS,cAAc,OAAO,aAAa,QAAQ,OAAO,KAAK,KAAK;AACpE,QAAI;AACF,mBAAa,OAAO,QAAQ,OAAO,MAAM;AAAA,QACvC,OAAO;AAAA,QACP,SAAS;AAAA,QACT,KAAK,QAAQ;AAAA,MACf,CAAC;AAED,UAAI,mBAAmB,MAAM,GAAG;AAC9B,iBAAS,0BAA0B,OAAO,aAAa,QAAQ,OAAO,KAAK,EAAE;AAC7E,eAAO;AAAA,MACT;AACA,eAAS,GAAG,OAAO,KAAK,0BAA0B,OAAO,aAAa,oBAAoB;AAAA,IAC5F,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,GAAG,OAAO,KAAK,oBAAoB,GAAG,EAAE;AAAA,IACnD;AAAA,EACF;AAEA,WAAS,0BAA0B,OAAO,aAAa,GAAG;AAC1D,MAAI,OAAO,YAAY;AACrB,aAAS,0BAA0B,OAAO,UAAU,EAAE;AAAA,EACxD;AACA,SAAO;AACT;AAOO,SAAS,kBACd,UACS;AAET,MAAI,SAAS,MAAM,YAAY,kBAAkB,MAAM,GAAG;AACxD,aAAS,qCAAqC;AAC9C,QAAI;AACF,mBAAa,QAAQ,CAAC,WAAW,uBAAuB,GAAG;AAAA,QACzD,OAAO;AAAA,QACP,SAAS;AAAA,QACT,KAAK,QAAQ;AAAA,MACf,CAAC;AACD,UAAI,kBAAkB,MAAM,GAAG;AAC7B,iBAAS,8CAA8C;AACvD,eAAO;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,4BAA4B,GAAG,EAAE;AAAA,IAC5C;AAAA,EACF;AAGA,MAAI,kBAAkB,IAAI,GAAG;AAC3B,aAAS,uCAAuC;AAChD,QAAI;AACF,mBAAa,MAAM,CAAC,WAAW,6CAA6C,GAAG;AAAA,QAC7E,OAAO;AAAA,QACP,SAAS;AAAA,QACT,KAAK,QAAQ;AAAA,MACf,CAAC;AACD,UAAI,kBAAkB,MAAM,GAAG;AAC7B,iBAAS,gDAAgD;AACzD,eAAO;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAS,sBAAsB,GAAG,EAAE;AAAA,IACtC;AAAA,EACF;AAEA,WAAS,kCAAkC;AAC3C,WAAS,qEAAqE;AAC9E,SAAO;AACT;;;AHvFA,eAAsB,QAAQ,MAA8C;AAC1E,QAAM;AAAA,IACJ;AAAA,IACA,YAAY;AAAA,IACZ,WAAW,QAAQ;AAAA,IACnB,kBAAkB;AAAA,EACpB,IAAI;AAEJ,QAAM,aAAa,KAAK,cAAcC,MAAK,aAAa,YAAY;AACpE,QAAM,WAAW,KAAK,YAAYA,MAAK,aAAa,UAAU;AAC9D,QAAM,QAAQ,KAAK,IAAI;AAGvB,QAAM,YAAY,KAAK,aAAa,gBAAgB,WAAW;AAC/D,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,WAAS,uBAAuB,UAAU,KAAK,IAAI,CAAC,EAAE;AAGtD,MAAI,CAAC,kBAAkB,MAAM,GAAG;AAC9B,QAAI,iBAAiB;AACnB,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,aAAS,wDAAwD;AACjE,QAAI,CAAC,kBAAkB,QAAQ,GAAG;AAChC,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM;AAAA,IACV,GAAG,QAAQ;AAAA,IACX,cAAc,wBAAwB,SAAS;AAAA,EACjD;AAGA,aAAW,QAAQ,WAAW;AAC5B,UAAM,SAAS,iBAAiB,IAAI;AAGpC,QAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,UAAI,iBAAiB;AACnB,cAAM,IAAI;AAAA,UACR,GAAG,OAAO,aAAa,yBAAyB,IAAI;AAAA,KACnD,OAAO,aAAa,iBAAiB,OAAO,UAAU,KAAK,aAAa,OAAO,aAAa;AAAA,QAC/F;AAAA,MACF;AACA,eAAS,GAAG,OAAO,aAAa,wCAAwC;AACxE,UAAI,CAAC,kBAAkB,QAAQ,QAAQ,GAAG;AACxC,cAAM,IAAI;AAAA,UACR,GAAG,OAAO,aAAa,yBAAyB,IAAI;AAAA,KACnD,OAAO,aAAa,0BAA0B,OAAO,UAAU,KAAK,aAAa,OAAO,aAAa;AAAA,QACxG;AAAA,MACF;AAAA,IACF;AAEA,aAAS,YAAY,IAAI,SAAS,OAAO,aAAa,KAAK;AAE3D,UAAM,EAAE,QAAQ,KAAK,IAAI,OAAO,UAAU;AAAA,MACxC;AAAA,MACA,YAAY;AAAA,MACZ,gBAAgB,KAAK;AAAA,IACvB,CAAC;AAED,QAAI;AACF,MAAAC,cAAa,QAAQ,MAAM;AAAA,QACzB,KAAK;AAAA,QACL;AAAA,QACA,OAAO;AAAA,QACP,WAAW,KAAK,OAAO;AAAA,MACzB,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,IAAI;AAAA,QACR,mBAAmB,IAAI,SAAS,OAAO,aAAa,KAAK,GAAG;AAAA,YAC/C,OAAO,aAAa;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAGA,WAAS,yBAAyB;AAClC,MAAI,CAACC,YAAW,UAAU,GAAG;AAC3B,UAAM,IAAI,MAAM,2BAA2B,UAAU,iBAAiB;AAAA,EACxE;AAEA,MAAI;AACF,IAAAD,cAAa,QAAQ,CAAC,gBAAgB,YAAY,UAAU,UAAU,GAAG;AAAA,MACvE;AAAA,MACA,OAAO;AAAA,MACP,WAAW,KAAK,OAAO;AAAA,IACzB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAM,IAAI,MAAM,2CAA2C,GAAG,EAAE;AAAA,EAClE;AAEA,QAAM,aAAa,KAAK,IAAI,IAAI;AAChC,WAAS,YAAY,aAAa,KAAM,QAAQ,CAAC,CAAC,GAAG;AAErD,SAAO,EAAE,WAAW,WAAW,YAAY,QAAQ,UAAU,WAAW;AAC1E;;;AIpJA,SAAS,gBAAAE,eAAc,eAAe,cAAAC,aAAY,iBAAiB;AACnE,SAAS,QAAAC,OAAM,eAAe;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AAGxB,IAAM,kBAAkB;AAExB,IAAM,gBAAuC;AAAA,EAC3C,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ,CAAC;AACX;AAMO,SAAS,kBAAkB,aAAoC;AACpE,QAAM,aAAaA,MAAK,aAAa,eAAe;AAEpD,MAAI,CAACD,YAAW,UAAU,GAAG;AAC3B,WAAO,CAAC;AAAA,EACV;AAEA,MAAI;AACF,UAAM,MAAMD,cAAa,YAAY,OAAO;AAC5C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGO,SAAS,mBAAmB,QAA8C;AAC/E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG,OAAO;AAAA,EACZ;AACF;AAWO,SAAS,gBAAgB,aAAqB,QAAgC;AAEnF,QAAM,cAAc,QAAQ,IAAI,sBAAsB;AACtD,MAAI,YAAa,QAAO,UAAU,WAAW;AAG7C,MAAI,QAAQ,OAAQ,QAAO,UAAU,QAAQ,aAAa,OAAO,MAAM,CAAC;AAGxE,QAAM,WAAW,QAAQ,IAAI,gBAAgB;AAC7C,QAAM,YAAY,YAAYE,MAAK,QAAQ,GAAG,QAAQ;AACtD,QAAM,cAAc,WAAW,QAAQ,EACpC,OAAO,QAAQ,WAAW,CAAC,EAC3B,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AAEd,QAAM,MAAMA,MAAK,WAAW,cAAc,YAAY,WAAW;AACjE,SAAO,UAAU,GAAG;AACtB;AAKO,SAAS,kBAAkB,aAAqB,QAKrD;AACA,QAAM,WAAW,gBAAgB,aAAa,MAAM;AACpD,SAAO;AAAA,IACL;AAAA,IACA,QAAQA,MAAK,UAAU,UAAU;AAAA,IACjC,WAAWA,MAAK,UAAU,YAAY;AAAA,IACtC,UAAUA,MAAK,UAAU,WAAW;AAAA,EACtC;AACF;AAMO,SAAS,kBAAkB,aAAqB,WAA6B;AAClF,QAAM,aAAaA,MAAK,aAAa,eAAe;AAEpD,MAAID,YAAW,UAAU,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,SAAwB;AAAA,IAC5B;AAAA,IACA,OAAO;AAAA,MACL,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,IACd;AAAA,EACF;AAEA,gBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,IAAI;AAChE,SAAO;AACT;AAEA,SAAS,UAAU,KAAqB;AACtC,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,SAAO;AACT;;;ACpHA,SAAS,aAAa;AACtB,SAAuB,cAAAE,aAAY,kBAAkB;AACrD,SAAS,QAAAC,OAAM,gBAAgB;AAC/B,SAAS,YAAY;AACrB,OAAOC,aAAY;AAwBZ,IAAM,UAAN,MAAc;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,SAAwB,EAAE,OAAO,OAAO;AAAA,EACxC,gBAAsD;AAAA,EACtD,gBAAsD;AAAA,EACtD,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,iBAAiB;AAAA;AAAA,EAGjB,aAAyC,CAAC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EAElB,YAAY,MAAsB;AAChC,SAAK,cAAc,KAAK;AACxB,SAAK,cAAc,mBAAmB,KAAK,MAAM;AACjD,SAAK,aAAa,kBAAkB,KAAK,aAAa,KAAK,MAAM;AACjE,SAAK,YAAY,KAAK;AACtB,SAAK,iBAAiB,KAAK,OAAO,SAAS,YAAY,kBAAkB;AAEzE,SAAK,WAAW,KAAK,aAAa,MAAM;AAAA,IAAC;AACzC,SAAK,oBAAoB,KAAK,sBAAsB,MAAM;AAAA,IAAC;AAC3D,SAAK,UAAU,KAAK,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAE,OAAO;AAE9D,SAAK,kBAAkB,sBAAsB,KAAK,WAAW;AAC7D,SAAK,cAAcC,QAAO;AAC1B,QAAI,KAAK,YAAY,OAAO,SAAS,GAAG;AACtC,WAAK,YAAY,IAAI,KAAK,YAAY,MAAM;AAAA,IAC9C;AAAA,EACF;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,UAAU;AACf,SAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAKhC,QAAI;AACF,YAAM,UAAU;AAAA,QACd,KAAK;AAAA,QACL,EAAE,WAAW,KAAK;AAAA,QAClB,CAAC,QAAQ,aAAa;AACpB,cAAI,YAAY,CAAC,KAAK,SAAS;AAC7B,iBAAK,iBAAiB,QAAQ;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AACA,WAAK,WAAW,KAAK,OAAO;AAAA,IAC9B,QAAQ;AACN,WAAK,QAAQ,IAAI;AAAA,QACf;AAAA,MAEF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,OAAa;AACX,SAAK,UAAU;AACf,eAAW,KAAK,KAAK,WAAY,GAAE,MAAM;AACzC,SAAK,aAAa,CAAC;AACnB,QAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AACvD,QAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AACvD,SAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,EAClC;AAAA;AAAA,EAGA,YAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAIQ,iBAAiB,UAAwB;AAE/C,UAAM,MAAM,SAAS,KAAK,aAAaC,MAAK,KAAK,aAAa,QAAQ,CAAC;AACvE,QAAI,KAAK,gBAAgB,UAAU,GAAG,EAAG;AACzC,QAAI,KAAK,YAAY,QAAQ,GAAG,EAAG;AAGnC,QAAI,SAAS,SAAS,UAAU,KAAK,SAAS,SAAS,YAAY,KAC/D,SAAS,SAAS,cAAc,KAAK,SAAS,SAAS,iBAAiB,GAAG;AAC7E;AAAA,IACF;AAEA,SAAK;AAEL,QAAI,KAAK,iBAAiB;AAExB,WAAK,QAAQ;AACb,WAAK,UAAU;AAAA,QACb,OAAO;AAAA,QACP,WAAY,KAAK,OAAiC;AAAA,MACpD,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,OAAO,UAAU,YAAY;AAEpC,WAAK,QAAQ;AACb,WAAK,UAAU,EAAE,OAAO,YAAY,OAAQ,KAAK,OAA6B,OAAO,OAAO,KAAK,CAAC;AAClG;AAAA,IACF;AAGA,QAAI,KAAK,cAAe,cAAa,KAAK,aAAa;AAEvD,UAAM,YAAY,KAAK,IAAI,IAAI,KAAK,YAAY;AAChD,SAAK,UAAU,EAAE,OAAO,WAAW,cAAc,KAAK,cAAc,UAAU,CAAC;AAE/E,SAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,gBAAgB;AACrB,WAAK,eAAe;AAAA,IACtB,GAAG,KAAK,YAAY,UAAU;AAAA,EAChC;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,mBAAmB,KAAK,QAAS;AAG1C,UAAM,uBAAuB,KAAK,IAAI,IAAI,KAAK;AAC/C,QAAI,KAAK,iBAAiB,KAAK,uBAAuB,KAAK,YAAY,YAAY;AACjF,YAAM,YAAY,KAAK,YAAY,aAAa;AAChD,WAAK,QAAQ;AACb,YAAM,QAAQ,KAAK,IAAI,IAAI;AAC3B,WAAK,UAAU,EAAE,OAAO,YAAY,OAAO,OAAO,KAAK,CAAC;AAExD,WAAK,gBAAgB,WAAW,MAAM;AACpC,aAAK,gBAAgB;AACrB,YAAI,KAAK,SAAS,CAAC,KAAK,SAAS;AAC/B,eAAK,QAAQ;AACb,eAAK,eAAe;AAAA,QACtB;AAAA,MACF,GAAG,SAAS;AACZ;AAAA,IACF;AAEA,SAAK,kBAAkB;AACvB,SAAK,QAAQ;AACb,SAAK,eAAe;AACpB,UAAM,YAAY,KAAK,IAAI;AAC3B,SAAK,UAAU,EAAE,OAAO,YAAY,UAAU,CAAC;AAG/C,SAAK,WAAW,EACb,KAAK,CAAC,eAAe;AACpB,WAAK,kBAAkB;AACvB,WAAK,iBAAiB,KAAK,IAAI;AAC/B,WAAK,kBAAkB,UAAU;AAEjC,UAAI,KAAK,SAAS,CAAC,KAAK,SAAS;AAE/B,cAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,YAAY;AAC5C,aAAK,UAAU,EAAE,OAAO,YAAY,OAAO,OAAO,KAAK,CAAC;AAExD,aAAK,gBAAgB,WAAW,MAAM;AACpC,eAAK,gBAAgB;AACrB,cAAI,KAAK,SAAS,CAAC,KAAK,SAAS;AAC/B,iBAAK,QAAQ;AACb,iBAAK,eAAe;AAAA,UACtB,OAAO;AACL,iBAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,UAClC;AAAA,QACF,GAAG,KAAK,YAAY,UAAU;AAAA,MAChC,OAAO;AACL,aAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,MAClC;AAAA,IACF,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,WAAK,kBAAkB;AACvB,WAAK,iBAAiB,KAAK,IAAI;AAC/B,WAAK,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAChE,WAAK,UAAU,EAAE,OAAO,OAAO,CAAC;AAAA,IAClC,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,aAA8B;AACpC,WAAO,IAAI,QAAQ,CAACC,UAAS,WAAW;AACtC,YAAM,QAAQ,KAAK,IAAI;AACvB,YAAM,QAAQ,KAAK,WAAW,SAAS;AACvC,YAAM,UAAU,KAAK,WAAW,YAAY;AAG5C,YAAM,QAAQ;AAAA,QACZ,IAAI,IAAI,uBAAuB,YAAY,GAAG,EAAE;AAAA,QAChD,CAAC;AAAA,QACD;AAAA,UACE,KAAK;AAAA,YACH,GAAG,QAAQ;AAAA,YACX,2BAA2B,KAAK;AAAA,YAChC,0BAA0B;AAAA,YAC1B,wBAAwB;AAAA,YACxB,wBAAwB,KAAK,WAAW,KAAK,GAAG,KAAK;AAAA,YACrD,8BAA8B,KAAK,iBAAiB,MAAM;AAAA,UAC5D;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAEA,YAAM,GAAG,QAAQ,CAACC,UAAS;AACzB,YAAIA,UAAS,GAAG;AAEd,cAAI;AACF,gBAAIC,YAAW,KAAK,GAAG;AACrB,yBAAW,OAAO,KAAK,WAAW,MAAM;AAAA,YAC1C;AACA,gBAAIA,YAAW,OAAO,GAAG;AACvB,yBAAW,SAAS,KAAK,WAAW,SAAS;AAAA,YAC/C;AACA,YAAAF,SAAQ,KAAK,IAAI,IAAI,KAAK;AAAA,UAC5B,SAAS,KAAK;AACZ,mBAAO,IAAI,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAAA,UAChD;AAAA,QACF,OAAO;AACL,iBAAO,IAAI,MAAM,mCAAmCC,KAAI,EAAE,CAAC;AAAA,QAC7D;AAAA,MACF,CAAC;AAED,YAAM,GAAG,SAAS,MAAM;AAAA,IAC1B,CAAC;AAAA,EACH;AAAA,EAEQ,UAAU,QAA6B;AAC7C,SAAK,SAAS;AACd,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;ACjRA;AAAA,EACE,cAAAE;AAAA,EAAY,aAAAC;AAAA,EAAW;AAAA,EAAa;AAAA,EACpC;AAAA,OACK;AACP,SAAS,QAAAC,OAAM,WAAAC,UAAS,WAAAC,gBAAe;AACvC,SAAS,WAAAC,UAAS,YAAAC,WAAU,YAAY;AACxC,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,qBAAqB;AAI9B,IAAMC,cAAaC,UAAS,MAAM;AAClC,IAAM,SAAS,CAAC,iBAAiB,gBAAgB,gBAAgB,aAAa;AAC9E,IAAM,eAAe;AAed,SAAS,cACd,OAA4B,CAAC,GACR;AACrB,QAAM,MAAM,KAAK,QAAQ,MAAM;AAAA,EAAC,IAAI,QAAQ;AAC5C,QAAM,WAAW,cAAc,YAAY,GAAG;AAC9C,QAAM,eAAeC,SAAQC,SAAQ,QAAQ,GAAG,MAAM,QAAQ;AAE9D,QAAM,UAAU;AAAA,IACdC,MAAKC,SAAQ,GAAG,WAAW,QAAQ;AAAA,IACnCD,MAAKC,SAAQ,GAAG,UAAU,QAAQ;AAAA,EACpC;AAEA,QAAM,SAA8B;AAAA,IAClC,WAAW,CAAC;AAAA,IACZ,SAAS,CAAC;AAAA,IACV,eAAe,CAAC;AAAA,EAClB;AAEA,aAAW,aAAa,SAAS;AAE/B,UAAM,YAAYF,SAAQ,SAAS;AACnC,QAAI,CAACG,YAAW,SAAS,GAAG;AAC1B;AAAA,IACF;AAEA,IAAAC,WAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AACxC,UAAM,WAAW,UAAU,SAAS,QAAQ,IAAI,UAAU;AAE1D,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAASH,MAAK,cAAc,KAAK;AACvC,YAAM,SAASA,MAAK,WAAW,KAAK;AAEpC,UAAI,CAACE,YAAW,MAAM,GAAG;AACvB,eAAO,QAAQ,KAAK,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC1C;AAAA,MACF;AAEA,UAAIA,YAAW,MAAM,GAAG;AACtB,YAAI;AACF,gBAAM,WAAW,aAAa,MAAM;AACpC,cAAIJ,SAAQ,QAAQ,MAAMA,SAAQ,MAAM,GAAG;AACzC,mBAAO,cAAc,KAAK,GAAG,QAAQ,IAAI,KAAK,EAAE;AAChD,gBAAI,WAAW,KAAK,WAAM,QAAQ,mBAAmB;AACrD;AAAA,UACF;AAAA,QACF,QAAQ;AAEN,iBAAO,QAAQ,KAAK,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC1C,cAAI,WAAW,KAAK,WAAM,QAAQ,0BAA0B;AAC5D;AAAA,QACF;AACA,mBAAW,MAAM;AAAA,MACnB;AAGA,kBAAY,QAAQ,QAAQF,cAAa,aAAa,KAAK;AAC3D,aAAO,UAAU,KAAK,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC5C,UAAI,WAAW,KAAK,WAAM,QAAQ,EAAE;AAAA,IACtC;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,kBAA2B;AACzC,MAAI;AACF,UAAM,MAAMA,cAAa,UAAU;AACnC,IAAAQ,cAAa,KAAK,CAAC,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,iBAAgC;AAC9C,MAAI;AACF,UAAM,SAASA,cAAa,QAAQ,CAAC,WAAW,GAAG,EAAE,OAAO,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK;AACtF,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKA,SAAS,qBAA+D;AACtE,QAAM,KAAKP,UAAS;AACpB,QAAM,MAAM,KAAK;AAEjB,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,UAAQ,IAAI;AAAA,IACV,KAAK;AAAU,eAAS;AAAU,YAAM;AAAU;AAAA,IAClD,KAAK;AAAS,eAAS;AAAS,YAAM;AAAU;AAAA,IAChD,KAAK;AAAS,eAAS;AAAW,YAAM;AAAO;AAAA,IAC/C;AAAS,aAAO;AAAA,EAClB;AAEA,UAAQ,KAAK;AAAA,IACX,KAAK;AAAS,iBAAW;AAAS;AAAA,IAClC,KAAK;AAAO,iBAAW;AAAS;AAAA,IAChC;AAAS,aAAO;AAAA,EAClB;AAEA,QAAM,WAAW,QAAQ,MAAM,IAAI,QAAQ,IAAI,GAAG;AAClD,QAAM,MAAM,yDAAyD,YAAY,IAAI,QAAQ;AAC7F,SAAO,EAAE,KAAK,SAAS;AACzB;AAKO,SAAS,+BAAqC;AACnD,QAAM,WAAW,mBAAmB;AAEpC,UAAQ,IAAI,uDAAuD;AAEnE,MAAIA,UAAS,MAAM,UAAU;AAC3B,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI,wCAAwC;AACpD,YAAQ,IAAI,uBAAuB;AAAA,EACrC,OAAO;AACL,YAAQ,IAAI,gBAAgB;AAAA,EAC9B;AAEA,MAAI,UAAU;AACZ,YAAQ,IAAI,KAAK,SAAS,GAAG;AAAA,CAAI;AAAA,EACnC,OAAO;AACL,YAAQ,IAAI,sDAAsD,YAAY;AAAA,CAAI;AAAA,EACpF;AAEA,UAAQ,IAAI,+EAA+E;AAC7F;","names":["files","execFileSync","existsSync","join","existsSync","join","methods","join","execFileSync","existsSync","readFileSync","existsSync","join","existsSync","join","ignore","ignore","join","resolve","code","existsSync","existsSync","mkdirSync","join","dirname","resolve","homedir","platform","execFileSync","IS_WINDOWS","platform","resolve","dirname","join","homedir","existsSync","mkdirSync","execFileSync"]}
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ tryInstallScipCli
4
+ } from "./chunk-DVWGWHFW.js";
5
+
6
+ // src/setup.ts
7
+ import {
8
+ existsSync,
9
+ mkdirSync,
10
+ symlinkSync,
11
+ readlinkSync,
12
+ unlinkSync
13
+ } from "fs";
14
+ import { join, dirname, resolve } from "path";
15
+ import { homedir, platform, arch } from "os";
16
+ import { execFileSync } from "child_process";
17
+ import { fileURLToPath } from "url";
18
+ var IS_WINDOWS = platform() === "win32";
19
+ var SKILLS = ["concrete-plan", "scip-explore", "scip-debloat", "scip-verify"];
20
+ var SCIP_VERSION = "v0.7.0";
21
+ function installSkills(opts = {}) {
22
+ const log = opts.quiet ? () => {
23
+ } : console.log;
24
+ const thisFile = fileURLToPath(import.meta.url);
25
+ const skillsSource = resolve(dirname(thisFile), "..", "skills");
26
+ const targets = [
27
+ join(homedir(), ".claude", "skills"),
28
+ join(homedir(), ".codex", "skills")
29
+ ];
30
+ const result = {
31
+ installed: [],
32
+ skipped: [],
33
+ alreadyLinked: []
34
+ };
35
+ for (const targetDir of targets) {
36
+ const parentDir = dirname(targetDir);
37
+ if (!existsSync(parentDir)) {
38
+ continue;
39
+ }
40
+ mkdirSync(targetDir, { recursive: true });
41
+ const toolName = targetDir.includes(".codex") ? "Codex" : "Claude";
42
+ for (const skill of SKILLS) {
43
+ const source = join(skillsSource, skill);
44
+ const target = join(targetDir, skill);
45
+ if (!existsSync(source)) {
46
+ result.skipped.push(`${toolName}/${skill}`);
47
+ continue;
48
+ }
49
+ if (existsSync(target)) {
50
+ try {
51
+ const existing = readlinkSync(target);
52
+ if (resolve(existing) === resolve(source)) {
53
+ result.alreadyLinked.push(`${toolName}/${skill}`);
54
+ log(` ok: ${skill} \u2192 ${toolName} (already linked)`);
55
+ continue;
56
+ }
57
+ } catch {
58
+ result.skipped.push(`${toolName}/${skill}`);
59
+ log(` skip: ${skill} \u2192 ${toolName} (exists, not a symlink)`);
60
+ continue;
61
+ }
62
+ unlinkSync(target);
63
+ }
64
+ symlinkSync(source, target, IS_WINDOWS ? "junction" : "dir");
65
+ result.installed.push(`${toolName}/${skill}`);
66
+ log(` done: ${skill} \u2192 ${toolName}`);
67
+ }
68
+ }
69
+ return result;
70
+ }
71
+ function isScipInstalled() {
72
+ try {
73
+ const cmd = IS_WINDOWS ? "where" : "which";
74
+ execFileSync(cmd, ["scip"], { stdio: "pipe" });
75
+ return true;
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ function getScipVersion() {
81
+ try {
82
+ const output = execFileSync("scip", ["--version"], { stdio: "pipe" }).toString().trim();
83
+ return output;
84
+ } catch {
85
+ return null;
86
+ }
87
+ }
88
+ function getScipDownloadUrl() {
89
+ const os = platform();
90
+ const cpu = arch();
91
+ let osName;
92
+ let archName;
93
+ let ext;
94
+ switch (os) {
95
+ case "darwin":
96
+ osName = "darwin";
97
+ ext = "tar.gz";
98
+ break;
99
+ case "linux":
100
+ osName = "linux";
101
+ ext = "tar.gz";
102
+ break;
103
+ case "win32":
104
+ osName = "windows";
105
+ ext = "zip";
106
+ break;
107
+ default:
108
+ return null;
109
+ }
110
+ switch (cpu) {
111
+ case "arm64":
112
+ archName = "arm64";
113
+ break;
114
+ case "x64":
115
+ archName = "amd64";
116
+ break;
117
+ default:
118
+ return null;
119
+ }
120
+ const filename = `scip-${osName}-${archName}.${ext}`;
121
+ const url = `https://github.com/sourcegraph/scip/releases/download/${SCIP_VERSION}/${filename}`;
122
+ return { url, filename };
123
+ }
124
+ function printScipInstallInstructions() {
125
+ const download = getScipDownloadUrl();
126
+ console.log("\nThe `scip` CLI is required but not found on PATH.\n");
127
+ if (platform() === "darwin") {
128
+ console.log("Install via Homebrew:");
129
+ console.log(" brew install sourcegraph/scip/scip\n");
130
+ console.log("Or download manually:");
131
+ } else {
132
+ console.log("Download from:");
133
+ }
134
+ if (download) {
135
+ console.log(` ${download.url}
136
+ `);
137
+ } else {
138
+ console.log(` https://github.com/sourcegraph/scip/releases/tag/${SCIP_VERSION}
139
+ `);
140
+ }
141
+ console.log("After installing, ensure `scip` is on your PATH and run `scip-query reindex`.");
142
+ }
143
+ function postinstall() {
144
+ console.log("scip-query: installing skills...");
145
+ const result = installSkills({ quiet: false });
146
+ const total = result.installed.length + result.alreadyLinked.length;
147
+ if (total > 0) {
148
+ console.log(`
149
+ ${result.installed.length} skill(s) installed, ${result.alreadyLinked.length} already linked.`);
150
+ }
151
+ if (!isScipInstalled()) {
152
+ console.log("\nscip CLI not found on PATH. Attempting auto-install...");
153
+ const installed = tryInstallScipCli(console.log);
154
+ if (!installed) {
155
+ printScipInstallInstructions();
156
+ }
157
+ } else {
158
+ const version = getScipVersion();
159
+ console.log(`
160
+ scip CLI: ${version ?? "installed"}`);
161
+ }
162
+ console.log("");
163
+ }
164
+
165
+ // src/postinstall.ts
166
+ postinstall();
167
+ //# sourceMappingURL=postinstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup.ts","../src/postinstall.ts"],"sourcesContent":["import {\n existsSync, mkdirSync, symlinkSync, readlinkSync,\n unlinkSync, chmodSync, createWriteStream,\n} from 'node:fs';\nimport { join, dirname, resolve } from 'node:path';\nimport { homedir, platform, arch } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { get as httpsGet } from 'node:https';\nimport { tryInstallScipCli } from './reindex/install.js';\n\nconst IS_WINDOWS = platform() === 'win32';\nconst SKILLS = ['concrete-plan', 'scip-explore', 'scip-debloat', 'scip-verify'];\nconst SCIP_VERSION = 'v0.7.0';\n\n// ── Skills Installation ────────────────────────────────────\n\nexport interface InstallSkillsResult {\n installed: string[];\n skipped: string[];\n alreadyLinked: string[];\n}\n\n/**\n * Install scip-query skills into both Claude Code (~/.claude/skills/)\n * and Codex (~/.codex/skills/). Uses symlinks (junctions on Windows)\n * so skills auto-update when the package updates.\n */\nexport function installSkills(\n opts: { quiet?: boolean } = {},\n): InstallSkillsResult {\n const log = opts.quiet ? () => {} : console.log;\n const thisFile = fileURLToPath(import.meta.url);\n const skillsSource = resolve(dirname(thisFile), '..', 'skills');\n\n const targets = [\n join(homedir(), '.claude', 'skills'),\n join(homedir(), '.codex', 'skills'),\n ];\n\n const result: InstallSkillsResult = {\n installed: [],\n skipped: [],\n alreadyLinked: [],\n };\n\n for (const targetDir of targets) {\n // Only install if the parent directory exists (tool is installed)\n const parentDir = dirname(targetDir);\n if (!existsSync(parentDir)) {\n continue;\n }\n\n mkdirSync(targetDir, { recursive: true });\n const toolName = targetDir.includes('.codex') ? 'Codex' : 'Claude';\n\n for (const skill of SKILLS) {\n const source = join(skillsSource, skill);\n const target = join(targetDir, skill);\n\n if (!existsSync(source)) {\n result.skipped.push(`${toolName}/${skill}`);\n continue;\n }\n\n if (existsSync(target)) {\n try {\n const existing = readlinkSync(target);\n if (resolve(existing) === resolve(source)) {\n result.alreadyLinked.push(`${toolName}/${skill}`);\n log(` ok: ${skill} → ${toolName} (already linked)`);\n continue;\n }\n } catch {\n // Not a symlink — don't overwrite user's custom skill\n result.skipped.push(`${toolName}/${skill}`);\n log(` skip: ${skill} → ${toolName} (exists, not a symlink)`);\n continue;\n }\n unlinkSync(target);\n }\n\n // Use 'junction' on Windows (doesn't need admin), 'dir' elsewhere\n symlinkSync(source, target, IS_WINDOWS ? 'junction' : 'dir');\n result.installed.push(`${toolName}/${skill}`);\n log(` done: ${skill} → ${toolName}`);\n }\n }\n\n return result;\n}\n\n// ── SCIP CLI Binary Detection & Installation ───────────────\n\n/**\n * Check if the `scip` CLI binary is available on PATH.\n */\nexport function isScipInstalled(): boolean {\n try {\n const cmd = IS_WINDOWS ? 'where' : 'which';\n execFileSync(cmd, ['scip'], { stdio: 'pipe' });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get the scip CLI version if installed.\n */\nexport function getScipVersion(): string | null {\n try {\n const output = execFileSync('scip', ['--version'], { stdio: 'pipe' }).toString().trim();\n return output;\n } catch {\n return null;\n }\n}\n\n/**\n * Resolve the download URL for the scip CLI binary for this platform.\n */\nfunction getScipDownloadUrl(): { url: string; filename: string } | null {\n const os = platform();\n const cpu = arch();\n\n let osName: string;\n let archName: string;\n let ext: string;\n\n switch (os) {\n case 'darwin': osName = 'darwin'; ext = 'tar.gz'; break;\n case 'linux': osName = 'linux'; ext = 'tar.gz'; break;\n case 'win32': osName = 'windows'; ext = 'zip'; break;\n default: return null;\n }\n\n switch (cpu) {\n case 'arm64': archName = 'arm64'; break;\n case 'x64': archName = 'amd64'; break;\n default: return null;\n }\n\n const filename = `scip-${osName}-${archName}.${ext}`;\n const url = `https://github.com/sourcegraph/scip/releases/download/${SCIP_VERSION}/${filename}`;\n return { url, filename };\n}\n\n/**\n * Print instructions for installing the scip CLI binary.\n */\nexport function printScipInstallInstructions(): void {\n const download = getScipDownloadUrl();\n\n console.log('\\nThe `scip` CLI is required but not found on PATH.\\n');\n\n if (platform() === 'darwin') {\n console.log('Install via Homebrew:');\n console.log(' brew install sourcegraph/scip/scip\\n');\n console.log('Or download manually:');\n } else {\n console.log('Download from:');\n }\n\n if (download) {\n console.log(` ${download.url}\\n`);\n } else {\n console.log(` https://github.com/sourcegraph/scip/releases/tag/${SCIP_VERSION}\\n`);\n }\n\n console.log('After installing, ensure `scip` is on your PATH and run `scip-query reindex`.');\n}\n\n// ── First-Run Setup ────────────────────────────────────────\n\n/**\n * Run first-time setup: install skills and check for scip binary.\n * Called from the postinstall script.\n */\nexport function postinstall(): void {\n console.log('scip-query: installing skills...');\n const result = installSkills({ quiet: false });\n\n const total = result.installed.length + result.alreadyLinked.length;\n if (total > 0) {\n console.log(`\\n${result.installed.length} skill(s) installed, ${result.alreadyLinked.length} already linked.`);\n }\n\n // Check for scip binary — auto-install if missing\n if (!isScipInstalled()) {\n console.log('\\nscip CLI not found on PATH. Attempting auto-install...');\n const installed = tryInstallScipCli(console.log);\n if (!installed) {\n printScipInstallInstructions();\n }\n } else {\n const version = getScipVersion();\n console.log(`\\nscip CLI: ${version ?? 'installed'}`);\n }\n\n console.log('');\n}\n","#!/usr/bin/env node\n/**\n * npm postinstall hook. Runs automatically after `npm install -g scip-query`.\n * Installs skills into Claude Code and Codex, checks for scip binary.\n */\nimport { postinstall } from './setup.js';\n\npostinstall();\n"],"mappings":"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","names":[]}
@@ -0,0 +1,14 @@
1
+ import { S as ScipDatabase, A as AffectedResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Full transitive closure of symbols that could break if a given symbol changes.
6
+ * BFS from the target through the mention graph: depth 1 = direct consumers,
7
+ * depth 2 = consumers of consumers, etc.
8
+ */
9
+ declare function affected(db: ScipDatabase, symbolPattern: string, opts?: {
10
+ maxDepth?: number;
11
+ scope?: string;
12
+ }): AffectedResult[];
13
+
14
+ export { affected };
@@ -0,0 +1,9 @@
1
+ import {
2
+ affected
3
+ } from "../chunk-6VJ6Q7IE.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ affected
8
+ };
9
+ //# sourceMappingURL=affected.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,18 @@
1
+ import { S as ScipDatabase, B as BottleneckResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Find coupling hubs: symbols with both high fan-in (many consumers)
6
+ * AND high fan-out (references many other symbols).
7
+ *
8
+ * These are the most dangerous symbols to change — they sit at the
9
+ * intersection of many dependency paths. Score = fanIn * fanOut.
10
+ */
11
+ declare function bottlenecks(db: ScipDatabase, opts?: {
12
+ limit?: number;
13
+ scope?: string;
14
+ minFanIn?: number;
15
+ minFanOut?: number;
16
+ }): BottleneckResult[];
17
+
18
+ export { bottlenecks };
@@ -0,0 +1,8 @@
1
+ import {
2
+ bottlenecks
3
+ } from "../chunk-2QZ23IBN.js";
4
+ import "../chunk-QOV2R2WT.js";
5
+ export {
6
+ bottlenecks
7
+ };
8
+ //# sourceMappingURL=bottlenecks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,20 @@
1
+ import { S as ScipDatabase, a as ByKindResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Find symbols by SCIP kind (class, interface, enum, function, etc.)
6
+ */
7
+ declare function byKind(db: ScipDatabase, kindQuery: string, opts?: {
8
+ scope?: string;
9
+ limit?: number;
10
+ }): ByKindResult[];
11
+ /** List all symbol kinds present in the index with counts */
12
+ declare function kindCounts(db: ScipDatabase, opts?: {
13
+ scope?: string;
14
+ }): Array<{
15
+ kind: number;
16
+ kindName: string;
17
+ count: number;
18
+ }>;
19
+
20
+ export { byKind, kindCounts };
@@ -0,0 +1,10 @@
1
+ import {
2
+ byKind,
3
+ kindCounts
4
+ } from "../chunk-LAWMH22O.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ byKind,
8
+ kindCounts
9
+ };
10
+ //# sourceMappingURL=by-kind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,13 @@
1
+ import { S as ScipDatabase, C as CallGraphResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Build a call graph for a symbol: who calls it (incoming) and
6
+ * what it calls (outgoing).
7
+ *
8
+ * Incoming: other symbols whose definition ranges contain a reference to this symbol.
9
+ * Outgoing: symbols referenced within this symbol's definition range.
10
+ */
11
+ declare function callGraph(db: ScipDatabase, symbolPattern: string): CallGraphResult | null;
12
+
13
+ export { callGraph };
@@ -0,0 +1,9 @@
1
+ import {
2
+ callGraph
3
+ } from "../chunk-UNTPVD36.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ callGraph
8
+ };
9
+ //# sourceMappingURL=call-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,10 @@
1
+ import { S as ScipDatabase, b as ChangeSurfaceResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Pre-change briefing for a file. For each symbol defined in the file,
6
+ * reports external consumer count, test coverage, and risk level.
7
+ */
8
+ declare function changeSurface(db: ScipDatabase, filePattern: string): ChangeSurfaceResult | null;
9
+
10
+ export { changeSurface };
@@ -0,0 +1,9 @@
1
+ import {
2
+ changeSurface
3
+ } from "../chunk-VRUJH4BO.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ changeSurface
8
+ };
9
+ //# sourceMappingURL=change-surface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Clean up the raw doc/signature string from the SCIP index.
3
+ *
4
+ * Shared across symbols, trace, and system queries.
5
+ * Previously duplicated as cleanSig/cleanSignature in three files.
6
+ */
7
+ declare function cleanSignature(sig: string | null): string | null;
8
+
9
+ export { cleanSignature };
@@ -0,0 +1,7 @@
1
+ import {
2
+ cleanSignature
3
+ } from "../chunk-4TYLS5XX.js";
4
+ export {
5
+ cleanSignature
6
+ };
7
+ //# sourceMappingURL=clean-signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,17 @@
1
+ import { S as ScipDatabase, c as CodeResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Read the source code for a symbol, bounded to its definition range.
6
+ * Language-agnostic: just reads the file and extracts the relevant lines.
7
+ *
8
+ * Accepts:
9
+ * - Symbol name pattern: "processVegaMention"
10
+ * - Full short name: "src:modules:chat:processVegaMention"
11
+ * - File:line-line syntax: "src/chat/service.ts:100-200"
12
+ */
13
+ declare function code(db: ScipDatabase, symbolPattern: string, opts?: {
14
+ context?: number;
15
+ }): CodeResult | null;
16
+
17
+ export { code };
@@ -0,0 +1,9 @@
1
+ import {
2
+ code
3
+ } from "../chunk-VZ7AMAFL.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ code
8
+ };
9
+ //# sourceMappingURL=code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,19 @@
1
+ import { S as ScipDatabase, d as ComplexityHotspot } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Find complexity hotspots: symbols with a composite score based on
6
+ * LOC, fan-in, fan-out, and callee count.
7
+ *
8
+ * Score = (loc / 50) * (fanIn / 5) * max(fanOut / 5, 1)
9
+ *
10
+ * High scores indicate symbols that are large, widely depended upon,
11
+ * AND reach out to many other modules — the riskiest code to change.
12
+ */
13
+ declare function complexityHotspots(db: ScipDatabase, opts?: {
14
+ scope?: string;
15
+ minLoc?: number;
16
+ limit?: number;
17
+ }): ComplexityHotspot[];
18
+
19
+ export { complexityHotspots };
@@ -0,0 +1,9 @@
1
+ import {
2
+ complexityHotspots
3
+ } from "../chunk-EMDQWNYR.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ complexityHotspots
8
+ };
9
+ //# sourceMappingURL=complexity-hotspots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,13 @@
1
+ import { S as ScipDatabase, e as ComplexityResult } from '../db-BxaevAyc.js';
2
+ import 'better-sqlite3';
3
+
4
+ /**
5
+ * Per-symbol complexity analysis combining source-level branch counting
6
+ * with index-level metrics (fan-in, fan-out, callee count).
7
+ *
8
+ * Branch counting uses language-aware regex. The language is read from
9
+ * the SCIP documents table, so it works for any indexed language.
10
+ */
11
+ declare function complexity(db: ScipDatabase, symbolPattern: string): ComplexityResult | null;
12
+
13
+ export { complexity };
@@ -0,0 +1,9 @@
1
+ import {
2
+ complexity
3
+ } from "../chunk-BP2ATLK2.js";
4
+ import "../chunk-FUHJCHS4.js";
5
+ import "../chunk-QOV2R2WT.js";
6
+ export {
7
+ complexity
8
+ };
9
+ //# sourceMappingURL=complexity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}