@namzu/cli 37.2.0 → 38.0.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 (314) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +2 -2
  3. package/dist/analysis-host.js +293 -10
  4. package/dist/analysis-host.js.map +2 -2
  5. package/dist/bin.js +1 -1
  6. package/dist/chunks/{acp-WRUFVVVS.js → acp-WH4EFAFK.js} +79 -56
  7. package/dist/chunks/acp-WH4EFAFK.js.map +6 -0
  8. package/dist/chunks/{activity-command-7GP4PLBD.js → activity-command-RM6YEJJE.js} +14 -14
  9. package/dist/chunks/{add-KNRDMCME.js → add-JUN463VT.js} +23 -22
  10. package/dist/chunks/add-JUN463VT.js.map +6 -0
  11. package/dist/chunks/{agent-LZDDK3NN.js → agent-UNGHD2P3.js} +27 -26
  12. package/dist/chunks/agent-session-FG4XT6SX.js +52 -0
  13. package/dist/chunks/{archive-PNHAJS2H.js → archive-IAT6HD7B.js} +9 -9
  14. package/dist/chunks/{bin-main-Y2J7CPYI.js → bin-main-B5GXM64T.js} +6 -5
  15. package/dist/chunks/bin-main-B5GXM64T.js.map +6 -0
  16. package/dist/chunks/{browser-RVLLK6CN.js → browser-4P3N4ZQL.js} +6 -6
  17. package/dist/chunks/{chat-YF3TI43Y.js → chat-4Q3PPOMP.js} +15 -14
  18. package/dist/chunks/chat-4Q3PPOMP.js.map +6 -0
  19. package/dist/chunks/{chunk-TQGYYDLF.js → chunk-25P24RKO.js} +5 -5
  20. package/dist/chunks/chunk-25P24RKO.js.map +6 -0
  21. package/dist/chunks/{chunk-REBTUQC6.js → chunk-2HZIBPEM.js} +21 -14
  22. package/dist/chunks/chunk-2HZIBPEM.js.map +6 -0
  23. package/dist/chunks/{chunk-MULW7FFH.js → chunk-2WMXW2HX.js} +4 -4
  24. package/dist/chunks/chunk-356N4VBU.js +134 -0
  25. package/dist/chunks/chunk-356N4VBU.js.map +6 -0
  26. package/dist/chunks/{chunk-KSLX3NGM.js → chunk-3CEDA5YH.js} +117 -3
  27. package/dist/chunks/chunk-3CEDA5YH.js.map +6 -0
  28. package/dist/chunks/{chunk-DRXG4OLL.js → chunk-466ECWQB.js} +4 -4
  29. package/dist/chunks/{chunk-2TDWK353.js → chunk-47W5PCU5.js} +12 -12
  30. package/dist/chunks/{chunk-PSLRTJU5.js → chunk-4DQ5TVCH.js} +12 -12
  31. package/dist/chunks/{chunk-A5GALFIC.js → chunk-6HPZCB5F.js} +2 -2
  32. package/dist/chunks/{chunk-VCUPZJDO.js → chunk-6PMO2KA2.js} +2 -2
  33. package/dist/chunks/{chunk-LO5DFG6H.js → chunk-735YHXE3.js} +2 -2
  34. package/dist/chunks/{devtools-LBE4PAQN.js → chunk-7AZTWFS7.js} +12 -84
  35. package/dist/chunks/{devtools-LBE4PAQN.js.map → chunk-7AZTWFS7.js.map} +2 -2
  36. package/dist/chunks/{chunk-O6X4O7VQ.js → chunk-7PBYGA76.js} +3 -3
  37. package/dist/chunks/{chunk-DS2PIOVD.js → chunk-7XBUFSLG.js} +3 -3
  38. package/dist/chunks/{chunk-72TESSG2.js → chunk-AQM2Q6XZ.js} +53 -11
  39. package/dist/chunks/chunk-AQM2Q6XZ.js.map +6 -0
  40. package/dist/chunks/{chunk-GEB3OP2H.js → chunk-BKBXEXIL.js} +355 -168
  41. package/dist/chunks/chunk-BKBXEXIL.js.map +6 -0
  42. package/dist/chunks/{chunk-5YERJLR7.js → chunk-BQRKMDDF.js} +4 -4
  43. package/dist/chunks/{chunk-GYM3FUBH.js → chunk-D5HL6QDV.js} +2 -2
  44. package/dist/chunks/{chunk-ERY3CYIM.js → chunk-G2ZBMR22.js} +4 -4
  45. package/dist/chunks/{chunk-5NHKC3NO.js → chunk-G6ETOUUR.js} +6 -6
  46. package/dist/chunks/{chunk-HJBZYFCC.js → chunk-GAYGCGIY.js} +6 -6
  47. package/dist/chunks/chunk-GK4HLIQQ.js +63 -0
  48. package/dist/chunks/chunk-GK4HLIQQ.js.map +6 -0
  49. package/dist/chunks/{chunk-UARWI3TA.js → chunk-GW7O5N42.js} +2 -2
  50. package/dist/chunks/{chunk-YX2ZK34T.js → chunk-HA37WH7H.js} +18 -18
  51. package/dist/chunks/{chunk-4H4YDNND.js → chunk-HCQUBJTS.js} +74 -49
  52. package/dist/chunks/chunk-HCQUBJTS.js.map +6 -0
  53. package/dist/chunks/{chunk-N2CP3FIQ.js → chunk-HVJXMGCJ.js} +4 -4
  54. package/dist/chunks/{chunk-HFFINVNN.js → chunk-JL3LUBAN.js} +3 -3
  55. package/dist/chunks/{chunk-NYRBM7PR.js → chunk-K5J7ATQR.js} +10 -10
  56. package/dist/chunks/{chunk-HFUBLJE5.js → chunk-KOOSFKHR.js} +2 -2
  57. package/dist/chunks/{chunk-77AX2GEP.js → chunk-LA7SHC2B.js} +43609 -41864
  58. package/dist/chunks/chunk-LA7SHC2B.js.map +6 -0
  59. package/dist/chunks/{chunk-7WKQQOKK.js → chunk-M6CYVSNV.js} +287 -31
  60. package/dist/chunks/chunk-M6CYVSNV.js.map +6 -0
  61. package/dist/chunks/{chunk-YDD74UVE.js → chunk-MJG4FQ27.js} +4 -4
  62. package/dist/chunks/{chunk-SMAN2IR4.js → chunk-MRJCV6EH.js} +2 -2
  63. package/dist/chunks/{chunk-37FCG7VX.js → chunk-N5L7HGNL.js} +2 -2
  64. package/dist/chunks/{chunk-T5GKAQHN.js → chunk-ORHVELT4.js} +2 -2
  65. package/dist/chunks/{chunk-HLHYVGQE.js → chunk-PKIH55PX.js} +13 -13
  66. package/dist/chunks/{chunk-4GIDESAM.js → chunk-PWFLM6BJ.js} +4 -4
  67. package/dist/chunks/{chunk-M46XYX7O.js → chunk-QKSBBKKC.js} +3 -3
  68. package/dist/chunks/{chunk-DW23UIKM.js → chunk-RU3AE4JE.js} +2 -2
  69. package/dist/chunks/{chunk-M2SQW7DK.js → chunk-S5KTYKQH.js} +3 -3
  70. package/dist/chunks/{chunk-M2SQW7DK.js.map → chunk-S5KTYKQH.js.map} +1 -1
  71. package/dist/chunks/{chunk-KK73BCYK.js → chunk-SZUOO7A2.js} +5 -5
  72. package/dist/chunks/{chunk-POEIV6AQ.js → chunk-TFA5ZAGJ.js} +2 -2
  73. package/dist/chunks/{chunk-QWCASGYH.js → chunk-TZLYJWSW.js} +4 -4
  74. package/dist/chunks/{chunk-XHJMDBRV.js → chunk-U6EH3UCL.js} +2 -2
  75. package/dist/chunks/{chunk-ABHX2QBJ.js → chunk-UKOMZND2.js} +4 -4
  76. package/dist/chunks/{chunk-ND6ZNIUM.js → chunk-UW42IRA4.js} +5 -5
  77. package/dist/chunks/{chunk-MF45FNH3.js → chunk-UZ7ONUMS.js} +3 -3
  78. package/dist/chunks/{chunk-MUG3SBGU.js → chunk-V5WCUTSO.js} +3 -3
  79. package/dist/chunks/{chunk-HFMDSVBA.js → chunk-VHZ3I7L4.js} +5 -5
  80. package/dist/chunks/{chunk-VIDT6RAV.js → chunk-VK2BAABY.js} +7 -7
  81. package/dist/chunks/{chunk-VONRWBC6.js → chunk-VKZKDPKS.js} +2 -2
  82. package/dist/chunks/{chunk-HS3TPTJ3.js → chunk-VUQE34X4.js} +2 -2
  83. package/dist/chunks/{chunk-XBRRTAXP.js → chunk-WCC5ABWX.js} +2 -2
  84. package/dist/chunks/chunk-WMEZTDLT.js +17 -0
  85. package/dist/chunks/chunk-WMEZTDLT.js.map +6 -0
  86. package/dist/chunks/{chunk-R7HI2NMR.js → chunk-XDA57K4Q.js} +2 -2
  87. package/dist/chunks/{chunk-UI3MX7CC.js → chunk-XHBZBISL.js} +3 -3
  88. package/dist/chunks/{chunk-34IZ6DMB.js → chunk-YMSXUKHE.js} +2 -2
  89. package/dist/chunks/{chunk-E6RPYGJP.js → chunk-YXFS44LU.js} +3 -3
  90. package/dist/chunks/chunk-Z7J6WN6G.js +86 -0
  91. package/dist/chunks/chunk-Z7J6WN6G.js.map +6 -0
  92. package/dist/chunks/{chunk-V6NJWYMP.js → chunk-ZDAUAJ4L.js} +2 -2
  93. package/dist/chunks/{chunk-HRRQSXVP.js → chunk-ZGODF5RM.js} +20 -14
  94. package/dist/chunks/chunk-ZGODF5RM.js.map +6 -0
  95. package/dist/chunks/{cli-runtime-6MW2CSZV.js → cli-runtime-HEQVJMIJ.js} +50 -9
  96. package/dist/chunks/cli-runtime-HEQVJMIJ.js.map +6 -0
  97. package/dist/chunks/{commands-FHJCPYZK.js → commands-6KNKGAYK.js} +5 -5
  98. package/dist/chunks/{crash-report-M5Q3DQCN.js → crash-report-4ZIUEO2T.js} +7 -7
  99. package/dist/chunks/devtools-V6SF7RES.js +93 -0
  100. package/dist/chunks/devtools-V6SF7RES.js.map +6 -0
  101. package/dist/chunks/{dist-JSQDWJJ7.js → dist-52AQ2S3B.js} +2 -2
  102. package/dist/chunks/{dist-4OQCWTIT.js → dist-6N7EBKOP.js} +2 -2
  103. package/dist/chunks/{dist-KGLSBIES.js → dist-ADL22Y3L.js} +1631 -208
  104. package/dist/chunks/dist-ADL22Y3L.js.map +6 -0
  105. package/dist/chunks/{dist-37DNQCWH.js → dist-DDOLI4FC.js} +2 -2
  106. package/dist/chunks/{dist-XB6XFRHI.js → dist-EXJEMH6E.js} +2 -2
  107. package/dist/chunks/{dist-PRV7KU6K.js → dist-KUY5YJQU.js} +2 -2
  108. package/dist/chunks/{dist-33WLKROX.js → dist-LJF7HG5B.js} +2 -2
  109. package/dist/chunks/{dist-RUF7G2EJ.js → dist-W2RL2YQU.js} +2 -2
  110. package/dist/chunks/{doctor-UHW2CT5G.js → doctor-BSYUHWBV.js} +8 -8
  111. package/dist/chunks/{drain-WW3OCWON.js → drain-ANNH6M4M.js} +11 -10
  112. package/dist/chunks/drain-ANNH6M4M.js.map +6 -0
  113. package/dist/chunks/{eval-7W7MY7MI.js → eval-FOOSHOQH.js} +2 -2
  114. package/dist/chunks/{exec-D3HAVGO3.js → exec-66BTZSXT.js} +60 -32
  115. package/dist/chunks/exec-66BTZSXT.js.map +6 -0
  116. package/dist/chunks/{home-OOMHTBCU.js → home-F3JAP7EK.js} +3 -3
  117. package/dist/chunks/{host-queries-LLRW35KQ.js → host-queries-DAZODJGM.js} +14 -14
  118. package/dist/chunks/{lifecycle-X3WP7K6J.js → lifecycle-4K6UYXHW.js} +27 -26
  119. package/dist/chunks/{list-YNC6NTUS.js → list-5P46GOYS.js} +16 -15
  120. package/dist/chunks/list-5P46GOYS.js.map +6 -0
  121. package/dist/chunks/{login-J2W3FTAI.js → login-3NTMRWH5.js} +8 -8
  122. package/dist/chunks/{logs-FBCRI5GX.js → logs-TOENBRPG.js} +4 -4
  123. package/dist/chunks/{mcp-S6HNWBTQ.js → mcp-R7AB2UAO.js} +23 -22
  124. package/dist/chunks/mcp-R7AB2UAO.js.map +6 -0
  125. package/dist/chunks/{message-command-4SLCM27I.js → message-command-G5CGLKBG.js} +40 -39
  126. package/dist/chunks/message-command-G5CGLKBG.js.map +6 -0
  127. package/dist/chunks/{operator-tools-PLCPLKHA.js → operator-tools-FQ6ITKE6.js} +12 -12
  128. package/dist/chunks/{output-schema-35UX32FC.js → output-schema-SKFZ25BQ.js} +3 -3
  129. package/dist/chunks/{pal-5BVWB3W7.js → pal-TNQSB2GK.js} +14 -14
  130. package/dist/chunks/{providers-7VVPQLKS.js → providers-HZYMMU6E.js} +6 -6
  131. package/dist/chunks/{resident-FUJTNNQU.js → resident-YDO5N5JH.js} +31 -28
  132. package/dist/chunks/resident-YDO5N5JH.js.map +6 -0
  133. package/dist/chunks/resume-OJYZ6YER.js +22 -0
  134. package/dist/chunks/{resume-command-LDVO5KIP.js → resume-command-5KZPLTK7.js} +4 -4
  135. package/dist/chunks/{schedule-NV5NQSKS.js → schedule-6XIBAC7U.js} +8 -8
  136. package/dist/chunks/{service-OZEMWADJ.js → service-2LFLAXAG.js} +28 -27
  137. package/dist/chunks/service-2LFLAXAG.js.map +6 -0
  138. package/dist/chunks/session-step-3PJBN33Y.js +29 -0
  139. package/dist/chunks/{skills-A7XMDZPV.js → skills-JOY3NTBC.js} +8 -8
  140. package/dist/chunks/{state-ZOLHKFZD.js → state-QQ2YFP4G.js} +2 -2
  141. package/dist/chunks/{store-ASOIXVEH.js → store-47KUDP7H.js} +9 -9
  142. package/dist/chunks/{store-AG3KCS6R.js → store-CLZKGKXL.js} +4 -4
  143. package/dist/chunks/{store-WZES4TNW.js → store-WC3TVOLU.js} +6 -6
  144. package/dist/chunks/{tui-H7MVCBHH.js → tui-2M6OGQUI.js} +228 -112
  145. package/dist/chunks/tui-2M6OGQUI.js.map +6 -0
  146. package/dist/chunks/{upgrade-G2R3EBLE.js → upgrade-ZZYBXJXO.js} +2 -2
  147. package/dist/chunks/{worktree-YIQTRMAT.js → worktree-7C3EZZ7D.js} +11 -11
  148. package/dist/chunks/wrapper-XHVFM6KS.js +34 -0
  149. package/dist/chunks/wrapper-XHVFM6KS.js.map +6 -0
  150. package/dist/cli-runtime.d.ts +4 -0
  151. package/dist/cli-runtime.d.ts.map +1 -1
  152. package/dist/cli.d.ts.map +1 -1
  153. package/dist/commands/acp.d.ts +1 -1
  154. package/dist/commands/acp.d.ts.map +1 -1
  155. package/dist/commands/desktop-host.d.ts.map +1 -1
  156. package/dist/commands/exec-flags.d.ts +1 -1
  157. package/dist/commands/exec-flags.d.ts.map +1 -1
  158. package/dist/commands/exec-json.d.ts.map +1 -1
  159. package/dist/commands/exec.d.ts.map +1 -1
  160. package/dist/commands/resident-flags.d.ts.map +1 -1
  161. package/dist/config/load.d.ts.map +1 -1
  162. package/dist/config/schema.d.ts +9 -0
  163. package/dist/config/schema.d.ts.map +1 -1
  164. package/dist/index.js +25 -24
  165. package/dist/integrations/harness/codex-adapter.d.ts.map +1 -1
  166. package/dist/integrations/monitors/web-access-hint.d.ts +8 -0
  167. package/dist/integrations/monitors/web-access-hint.d.ts.map +1 -0
  168. package/dist/integrations/resident/runner-worker.js +20 -18
  169. package/dist/integrations/resident/runner-worker.js.map +1 -1
  170. package/dist/integrations/resident/session-step.d.ts.map +1 -1
  171. package/dist/integrations/workflows/offering.d.ts +1 -1
  172. package/dist/pals/actions.d.ts.map +1 -1
  173. package/dist/permissions/auto-classifier.d.ts +74 -0
  174. package/dist/permissions/auto-classifier.d.ts.map +1 -0
  175. package/dist/permissions/consent-prompt.d.ts +11 -0
  176. package/dist/permissions/consent-prompt.d.ts.map +1 -0
  177. package/dist/permissions/consent.d.ts +9 -0
  178. package/dist/permissions/consent.d.ts.map +1 -0
  179. package/dist/permissions/launch.d.ts +59 -0
  180. package/dist/permissions/launch.d.ts.map +1 -0
  181. package/dist/permissions/live-mode.d.ts +5 -4
  182. package/dist/permissions/live-mode.d.ts.map +1 -1
  183. package/dist/permissions/mode-names.d.ts +2 -1
  184. package/dist/permissions/mode-names.d.ts.map +1 -1
  185. package/dist/permissions/mode.d.ts +59 -19
  186. package/dist/permissions/mode.d.ts.map +1 -1
  187. package/dist/permissions/rules.d.ts.map +1 -1
  188. package/dist/permissions/settings.d.ts +81 -0
  189. package/dist/permissions/settings.d.ts.map +1 -0
  190. package/dist/tui/App.d.ts +160 -1
  191. package/dist/tui/App.d.ts.map +1 -1
  192. package/dist/tui/BrandHeader.d.ts.map +1 -1
  193. package/dist/tui/StatusBar.d.ts +6 -0
  194. package/dist/tui/StatusBar.d.ts.map +1 -1
  195. package/dist/tui/agent.d.ts +52 -3
  196. package/dist/tui/agent.d.ts.map +1 -1
  197. package/dist/tui/mentions.d.ts +6 -0
  198. package/dist/tui/mentions.d.ts.map +1 -1
  199. package/dist/tui/slashCommands.d.ts +1 -1
  200. package/dist/tui/slashCommands.d.ts.map +1 -1
  201. package/dist/tui/status-line/payload.d.ts.map +1 -1
  202. package/dist/tui/types.d.ts +13 -2
  203. package/dist/tui/types.d.ts.map +1 -1
  204. package/package.json +9 -9
  205. package/dist/chunks/acp-WRUFVVVS.js.map +0 -6
  206. package/dist/chunks/add-KNRDMCME.js.map +0 -6
  207. package/dist/chunks/agent-session-2XPAWSJU.js +0 -51
  208. package/dist/chunks/bin-main-Y2J7CPYI.js.map +0 -6
  209. package/dist/chunks/chat-YF3TI43Y.js.map +0 -6
  210. package/dist/chunks/chunk-4H4YDNND.js.map +0 -6
  211. package/dist/chunks/chunk-72TESSG2.js.map +0 -6
  212. package/dist/chunks/chunk-77AX2GEP.js.map +0 -6
  213. package/dist/chunks/chunk-7WKQQOKK.js.map +0 -6
  214. package/dist/chunks/chunk-GEB3OP2H.js.map +0 -6
  215. package/dist/chunks/chunk-HRRQSXVP.js.map +0 -6
  216. package/dist/chunks/chunk-KSLX3NGM.js.map +0 -6
  217. package/dist/chunks/chunk-N3YMYKEU.js +0 -84
  218. package/dist/chunks/chunk-N3YMYKEU.js.map +0 -6
  219. package/dist/chunks/chunk-REBTUQC6.js.map +0 -6
  220. package/dist/chunks/chunk-TQGYYDLF.js.map +0 -6
  221. package/dist/chunks/cli-runtime-6MW2CSZV.js.map +0 -6
  222. package/dist/chunks/dist-KGLSBIES.js.map +0 -6
  223. package/dist/chunks/drain-WW3OCWON.js.map +0 -6
  224. package/dist/chunks/exec-D3HAVGO3.js.map +0 -6
  225. package/dist/chunks/list-YNC6NTUS.js.map +0 -6
  226. package/dist/chunks/mcp-S6HNWBTQ.js.map +0 -6
  227. package/dist/chunks/message-command-4SLCM27I.js.map +0 -6
  228. package/dist/chunks/resident-FUJTNNQU.js.map +0 -6
  229. package/dist/chunks/resume-AJ6LESHD.js +0 -22
  230. package/dist/chunks/service-OZEMWADJ.js.map +0 -6
  231. package/dist/chunks/session-step-RZEULQKO.js +0 -27
  232. package/dist/chunks/tui-H7MVCBHH.js.map +0 -6
  233. /package/dist/chunks/{activity-command-7GP4PLBD.js.map → activity-command-RM6YEJJE.js.map} +0 -0
  234. /package/dist/chunks/{agent-LZDDK3NN.js.map → agent-UNGHD2P3.js.map} +0 -0
  235. /package/dist/chunks/{agent-session-2XPAWSJU.js.map → agent-session-FG4XT6SX.js.map} +0 -0
  236. /package/dist/chunks/{archive-PNHAJS2H.js.map → archive-IAT6HD7B.js.map} +0 -0
  237. /package/dist/chunks/{browser-RVLLK6CN.js.map → browser-4P3N4ZQL.js.map} +0 -0
  238. /package/dist/chunks/{chunk-MULW7FFH.js.map → chunk-2WMXW2HX.js.map} +0 -0
  239. /package/dist/chunks/{chunk-DRXG4OLL.js.map → chunk-466ECWQB.js.map} +0 -0
  240. /package/dist/chunks/{chunk-2TDWK353.js.map → chunk-47W5PCU5.js.map} +0 -0
  241. /package/dist/chunks/{chunk-PSLRTJU5.js.map → chunk-4DQ5TVCH.js.map} +0 -0
  242. /package/dist/chunks/{chunk-A5GALFIC.js.map → chunk-6HPZCB5F.js.map} +0 -0
  243. /package/dist/chunks/{chunk-VCUPZJDO.js.map → chunk-6PMO2KA2.js.map} +0 -0
  244. /package/dist/chunks/{chunk-LO5DFG6H.js.map → chunk-735YHXE3.js.map} +0 -0
  245. /package/dist/chunks/{chunk-O6X4O7VQ.js.map → chunk-7PBYGA76.js.map} +0 -0
  246. /package/dist/chunks/{chunk-DS2PIOVD.js.map → chunk-7XBUFSLG.js.map} +0 -0
  247. /package/dist/chunks/{chunk-5YERJLR7.js.map → chunk-BQRKMDDF.js.map} +0 -0
  248. /package/dist/chunks/{chunk-GYM3FUBH.js.map → chunk-D5HL6QDV.js.map} +0 -0
  249. /package/dist/chunks/{chunk-ERY3CYIM.js.map → chunk-G2ZBMR22.js.map} +0 -0
  250. /package/dist/chunks/{chunk-5NHKC3NO.js.map → chunk-G6ETOUUR.js.map} +0 -0
  251. /package/dist/chunks/{chunk-HJBZYFCC.js.map → chunk-GAYGCGIY.js.map} +0 -0
  252. /package/dist/chunks/{chunk-UARWI3TA.js.map → chunk-GW7O5N42.js.map} +0 -0
  253. /package/dist/chunks/{chunk-YX2ZK34T.js.map → chunk-HA37WH7H.js.map} +0 -0
  254. /package/dist/chunks/{chunk-N2CP3FIQ.js.map → chunk-HVJXMGCJ.js.map} +0 -0
  255. /package/dist/chunks/{chunk-HFFINVNN.js.map → chunk-JL3LUBAN.js.map} +0 -0
  256. /package/dist/chunks/{chunk-NYRBM7PR.js.map → chunk-K5J7ATQR.js.map} +0 -0
  257. /package/dist/chunks/{chunk-HFUBLJE5.js.map → chunk-KOOSFKHR.js.map} +0 -0
  258. /package/dist/chunks/{chunk-YDD74UVE.js.map → chunk-MJG4FQ27.js.map} +0 -0
  259. /package/dist/chunks/{chunk-SMAN2IR4.js.map → chunk-MRJCV6EH.js.map} +0 -0
  260. /package/dist/chunks/{chunk-37FCG7VX.js.map → chunk-N5L7HGNL.js.map} +0 -0
  261. /package/dist/chunks/{chunk-T5GKAQHN.js.map → chunk-ORHVELT4.js.map} +0 -0
  262. /package/dist/chunks/{chunk-HLHYVGQE.js.map → chunk-PKIH55PX.js.map} +0 -0
  263. /package/dist/chunks/{chunk-4GIDESAM.js.map → chunk-PWFLM6BJ.js.map} +0 -0
  264. /package/dist/chunks/{chunk-M46XYX7O.js.map → chunk-QKSBBKKC.js.map} +0 -0
  265. /package/dist/chunks/{chunk-DW23UIKM.js.map → chunk-RU3AE4JE.js.map} +0 -0
  266. /package/dist/chunks/{chunk-KK73BCYK.js.map → chunk-SZUOO7A2.js.map} +0 -0
  267. /package/dist/chunks/{chunk-POEIV6AQ.js.map → chunk-TFA5ZAGJ.js.map} +0 -0
  268. /package/dist/chunks/{chunk-QWCASGYH.js.map → chunk-TZLYJWSW.js.map} +0 -0
  269. /package/dist/chunks/{chunk-XHJMDBRV.js.map → chunk-U6EH3UCL.js.map} +0 -0
  270. /package/dist/chunks/{chunk-ABHX2QBJ.js.map → chunk-UKOMZND2.js.map} +0 -0
  271. /package/dist/chunks/{chunk-ND6ZNIUM.js.map → chunk-UW42IRA4.js.map} +0 -0
  272. /package/dist/chunks/{chunk-MF45FNH3.js.map → chunk-UZ7ONUMS.js.map} +0 -0
  273. /package/dist/chunks/{chunk-MUG3SBGU.js.map → chunk-V5WCUTSO.js.map} +0 -0
  274. /package/dist/chunks/{chunk-HFMDSVBA.js.map → chunk-VHZ3I7L4.js.map} +0 -0
  275. /package/dist/chunks/{chunk-VIDT6RAV.js.map → chunk-VK2BAABY.js.map} +0 -0
  276. /package/dist/chunks/{chunk-VONRWBC6.js.map → chunk-VKZKDPKS.js.map} +0 -0
  277. /package/dist/chunks/{chunk-HS3TPTJ3.js.map → chunk-VUQE34X4.js.map} +0 -0
  278. /package/dist/chunks/{chunk-XBRRTAXP.js.map → chunk-WCC5ABWX.js.map} +0 -0
  279. /package/dist/chunks/{chunk-R7HI2NMR.js.map → chunk-XDA57K4Q.js.map} +0 -0
  280. /package/dist/chunks/{chunk-UI3MX7CC.js.map → chunk-XHBZBISL.js.map} +0 -0
  281. /package/dist/chunks/{chunk-34IZ6DMB.js.map → chunk-YMSXUKHE.js.map} +0 -0
  282. /package/dist/chunks/{chunk-E6RPYGJP.js.map → chunk-YXFS44LU.js.map} +0 -0
  283. /package/dist/chunks/{chunk-V6NJWYMP.js.map → chunk-ZDAUAJ4L.js.map} +0 -0
  284. /package/dist/chunks/{commands-FHJCPYZK.js.map → commands-6KNKGAYK.js.map} +0 -0
  285. /package/dist/chunks/{crash-report-M5Q3DQCN.js.map → crash-report-4ZIUEO2T.js.map} +0 -0
  286. /package/dist/chunks/{dist-JSQDWJJ7.js.map → dist-52AQ2S3B.js.map} +0 -0
  287. /package/dist/chunks/{dist-4OQCWTIT.js.map → dist-6N7EBKOP.js.map} +0 -0
  288. /package/dist/chunks/{dist-37DNQCWH.js.map → dist-DDOLI4FC.js.map} +0 -0
  289. /package/dist/chunks/{dist-XB6XFRHI.js.map → dist-EXJEMH6E.js.map} +0 -0
  290. /package/dist/chunks/{dist-PRV7KU6K.js.map → dist-KUY5YJQU.js.map} +0 -0
  291. /package/dist/chunks/{dist-33WLKROX.js.map → dist-LJF7HG5B.js.map} +0 -0
  292. /package/dist/chunks/{dist-RUF7G2EJ.js.map → dist-W2RL2YQU.js.map} +0 -0
  293. /package/dist/chunks/{doctor-UHW2CT5G.js.map → doctor-BSYUHWBV.js.map} +0 -0
  294. /package/dist/chunks/{eval-7W7MY7MI.js.map → eval-FOOSHOQH.js.map} +0 -0
  295. /package/dist/chunks/{home-OOMHTBCU.js.map → home-F3JAP7EK.js.map} +0 -0
  296. /package/dist/chunks/{host-queries-LLRW35KQ.js.map → host-queries-DAZODJGM.js.map} +0 -0
  297. /package/dist/chunks/{lifecycle-X3WP7K6J.js.map → lifecycle-4K6UYXHW.js.map} +0 -0
  298. /package/dist/chunks/{login-J2W3FTAI.js.map → login-3NTMRWH5.js.map} +0 -0
  299. /package/dist/chunks/{logs-FBCRI5GX.js.map → logs-TOENBRPG.js.map} +0 -0
  300. /package/dist/chunks/{operator-tools-PLCPLKHA.js.map → operator-tools-FQ6ITKE6.js.map} +0 -0
  301. /package/dist/chunks/{output-schema-35UX32FC.js.map → output-schema-SKFZ25BQ.js.map} +0 -0
  302. /package/dist/chunks/{pal-5BVWB3W7.js.map → pal-TNQSB2GK.js.map} +0 -0
  303. /package/dist/chunks/{providers-7VVPQLKS.js.map → providers-HZYMMU6E.js.map} +0 -0
  304. /package/dist/chunks/{resume-AJ6LESHD.js.map → resume-OJYZ6YER.js.map} +0 -0
  305. /package/dist/chunks/{resume-command-LDVO5KIP.js.map → resume-command-5KZPLTK7.js.map} +0 -0
  306. /package/dist/chunks/{schedule-NV5NQSKS.js.map → schedule-6XIBAC7U.js.map} +0 -0
  307. /package/dist/chunks/{session-step-RZEULQKO.js.map → session-step-3PJBN33Y.js.map} +0 -0
  308. /package/dist/chunks/{skills-A7XMDZPV.js.map → skills-JOY3NTBC.js.map} +0 -0
  309. /package/dist/chunks/{state-ZOLHKFZD.js.map → state-QQ2YFP4G.js.map} +0 -0
  310. /package/dist/chunks/{store-AG3KCS6R.js.map → store-47KUDP7H.js.map} +0 -0
  311. /package/dist/chunks/{store-ASOIXVEH.js.map → store-CLZKGKXL.js.map} +0 -0
  312. /package/dist/chunks/{store-WZES4TNW.js.map → store-WC3TVOLU.js.map} +0 -0
  313. /package/dist/chunks/{upgrade-G2R3EBLE.js.map → upgrade-ZZYBXJXO.js.map} +0 -0
  314. /package/dist/chunks/{worktree-YIQTRMAT.js.map → worktree-7C3EZZ7D.js.map} +0 -0
@@ -1,22 +1,883 @@
1
1
  import { createRequire as __namzuCreateRequire } from 'node:module';
2
2
  const require = __namzuCreateRequire(import.meta.url);
3
3
  import {
4
+ CUT_MARK_CHARS,
4
5
  EMPTY_ROWS,
5
6
  ParserUnavailableError,
6
7
  isDeclarationFile,
7
8
  languageOf
8
- } from "./chunk-7WKQQOKK.js";
9
+ } from "./chunk-M6CYVSNV.js";
9
10
  import {
10
- __name
11
+ __commonJS,
12
+ __name,
13
+ __toESM
11
14
  } from "./chunk-76FLAFCG.js";
12
15
 
16
+ // ../../node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js
17
+ var require_ignore = __commonJS({
18
+ "../../node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js"(exports, module) {
19
+ "use strict";
20
+ function makeArray(subject) {
21
+ return Array.isArray(subject) ? subject : [subject];
22
+ }
23
+ __name(makeArray, "makeArray");
24
+ var UNDEFINED = void 0;
25
+ var EMPTY = "";
26
+ var SPACE = " ";
27
+ var ESCAPE = "\\";
28
+ var REGEX_LITERAL_SPECIAL = /[.*+?()[\]{}^$|\\/]/;
29
+ var BOM = "\uFEFF";
30
+ var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
31
+ var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
32
+ var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
33
+ var REGEX_SPLITALL_CRLF = /\r?\n/g;
34
+ var DOUBLE_SLASH = "//";
35
+ var SLASH_CODE = 47;
36
+ var DOT_CODE = 46;
37
+ var SLASH = "/";
38
+ var TMP_KEY_IGNORE = "node-ignore";
39
+ if (typeof Symbol !== "undefined") {
40
+ TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
41
+ }
42
+ var KEY_IGNORE = TMP_KEY_IGNORE;
43
+ var define = /* @__PURE__ */ __name((object, key, value) => {
44
+ Object.defineProperty(object, key, { value });
45
+ return value;
46
+ }, "define");
47
+ var RETURN_FALSE = /* @__PURE__ */ __name(() => false, "RETURN_FALSE");
48
+ var cleanRangeBackSlash = /* @__PURE__ */ __name((slashes) => {
49
+ const { length } = slashes;
50
+ return slashes.slice(0, length - length % 2);
51
+ }, "cleanRangeBackSlash");
52
+ var POSIX_CLASSES = {
53
+ alnum: "0-9A-Za-z",
54
+ alpha: "A-Za-z",
55
+ blank: " \\t",
56
+ cntrl: "\\x00-\\x1f\\x7f",
57
+ digit: "0-9",
58
+ graph: "!-.0-~",
59
+ lower: "a-z",
60
+ print: " -.0-~",
61
+ punct: "!-.:-@\\[-`{-~",
62
+ // git's `sane-ctype.h` classifies \v and \f as control, not space,
63
+ // unlike C's `isspace`
64
+ space: " \\t\\n\\r",
65
+ upper: "A-Z",
66
+ xdigit: "0-9A-Fa-f"
67
+ };
68
+ var CLASS_MEMBERS_TO_ESCAPE = "\\]^-[";
69
+ var escapeMember = /* @__PURE__ */ __name((char) => CLASS_MEMBERS_TO_ESCAPE.indexOf(char) < 0 ? char : ESCAPE + char, "escapeMember");
70
+ var NON_SLASH = "(?!\\/)";
71
+ var classSource = /* @__PURE__ */ __name((negated, body) => {
72
+ if (negated) {
73
+ return `[^\\/${body}]`;
74
+ }
75
+ const source = `[${body}]`;
76
+ return new RegExp(source).test("/") ? NON_SLASH + source : source;
77
+ }, "classSource");
78
+ var scanBracket = /* @__PURE__ */ __name((pattern, start) => {
79
+ const { length } = pattern;
80
+ let index = start + 1;
81
+ let negated = EMPTY;
82
+ const lead = pattern[index];
83
+ if (lead === "!" || lead === "^") {
84
+ negated = "^";
85
+ index++;
86
+ }
87
+ let body = EMPTY;
88
+ let prev = EMPTY;
89
+ for (; ; ) {
90
+ const char = pattern[index];
91
+ if (char === UNDEFINED) {
92
+ return null;
93
+ }
94
+ if (char === ESCAPE) {
95
+ const escaped = pattern[index + 1];
96
+ if (escaped === UNDEFINED) {
97
+ return null;
98
+ }
99
+ body += escapeMember(escaped);
100
+ prev = escaped;
101
+ index++;
102
+ } else if (char === "-" && prev && index + 1 < length && pattern[index + 1] !== "]") {
103
+ index++;
104
+ let to = pattern[index];
105
+ if (to === ESCAPE) {
106
+ to = pattern[index += 1];
107
+ }
108
+ if (prev <= to) {
109
+ body += `-${escapeMember(to)}`;
110
+ }
111
+ prev = EMPTY;
112
+ } else if (char === "[" && pattern[index + 1] === ":") {
113
+ const nameStart = index + 2;
114
+ let end = nameStart;
115
+ while (end < length && pattern[end] !== "]") {
116
+ end++;
117
+ }
118
+ if (end === length) {
119
+ return null;
120
+ }
121
+ if (end > nameStart && pattern[end - 1] === ":") {
122
+ const expanded = POSIX_CLASSES[pattern.slice(nameStart, end - 1)];
123
+ if (expanded === UNDEFINED) {
124
+ return null;
125
+ }
126
+ body += expanded;
127
+ prev = EMPTY;
128
+ index = end;
129
+ } else {
130
+ body += escapeMember("[");
131
+ prev = "[";
132
+ index = nameStart - 2;
133
+ }
134
+ } else {
135
+ body += escapeMember(char);
136
+ prev = char;
137
+ }
138
+ index++;
139
+ if (pattern[index] === "]") {
140
+ return {
141
+ end: index,
142
+ source: classSource(negated, body)
143
+ };
144
+ }
145
+ }
146
+ }, "scanBracket");
147
+ var NEVER_MATCH = "[]";
148
+ var PLACEHOLDER = "\0";
149
+ var REGEX_RESTORE_PLACEHOLDER = new RegExp(
150
+ `${PLACEHOLDER}(\\d+)${PLACEHOLDER}`,
151
+ "g"
152
+ );
153
+ var TRAILING_WILDCARD = "\uE000";
154
+ var TRAILING_DOUBLESTAR = "\uE001";
155
+ var extractBrackets = /* @__PURE__ */ __name((pattern) => {
156
+ const sources = [];
157
+ const hold = /* @__PURE__ */ __name((source) => `${PLACEHOLDER}${sources.push(source) - 1}${PLACEHOLDER}`, "hold");
158
+ const { length } = pattern;
159
+ let out = EMPTY;
160
+ let index = 0;
161
+ while (index < length) {
162
+ const char = pattern[index];
163
+ if (char === ESCAPE) {
164
+ const escaped = pattern[index + 1];
165
+ if (escaped === UNDEFINED || escaped === SLASH && index + 2 === length) {
166
+ out += hold(NEVER_MATCH);
167
+ } else if (escaped === "*" || escaped === "[" || escaped === SPACE || escaped === ESCAPE) {
168
+ out += pattern.slice(index, index + 2);
169
+ } else {
170
+ out += hold(
171
+ REGEX_LITERAL_SPECIAL.test(escaped) ? ESCAPE + escaped : escaped
172
+ );
173
+ }
174
+ index += 2;
175
+ } else if (char === PLACEHOLDER) {
176
+ out += hold(`[${PLACEHOLDER}]`);
177
+ index++;
178
+ } else if (char === "[") {
179
+ const scanned = scanBracket(pattern, index);
180
+ if (scanned === null) {
181
+ out += hold(NEVER_MATCH);
182
+ index = length;
183
+ } else {
184
+ out += hold(scanned.source);
185
+ index = scanned.end + 1;
186
+ }
187
+ } else {
188
+ out += char;
189
+ index++;
190
+ }
191
+ }
192
+ return {
193
+ source: out,
194
+ sources
195
+ };
196
+ }, "extractBrackets");
197
+ var DIRECT = null;
198
+ var REGEX_INNER_SLASH = /\/(?!$)/;
199
+ var REPLACERS = [
200
+ // Replace (\ ) with ' '
201
+ // Only a space: an escaped tab or other whitespace is already a literal by
202
+ // the time it reaches here, and a bare tab must be left as one, not turned
203
+ // into a space.
204
+ // (\ ) -> ' '
205
+ // (\\ ) -> '\\ '
206
+ // (\\\ ) -> '\\ '
207
+ [
208
+ // A run of backslashes is taken whole, from its first one, so no match
209
+ // ever starts again inside it -- `(\\+?) ` did, which made a long run
210
+ // quadratic.
211
+ /(\\+)( ?)/g,
212
+ (_, run, space) => space ? run.slice(0, run.length - run.length % 2) + SPACE : run,
213
+ ESCAPE + SPACE
214
+ ],
215
+ // Escape metacharacters
216
+ // which is written down by users but means special for regular expressions.
217
+ // > There are 12 characters with special meanings:
218
+ // > - the backslash \,
219
+ // > - the caret ^,
220
+ // > - the dollar sign $,
221
+ // > - the period or dot .,
222
+ // > - the vertical bar or pipe symbol |,
223
+ // > - the question mark ?,
224
+ // > - the asterisk or star *,
225
+ // > - the plus sign +,
226
+ // > - the opening parenthesis (,
227
+ // > - the closing parenthesis ),
228
+ // > - and the opening square bracket [,
229
+ // > - the opening curly brace {,
230
+ // > These special characters are often called "metacharacters".
231
+ [
232
+ /[\\$.|*+(){^]/g,
233
+ (match) => `\\${match}`
234
+ ],
235
+ [
236
+ // > a question mark (?) matches a single character
237
+ /(?!\\)\?/g,
238
+ () => "[^/]",
239
+ "?"
240
+ ],
241
+ // leading slash
242
+ [
243
+ // > A leading slash matches the beginning of the pathname.
244
+ // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c".
245
+ // A leading slash matches the beginning of the pathname
246
+ /^\//,
247
+ () => "^",
248
+ SLASH
249
+ ],
250
+ // replace special metacharacter slash after the leading slash
251
+ [
252
+ /\//g,
253
+ () => "\\/",
254
+ SLASH
255
+ ],
256
+ [
257
+ // > A leading "**" followed by a slash means match in all directories.
258
+ // > For example, "**/foo" matches file or directory "foo" anywhere,
259
+ // > the same as pattern "foo".
260
+ // > "**/foo/bar" matches file or directory "bar" anywhere that is directly
261
+ // > under directory "foo".
262
+ // Notice that the '*'s have been replaced as '\\*'
263
+ /^\^*(?:\\\*\\\*\\\/)+/,
264
+ // '**/foo' <-> 'foo'
265
+ () => "^(?:.*\\/)?",
266
+ "*"
267
+ ],
268
+ // starting
269
+ [
270
+ // there will be no leading '/'
271
+ // (which has been replaced by section "leading slash")
272
+ // If starts with '**', adding a '^' to the regular expression also works
273
+ DIRECT,
274
+ (source, pattern) => {
275
+ if (!source || source[0] === "^") {
276
+ return source;
277
+ }
278
+ const anchor = !REGEX_INNER_SLASH.test(pattern) ? "(?:^|\\/)" : "^";
279
+ return anchor + source;
280
+ }
281
+ ],
282
+ // two globstars
283
+ [
284
+ // Use lookahead assertions so that we could match more than one `'/**'`
285
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
286
+ // Zero, one or several directories
287
+ // should not use '*', or it will be replaced by the next replacer
288
+ // Check if it is not the last `'/**'`
289
+ (_, index, str) => index + 6 < str.length ? str.slice(index + 6) === "\\/" ? "(?:\\/[^\\/]+)+" : "(?:\\/[^\\/]+)*" : `\\/${TRAILING_DOUBLESTAR}`,
290
+ "*"
291
+ ],
292
+ // normal intermediate wildcards
293
+ [
294
+ // Never replace escaped '*'
295
+ // ignore rule '\*' will match the path '*'
296
+ // 'abc.*/' -> go
297
+ // 'abc.*' -> skip this rule,
298
+ // coz trailing single wildcard will be handed by [trailing wildcard]
299
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
300
+ // '*.js' matches '.js'
301
+ // '*.js' doesn't match 'abc'
302
+ (_, p1, p2) => {
303
+ const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
304
+ return p1 + unescaped;
305
+ },
306
+ "*"
307
+ ],
308
+ // trailing wildcard, held apart from a literal star
309
+ [
310
+ // The step above leaves a trailing `*` alone, so a single `\*` is all that
311
+ // can be left at the end here. Whether it is a wildcard or a literal
312
+ // turns on the backslashes the user put in front of it: the escaper has
313
+ // since doubled every one, so what stands here is those `2N` doubled
314
+ // backslashes and then the star's own escape. An even number of the
315
+ // original `N` leaves the star unescaped -- a wildcard -- and an odd
316
+ // number escapes it -- a literal. This runs while the two are still
317
+ // distinct, before the unescape steps below collapse the literal onto
318
+ // the very `\*` a wildcard leaves behind.
319
+ /(^|[^\\])((?:\\\\)*)\\\*$/,
320
+ (match, p1, p2) => (
321
+ // `p2` holds the doubled user backslashes; half of them is `N`.
322
+ p2.length / 2 % 2 === 0 ? p1 + p2 + TRAILING_WILDCARD : match
323
+ ),
324
+ "*"
325
+ ],
326
+ [
327
+ // unescape, revert step 3 except for back slash
328
+ // For example, if a user escape a '\\*',
329
+ // after step 3, the result will be '\\\\\\*'
330
+ /\\\\\\(?=[$.|*+(){^])/g,
331
+ () => ESCAPE,
332
+ ESCAPE + ESCAPE
333
+ ],
334
+ [
335
+ // '\\\\' -> '\\'
336
+ /\\\\/g,
337
+ () => ESCAPE,
338
+ ESCAPE + ESCAPE
339
+ ],
340
+ [
341
+ // Every real bracket expression -- POSIX classes included -- has already
342
+ // been held aside by `extractBrackets`, so the only `[` left in the
343
+ // pattern is an escaped, literal one.
344
+ // `\` is escaped by step 3
345
+ /\\\[([^\]/]*?)(\\*)($|\])/g,
346
+ // '\\[bar]' -> '\\\\[bar\\]'
347
+ (match, range, endEscape, close) => `\\[${range}${cleanRangeBackSlash(endEscape)}${close}`,
348
+ "["
349
+ ],
350
+ // ending
351
+ [
352
+ // 'js' will not match 'js.'
353
+ // 'ab' will not match 'abc'
354
+ DIRECT,
355
+ // WTF!
356
+ // https://git-scm.com/docs/gitignore
357
+ // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1)
358
+ // which re-fixes #24, #38
359
+ // > If there is a separator at the end of the pattern then the pattern
360
+ // > will only match directories, otherwise the pattern can match both
361
+ // > files and directories.
362
+ // 'js*' will not match 'a.js'
363
+ // 'js/' will not match 'a.js'
364
+ // 'js' will match 'a.js' and 'a.js/'
365
+ (source) => {
366
+ const last = source[source.length - 1];
367
+ if (!last || last === TRAILING_WILDCARD || last === TRAILING_DOUBLESTAR) {
368
+ return source;
369
+ }
370
+ return last === SLASH ? `${source}$` : `${source}(?=$|\\/$)`;
371
+ }
372
+ ]
373
+ ];
374
+ var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\uE000$/;
375
+ var MODE_IGNORE = "regex";
376
+ var MODE_CHECK_IGNORE = "checkRegex";
377
+ var UNDERSCORE = "_";
378
+ var replaceTrailingWildcard = /* @__PURE__ */ __name((_, p1) => {
379
+ const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
380
+ return `${prefix}(?=$|\\/$)`;
381
+ }, "replaceTrailingWildcard");
382
+ var REGEX_REPLACE_TRAILING_DOUBLESTAR = /\uE001$/;
383
+ var replaceTrailingDoublestar = /* @__PURE__ */ __name(() => ".+(?=$|\\/$)", "replaceTrailingDoublestar");
384
+ var WILDCARD = "[^\\/]*";
385
+ var separatorAfter = /* @__PURE__ */ __name((run, at) => {
386
+ let separator = EMPTY;
387
+ for (let index = at + 1; index < run.length && !run[index].wildcard; index++) {
388
+ separator += run[index].single;
389
+ }
390
+ return separator;
391
+ }, "separatorAfter");
392
+ var pinWildcards = /* @__PURE__ */ __name((source) => {
393
+ if (source.indexOf(WILDCARD) < 0) {
394
+ return source;
395
+ }
396
+ const tokens = [];
397
+ const { length } = source;
398
+ let index = 0;
399
+ while (index < length) {
400
+ const char = source[index];
401
+ if (source.startsWith(WILDCARD, index)) {
402
+ tokens.push({ wildcard: true });
403
+ index += WILDCARD.length;
404
+ } else if (char === "[") {
405
+ let end = index + 1;
406
+ if (source[end] === "^") {
407
+ end++;
408
+ }
409
+ if (source[end] === "]") {
410
+ end++;
411
+ }
412
+ while (end < length && source[end] !== "]") {
413
+ end += source[end] === ESCAPE ? 2 : 1;
414
+ }
415
+ end++;
416
+ tokens.push({ single: source.slice(index, end) });
417
+ index = end;
418
+ } else if (char === ESCAPE) {
419
+ tokens.push({ single: source.slice(index, index + 2) });
420
+ index += 2;
421
+ } else if (char === "(") {
422
+ let depth = 0;
423
+ let end = index;
424
+ do {
425
+ if (source[end] === ESCAPE) {
426
+ end++;
427
+ } else if (source[end] === "(") {
428
+ depth++;
429
+ } else if (source[end] === ")") {
430
+ depth--;
431
+ }
432
+ end++;
433
+ } while (end < length && depth > 0);
434
+ if ("*+?".indexOf(source[end]) >= 0) {
435
+ end++;
436
+ }
437
+ tokens.push({ boundary: source.slice(index, end) });
438
+ index = end;
439
+ } else if (char === "^" || char === "$") {
440
+ tokens.push({ boundary: char });
441
+ index++;
442
+ } else {
443
+ tokens.push({ single: char });
444
+ index++;
445
+ }
446
+ }
447
+ let out = EMPTY;
448
+ let run = [];
449
+ const flush = /* @__PURE__ */ __name(() => {
450
+ let lastWildcard;
451
+ run.forEach((token, at) => {
452
+ if (token.wildcard) {
453
+ lastWildcard = at;
454
+ }
455
+ });
456
+ run.forEach((token, at) => {
457
+ if (!token.wildcard) {
458
+ out += token.single;
459
+ return;
460
+ }
461
+ out += at === lastWildcard ? WILDCARD : `(?:(?!${separatorAfter(run, at)})[^\\/])*`;
462
+ });
463
+ run = [];
464
+ }, "flush");
465
+ tokens.forEach((token) => {
466
+ if (token.boundary === void 0) {
467
+ run.push(token);
468
+ return;
469
+ }
470
+ flush();
471
+ out += token.boundary;
472
+ });
473
+ flush();
474
+ return out;
475
+ }, "pinWildcards");
476
+ var makeRegexPrefix = /* @__PURE__ */ __name((pattern) => {
477
+ const { source, sources } = extractBrackets(pattern);
478
+ const replaced = REPLACERS.reduce(
479
+ // A pass whose matcher finds nothing hands back the very string it was
480
+ // given, so asking first costs a search and saves a rewrite. Ten of the
481
+ // fifteen passes never fire for a typical .gitignore line, and between
482
+ // them they were 45% of this chain.
483
+ (prev, [matcher, replacer, required]) => {
484
+ if (matcher === DIRECT) {
485
+ return replacer(prev, pattern);
486
+ }
487
+ if (required !== UNDEFINED && prev.indexOf(required) < 0) {
488
+ return prev;
489
+ }
490
+ return matcher.test(prev) ? prev.replace(matcher, replacer.bind(pattern)) : prev;
491
+ },
492
+ source
493
+ );
494
+ return sources.length ? replaced.replace(
495
+ REGEX_RESTORE_PLACEHOLDER,
496
+ (match, index) => sources[index]
497
+ ) : replaced;
498
+ }, "makeRegexPrefix");
499
+ var checkSourceOf = /* @__PURE__ */ __name((body, prefix) => {
500
+ if (body[body.length - 1] === SLASH) {
501
+ prefix = makeRegexPrefix(body.slice(0, -1));
502
+ }
503
+ const head = prefix.slice(0, -1);
504
+ const last = prefix[prefix.length - 1];
505
+ return last === TRAILING_WILDCARD ? `${head}$` : last === TRAILING_DOUBLESTAR ? `${head}.*$` : NEVER_MATCH;
506
+ }, "checkSourceOf");
507
+ var matchesBasename = /* @__PURE__ */ __name((body) => {
508
+ const index = body.indexOf(SLASH);
509
+ return index < 0 || index === body.length - 1;
510
+ }, "matchesBasename");
511
+ var basenameOf = /* @__PURE__ */ __name((path) => {
512
+ const end = path.length - 1;
513
+ const index = path.lastIndexOf(
514
+ SLASH,
515
+ path[end] === SLASH ? end - 1 : end
516
+ );
517
+ return index < 0 ? path : path.slice(index + 1);
518
+ }, "basenameOf");
519
+ var parentOf = /* @__PURE__ */ __name((path) => {
520
+ if (path.charCodeAt(0) === SLASH_CODE || path.indexOf(DOUBLE_SLASH) >= 0) {
521
+ const slices = path.split(SLASH).filter(Boolean);
522
+ slices.pop();
523
+ return slices.length ? slices.join(SLASH) + SLASH : EMPTY;
524
+ }
525
+ const end = path.length - 1;
526
+ const cut = path.lastIndexOf(
527
+ SLASH,
528
+ path.charCodeAt(end) === SLASH_CODE ? end - 1 : end
529
+ );
530
+ return cut < 0 ? EMPTY : path.slice(0, cut + 1);
531
+ }, "parentOf");
532
+ var isString = /* @__PURE__ */ __name((subject) => typeof subject === "string", "isString");
533
+ var checkPattern = /* @__PURE__ */ __name((pattern) => pattern && isString(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern), "checkPattern");
534
+ var splitPattern = /* @__PURE__ */ __name((pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean), "splitPattern");
535
+ var IgnoreRule = class {
536
+ static {
537
+ __name(this, "IgnoreRule");
538
+ }
539
+ constructor(pattern, mark, body, ignoreCase, negative, prefix) {
540
+ this.pattern = pattern;
541
+ this.mark = mark;
542
+ this.negative = negative;
543
+ define(this, "body", body);
544
+ define(this, "ignoreCase", ignoreCase);
545
+ define(this, "regexPrefix", prefix);
546
+ }
547
+ // Worked out on first use and kept behind an own property, the way `regex`
548
+ // caches itself in `_regex`. Deciding it in the constructor instead would
549
+ // add a fourth `defineProperty` to every rule ever built, which cost 4% of
550
+ // every compile -- including the compiles of rules that are never matched
551
+ // against anything.
552
+ get _basenameOnly() {
553
+ return define(this, "_basenameOnly", matchesBasename(this.body));
554
+ }
555
+ get regex() {
556
+ const key = UNDERSCORE + MODE_IGNORE;
557
+ if (this[key]) {
558
+ return this[key];
559
+ }
560
+ return this._make(MODE_IGNORE, key);
561
+ }
562
+ get checkRegex() {
563
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
564
+ if (this[key]) {
565
+ return this[key];
566
+ }
567
+ return this._make(MODE_CHECK_IGNORE, key);
568
+ }
569
+ _make(mode, key) {
570
+ const str = pinWildcards(
571
+ mode === MODE_IGNORE ? this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, replaceTrailingWildcard).replace(REGEX_REPLACE_TRAILING_DOUBLESTAR, replaceTrailingDoublestar) : checkSourceOf(this.body, this.regexPrefix)
572
+ );
573
+ const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
574
+ return define(this, key, regex);
575
+ }
576
+ };
577
+ var isLineEnd = /* @__PURE__ */ __name((char) => char === "\r" || char === "\n", "isLineEnd");
578
+ var trimEnd = /* @__PURE__ */ __name((body) => {
579
+ let end = body.length;
580
+ while (end && isLineEnd(body[end - 1])) {
581
+ end--;
582
+ }
583
+ const lineEnd = end;
584
+ while (end && body[end - 1] === SPACE) {
585
+ end--;
586
+ }
587
+ if (end === lineEnd) {
588
+ return body.slice(0, end);
589
+ }
590
+ let backslashes = 0;
591
+ while (backslashes < end && body[end - backslashes - 1] === ESCAPE) {
592
+ backslashes++;
593
+ }
594
+ return backslashes % 2 ? body.slice(0, end - 1) + SPACE : body.slice(0, end);
595
+ }, "trimEnd");
596
+ var createRule = /* @__PURE__ */ __name(({
597
+ pattern,
598
+ mark
599
+ }, ignoreCase) => {
600
+ let body = pattern[0] === BOM ? pattern.slice(1) : pattern;
601
+ if (body[0] === "#") {
602
+ return;
603
+ }
604
+ let negative = false;
605
+ if (body[0] === "!") {
606
+ negative = true;
607
+ body = body.slice(1);
608
+ }
609
+ const last = body[body.length - 1];
610
+ if (last === SPACE || last === "\r" || last === "\n") {
611
+ body = trimEnd(body);
612
+ }
613
+ if (!body) {
614
+ return;
615
+ }
616
+ body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
617
+ const regexPrefix = makeRegexPrefix(body);
618
+ return new IgnoreRule(
619
+ pattern,
620
+ mark,
621
+ body,
622
+ ignoreCase,
623
+ negative,
624
+ regexPrefix
625
+ );
626
+ }, "createRule");
627
+ var RuleManager = class {
628
+ static {
629
+ __name(this, "RuleManager");
630
+ }
631
+ constructor(ignoreCase) {
632
+ this._ignoreCase = ignoreCase;
633
+ this._rules = [];
634
+ this._basenameCount = 0;
635
+ }
636
+ _add(pattern) {
637
+ if (pattern && pattern[KEY_IGNORE]) {
638
+ this._rules = this._rules.concat(pattern._rules._rules);
639
+ this._basenameCount += pattern._rules._basenameCount;
640
+ this._added = true;
641
+ return;
642
+ }
643
+ if (isString(pattern)) {
644
+ pattern = {
645
+ pattern
646
+ };
647
+ }
648
+ const rule = checkPattern(pattern.pattern) && createRule(pattern, this._ignoreCase);
649
+ if (rule) {
650
+ this._added = true;
651
+ this._rules.push(rule);
652
+ if (matchesBasename(rule.body)) {
653
+ this._basenameCount++;
654
+ }
655
+ }
656
+ }
657
+ // @param {Array<string> | string | Ignore} pattern
658
+ add(pattern) {
659
+ this._added = false;
660
+ makeArray(
661
+ isString(pattern) ? splitPattern(pattern) : pattern
662
+ ).forEach(this._add, this);
663
+ if (this._added) {
664
+ this._literalRules = UNDEFINED;
665
+ }
666
+ return this._added;
667
+ }
668
+ // Match the literal 'abc/' for `checkIgnore`, last rule wins. Only a rule
669
+ // ending in a wildcard can match it (see `checkSourceOf`), so the rest
670
+ // are left out once, rather than tested or compiled for every path.
671
+ testLiteral(path) {
672
+ const rules = this._literalRules || (this._literalRules = this._rules.filter(
673
+ ({ body }) => body[body.length - (body[body.length - 1] === SLASH ? 2 : 1)] === "*"
674
+ ));
675
+ let ignored = false;
676
+ let unignored = false;
677
+ let matchedRule;
678
+ for (let index = rules.length - 1; index >= 0; index--) {
679
+ const rule = rules[index];
680
+ if (rule.checkRegex.test(path)) {
681
+ ignored = !rule.negative;
682
+ unignored = rule.negative;
683
+ matchedRule = rule.negative ? UNDEFINED : rule;
684
+ break;
685
+ }
686
+ }
687
+ const ret = {
688
+ ignored,
689
+ unignored
690
+ };
691
+ if (matchedRule) {
692
+ ret.rule = matchedRule;
693
+ }
694
+ return ret;
695
+ }
696
+ // Test one single path without recursively checking parent directories
697
+ //
698
+ // - checkUnignored `boolean` whether should check if the path is unignored,
699
+ // setting `checkUnignored` to `false` could reduce additional
700
+ // path matching.
701
+ // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
702
+ // @returns {TestResult} true if a file is ignored
703
+ test(path, checkUnignored, mode) {
704
+ let ignored = false;
705
+ let unignored = false;
706
+ let matchedRule;
707
+ const rules = this._rules;
708
+ const { length } = rules;
709
+ const shortcut = this._basenameCount * 2 >= length;
710
+ const basename3 = shortcut ? basenameOf(path) : path;
711
+ for (let index = 0; index < length; index++) {
712
+ const rule = rules[index];
713
+ const { negative } = rule;
714
+ const skip = unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored;
715
+ if (!skip && rule[mode].test(
716
+ shortcut && rule._basenameOnly ? basename3 : path
717
+ )) {
718
+ ignored = !negative;
719
+ unignored = negative;
720
+ matchedRule = negative ? UNDEFINED : rule;
721
+ }
722
+ }
723
+ const ret = {
724
+ ignored,
725
+ unignored
726
+ };
727
+ if (matchedRule) {
728
+ ret.rule = matchedRule;
729
+ }
730
+ return ret;
731
+ }
732
+ };
733
+ var throwError = /* @__PURE__ */ __name((message, Ctor) => {
734
+ throw new Ctor(message);
735
+ }, "throwError");
736
+ var checkPath = /* @__PURE__ */ __name((path, originalPath, doThrow) => {
737
+ if (!isString(path)) {
738
+ return doThrow(
739
+ `path must be a string, but got \`${originalPath}\``,
740
+ TypeError
741
+ );
742
+ }
743
+ if (!path) {
744
+ return doThrow(`path must not be empty`, TypeError);
745
+ }
746
+ if (checkPath.isNotRelative(path)) {
747
+ const r = "`path.relative()`d";
748
+ return doThrow(
749
+ `path should be a ${r} string, but got "${originalPath}"`,
750
+ RangeError
751
+ );
752
+ }
753
+ return true;
754
+ }, "checkPath");
755
+ var isNotRelative = /* @__PURE__ */ __name((path) => {
756
+ const first = path.charCodeAt(0);
757
+ if (first === SLASH_CODE) {
758
+ return true;
759
+ }
760
+ if (first !== DOT_CODE) {
761
+ return false;
762
+ }
763
+ if (path.length === 1) {
764
+ return true;
765
+ }
766
+ const second = path.charCodeAt(1);
767
+ if (second === SLASH_CODE) {
768
+ return true;
769
+ }
770
+ if (second !== DOT_CODE) {
771
+ return false;
772
+ }
773
+ return path.length === 2 || path.charCodeAt(2) === SLASH_CODE;
774
+ }, "isNotRelative");
775
+ checkPath.isNotRelative = isNotRelative;
776
+ checkPath.convert = (p) => p;
777
+ var Ignore = class {
778
+ static {
779
+ __name(this, "Ignore");
780
+ }
781
+ constructor({
782
+ ignorecase = true,
783
+ ignoreCase = ignorecase,
784
+ allowRelativePaths = false
785
+ } = {}) {
786
+ define(this, KEY_IGNORE, true);
787
+ this._rules = new RuleManager(ignoreCase);
788
+ this._strictPathCheck = !allowRelativePaths;
789
+ this._initCache();
790
+ }
791
+ _initCache() {
792
+ this._ignoreCache = /* @__PURE__ */ Object.create(null);
793
+ this._testCache = /* @__PURE__ */ Object.create(null);
794
+ }
795
+ add(pattern) {
796
+ if (this._rules.add(pattern)) {
797
+ this._initCache();
798
+ }
799
+ return this;
800
+ }
801
+ // legacy
802
+ addPattern(pattern) {
803
+ return this.add(pattern);
804
+ }
805
+ // @returns {TestResult}
806
+ _test(originalPath, cache, checkUnignored) {
807
+ const path = originalPath && checkPath.convert(originalPath);
808
+ checkPath(
809
+ path,
810
+ originalPath,
811
+ this._strictPathCheck ? throwError : RETURN_FALSE
812
+ );
813
+ return this._t(path, cache, checkUnignored);
814
+ }
815
+ checkIgnore(path) {
816
+ if (path.charCodeAt(path.length - 1) !== SLASH_CODE) {
817
+ return this.test(path);
818
+ }
819
+ const dir = this._t(path, this._testCache, true);
820
+ if (dir.ignored) {
821
+ return dir;
822
+ }
823
+ const literal = this._rules.testLiteral(path);
824
+ return literal.ignored || literal.unignored ? literal : dir;
825
+ }
826
+ _t(path, cache, checkUnignored) {
827
+ if (path in cache) {
828
+ return cache[path];
829
+ }
830
+ const parentPath = parentOf(path);
831
+ const parent = parentPath ? this._t(parentPath, cache, checkUnignored) : UNDEFINED;
832
+ return cache[path] = parent && parent.ignored ? parent : this._rules.test(path, checkUnignored, MODE_IGNORE);
833
+ }
834
+ ignores(path) {
835
+ return this._test(path, this._ignoreCache, false).ignored;
836
+ }
837
+ createFilter() {
838
+ return (path) => !this.ignores(path);
839
+ }
840
+ filter(paths) {
841
+ return makeArray(paths).filter(this.createFilter());
842
+ }
843
+ // @returns {TestResult}
844
+ test(path) {
845
+ return this._test(path, this._testCache, true);
846
+ }
847
+ };
848
+ var factory = /* @__PURE__ */ __name((options) => new Ignore(options), "factory");
849
+ var isPathValid = /* @__PURE__ */ __name((path) => checkPath(path && checkPath.convert(path), path, RETURN_FALSE), "isPathValid");
850
+ var setupWindows = /* @__PURE__ */ __name(() => {
851
+ const makePosix = /* @__PURE__ */ __name((str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/"), "makePosix");
852
+ checkPath.convert = makePosix;
853
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
854
+ checkPath.isNotRelative = (path) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path) || isNotRelative(path);
855
+ }, "setupWindows");
856
+ if (
857
+ // Detect `process` so that it can run in browsers.
858
+ typeof process !== "undefined" && process.platform === "win32"
859
+ ) {
860
+ setupWindows();
861
+ }
862
+ module.exports = factory;
863
+ factory.default = factory;
864
+ module.exports.isPathValid = isPathValid;
865
+ define(module.exports, /* @__PURE__ */ Symbol.for("setupWindows"), setupWindows);
866
+ }
867
+ });
868
+
13
869
  // ../analysis/dist/provider.js
14
- import { lstat as lstat4, realpath as realpath3, stat as stat3 } from "node:fs/promises";
870
+ import { lstat as lstat5, realpath as realpath3, stat as stat3 } from "node:fs/promises";
15
871
 
16
872
  // ../analysis/dist/context.js
17
873
  import { createHash as createHash3 } from "node:crypto";
18
- import { lstat as lstat3 } from "node:fs/promises";
19
- import { join as join4 } from "node:path";
874
+ import { join as join5 } from "node:path";
875
+
876
+ // ../analysis/dist/collect.js
877
+ var import_ignore = __toESM(require_ignore(), 1);
878
+ import { lstat as lstat3, readdir as readdir2 } from "node:fs/promises";
879
+ import { basename, extname, join as join4 } from "node:path";
880
+ import { setImmediate as nextTurn2 } from "node:timers/promises";
20
881
 
21
882
  // ../analysis/dist/fsafe.js
22
883
  import { constants } from "node:fs";
@@ -47,7 +908,7 @@ async function descriptorInside(rootReal, fd, path, opened) {
47
908
  }
48
909
  }
49
910
  __name(descriptorInside, "descriptorInside");
50
- async function readRegular(rootReal, abs) {
911
+ async function readRegular(rootReal, abs, limit) {
51
912
  let before;
52
913
  try {
53
914
  before = await lstat(abs);
@@ -74,7 +935,14 @@ async function readRegular(rootReal, abs) {
74
935
  }
75
936
  if (!await descriptorInside(rootReal, handle.fd, abs, opened))
76
937
  return { ok: false, why: "outside" };
77
- const buffer = await handle.readFile();
938
+ let buffer;
939
+ if (limit === void 0)
940
+ buffer = await handle.readFile();
941
+ else {
942
+ const chunk = Buffer.alloc(Math.min(limit, opened.size));
943
+ const { bytesRead } = await handle.read(chunk, 0, chunk.length, 0);
944
+ buffer = chunk.subarray(0, bytesRead);
945
+ }
78
946
  if (!isInside(rootReal, await realpath(abs)))
79
947
  return { ok: false, why: "outside" };
80
948
  return { ok: true, buffer, stat: opened };
@@ -109,13 +977,15 @@ async function conditionOf(rootReal, abs, recorded) {
109
977
  return s.size === recorded.size && s.mtimeMs === recorded.mtimeMs ? "same" : "changed";
110
978
  }
111
979
  __name(conditionOf, "conditionOf");
112
-
113
- // ../analysis/dist/indexer.js
114
- import { createHash as createHash2 } from "node:crypto";
115
- import { lstat as lstat2, readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
116
- import { join as join3, sep as sep3 } from "node:path";
117
- import { setImmediate as nextTurn } from "node:timers/promises";
118
- import { TextDecoder } from "node:util";
980
+ function toRel(root, abs) {
981
+ if (abs === root)
982
+ return "";
983
+ const prefix = root.endsWith(sep) ? root : root + sep;
984
+ if (!abs.startsWith(prefix))
985
+ return void 0;
986
+ return abs.slice(prefix.length).split(sep).join("/");
987
+ }
988
+ __name(toRel, "toRel");
119
989
 
120
990
  // ../analysis/dist/host.js
121
991
  import { fork } from "node:child_process";
@@ -288,7 +1158,12 @@ var ParserHost = class {
288
1158
  }
289
1159
  if (m.t === "done" && m.rel === job.rel) {
290
1160
  cleanup();
291
- resolve2({ kind: "rows", parseErrors: m.parseErrors, rows: m.rows });
1161
+ resolve2({
1162
+ kind: "rows",
1163
+ parseErrors: m.parseErrors,
1164
+ degraded: m.degraded,
1165
+ rows: m.rows
1166
+ });
292
1167
  } else if (m.t === "fail" && m.rel === job.rel) {
293
1168
  cleanup();
294
1169
  if (m.unavailable)
@@ -363,6 +1238,13 @@ function abortError() {
363
1238
  }
364
1239
  __name(abortError, "abortError");
365
1240
 
1241
+ // ../analysis/dist/indexer.js
1242
+ import { createHash as createHash2 } from "node:crypto";
1243
+ import { lstat as lstat2, realpath as realpath2 } from "node:fs/promises";
1244
+ import { join as join3 } from "node:path";
1245
+ import { setImmediate as nextTurn } from "node:timers/promises";
1246
+ import { TextDecoder } from "node:util";
1247
+
366
1248
  // ../analysis/dist/lines.js
367
1249
  function lineStarts(text) {
368
1250
  let count = 1;
@@ -479,7 +1361,7 @@ async function evictCaches(cacheDir, keep, policy, now = Date.now()) {
479
1361
  __name(evictCaches, "evictCaches");
480
1362
 
481
1363
  // ../analysis/dist/store.js
482
- var SCHEMA_VERSION = 1;
1364
+ var SCHEMA_VERSION = 3;
483
1365
  var sqlite;
484
1366
  async function loadSqlite() {
485
1367
  sqlite ??= import("node:sqlite").catch(() => void 0);
@@ -491,17 +1373,23 @@ CREATE TABLE IF NOT EXISTS meta(key TEXT PRIMARY KEY, value TEXT NOT NULL);
491
1373
  CREATE TABLE IF NOT EXISTS files(
492
1374
  id INTEGER PRIMARY KEY, path TEXT NOT NULL UNIQUE, chars INTEGER NOT NULL, lang TEXT NOT NULL,
493
1375
  parse_errors INTEGER NOT NULL, line_starts BLOB NOT NULL, size INTEGER NOT NULL,
494
- mtime_ms REAL NOT NULL, hash TEXT NOT NULL);
1376
+ mtime_ms REAL NOT NULL, hash TEXT NOT NULL, degraded INTEGER NOT NULL DEFAULT 0);
495
1377
  CREATE TABLE IF NOT EXISTS dirs(path TEXT PRIMARY KEY, mtime_ms REAL NOT NULL);
1378
+ CREATE TABLE IF NOT EXISTS excl(
1379
+ path TEXT NOT NULL, kind TEXT NOT NULL, name TEXT NOT NULL, n INTEGER NOT NULL,
1380
+ PRIMARY KEY(path, kind, name));
496
1381
  CREATE TABLE IF NOT EXISTS functions(
497
1382
  id INTEGER PRIMARY KEY, file_id INTEGER NOT NULL, parent_id INTEGER, kind TEXT NOT NULL, name TEXT,
498
- start INTEGER NOT NULL, "end" INTEGER NOT NULL, sline INTEGER NOT NULL, eline INTEGER NOT NULL);
1383
+ start INTEGER NOT NULL, "end" INTEGER NOT NULL, sline INTEGER NOT NULL, eline INTEGER NOT NULL,
1384
+ qname TEXT);
1385
+ CREATE TABLE IF NOT EXISTS classes(
1386
+ file_id INTEGER NOT NULL, name TEXT, start INTEGER NOT NULL, "end" INTEGER NOT NULL);
499
1387
  CREATE TABLE IF NOT EXISTS strings(
500
1388
  id INTEGER PRIMARY KEY, file_id INTEGER NOT NULL, fn_id INTEGER, start INTEGER NOT NULL,
501
- "end" INTEGER NOT NULL, kind TEXT NOT NULL, value TEXT NOT NULL);
1389
+ "end" INTEGER NOT NULL, kind TEXT NOT NULL, value TEXT NOT NULL, cut INTEGER NOT NULL DEFAULT 0);
502
1390
  CREATE TABLE IF NOT EXISTS calls(
503
1391
  file_id INTEGER NOT NULL, fn_id INTEGER, start INTEGER NOT NULL, "end" INTEGER NOT NULL,
504
- callee TEXT NOT NULL, kind TEXT NOT NULL, nargs INTEGER NOT NULL);
1392
+ callee TEXT NOT NULL, kind TEXT NOT NULL, nargs INTEGER NOT NULL, owner TEXT, unres INTEGER NOT NULL DEFAULT 0);
505
1393
  CREATE TABLE IF NOT EXISTS imports(
506
1394
  file_id INTEGER NOT NULL, kind TEXT NOT NULL, source TEXT NOT NULL, names TEXT NOT NULL, start INTEGER NOT NULL);
507
1395
  CREATE TABLE IF NOT EXISTS exports(
@@ -510,6 +1398,10 @@ CREATE TABLE IF NOT EXISTS exports(
510
1398
  var SECONDARY_INDEXES = `
511
1399
  CREATE INDEX IF NOT EXISTS fn_file_start ON functions(file_id, start);
512
1400
  CREATE INDEX IF NOT EXISTS fn_name ON functions(name);
1401
+ CREATE INDEX IF NOT EXISTS fn_qname ON functions(qname) WHERE qname IS NOT NULL;
1402
+ CREATE INDEX IF NOT EXISTS class_file ON classes(file_id, start);
1403
+ CREATE INDEX IF NOT EXISTS str_cut ON strings(file_id) WHERE cut > 0;
1404
+ CREATE INDEX IF NOT EXISTS call_unres ON calls(file_id) WHERE unres = 1;
513
1405
  CREATE INDEX IF NOT EXISTS str_fn ON strings(fn_id);
514
1406
  CREATE INDEX IF NOT EXISTS str_file ON strings(file_id, start);
515
1407
  CREATE INDEX IF NOT EXISTS call_callee ON calls(callee);
@@ -699,9 +1591,24 @@ var Store = class _Store {
699
1591
  this.db.exec(SECONDARY_INDEXES);
700
1592
  }
701
1593
  /** Every stored file at or under `scope` (a relative path; empty is all), keyed by path. */
702
- storedFiles(scope) {
1594
+ /**
1595
+ * The files recorded at or under `scope`. With `shallow`, only the scope
1596
+ * itself and its direct children, plus everything under the `vanished`
1597
+ * subdirectories.
1598
+ */
1599
+ storedFiles(scope, only) {
703
1600
  const map = /* @__PURE__ */ new Map();
704
- const rows = scope === "" ? this.all("SELECT id, path, size, mtime_ms, hash FROM files") : this.all("SELECT id, path, size, mtime_ms, hash FROM files WHERE path = ? OR (path >= ? AND path < ?)", scope, `${scope}/`, `${scope}0`);
1601
+ const select = "SELECT id, path, size, mtime_ms, hash FROM files";
1602
+ const rows = [];
1603
+ if (only) {
1604
+ const prefix = scope === "" ? "" : `${scope}/`;
1605
+ rows.push(...this.all(`${select} WHERE path = ? OR (path >= ? AND path < ? AND instr(substr(path, ?), '/') = 0)`, scope, prefix, scope === "" ? "\uFFFF" : `${scope}0`, Array.from(prefix).length + 1));
1606
+ for (const v of only.vanished) {
1607
+ rows.push(...this.all(`${select} WHERE path >= ? AND path < ?`, `${v}/`, `${v}0`));
1608
+ }
1609
+ } else {
1610
+ rows.push(...scope === "" ? this.all(select) : this.all(`${select} WHERE path = ? OR (path >= ? AND path < ?)`, scope, `${scope}/`, `${scope}0`));
1611
+ }
705
1612
  for (const r of rows) {
706
1613
  map.set(String(r.path), {
707
1614
  id: Number(r.id),
@@ -712,12 +1619,23 @@ var Store = class _Store {
712
1619
  }
713
1620
  return map;
714
1621
  }
1622
+ /** Recorded directories directly below `scope`. */
1623
+ childDirs(scope) {
1624
+ const prefix = scope === "" ? "" : `${scope}/`;
1625
+ return this.all("SELECT path FROM dirs WHERE path >= ? AND path < ? AND path != '' AND instr(substr(path, ?), '/') = 0", prefix, scope === "" ? "\uFFFF" : `${scope}0`, Array.from(prefix).length + 1).map((r) => String(r.path));
1626
+ }
1627
+ /** Forget a directory and everything recorded below it about what its walk saw. */
1628
+ dropDirectoryRows(rel) {
1629
+ for (const table of ["dirs", "excl"]) {
1630
+ this.prepare(`DELETE FROM ${table} WHERE path = ? OR (path >= ? AND path < ?)`).run(rel, `${rel}/`, `${rel}0`);
1631
+ }
1632
+ }
715
1633
  /** Remove a file and every row that hangs off it. */
716
1634
  removeFile(fileId) {
717
1635
  if (this.fts) {
718
1636
  this.prepare("INSERT INTO lit(lit, rowid, value) SELECT 'delete', id, value FROM strings WHERE file_id = ? AND length(value) >= 3").run(fileId);
719
1637
  }
720
- for (const table of ["strings", "calls", "functions", "imports", "exports"]) {
1638
+ for (const table of ["strings", "calls", "functions", "classes", "imports", "exports"]) {
721
1639
  this.prepare(`DELETE FROM ${table} WHERE file_id = ?`).run(fileId);
722
1640
  }
723
1641
  this.prepare("DELETE FROM files WHERE id = ?").run(fileId);
@@ -753,23 +1671,28 @@ var Store = class _Store {
753
1671
  }
754
1672
  return lo + 1;
755
1673
  }, "lineOf");
756
- const result = this.prepare("INSERT INTO files(path, chars, lang, parse_errors, line_starts, size, mtime_ms, hash) VALUES(?,?,?,?,?,?,?,?)").run(record.path, record.chars, record.lang, record.parseErrors, encodeLineStarts(lineStarts2), record.size, record.mtimeMs, record.hash);
1674
+ const result = this.prepare("INSERT INTO files(path, chars, lang, parse_errors, line_starts, size, mtime_ms, hash, degraded) VALUES(?,?,?,?,?,?,?,?,?)").run(record.path, record.chars, record.lang, record.parseErrors, encodeLineStarts(lineStarts2), record.size, record.mtimeMs, record.hash, record.degraded);
757
1675
  const id = Number(result.lastInsertRowid);
758
1676
  const remap = /* @__PURE__ */ __name((local) => local === null ? null : base + local, "remap");
759
- const insFn = this.prepare("INSERT INTO functions VALUES(?,?,?,?,?,?,?,?,?)");
1677
+ const insFn = this.prepare("INSERT INTO functions VALUES(?,?,?,?,?,?,?,?,?,?)");
760
1678
  for (const f of rows.functions) {
761
- insFn.run(base + f.id, id, remap(f.parentId), f.kind, f.name, f.start, f.end, lineOf(f.start), lineOf(f.end));
1679
+ insFn.run(base + f.id, id, remap(f.parentId), f.kind, f.name, f.start, f.end, lineOf(f.start), lineOf(f.end), f.qname !== null && f.qname !== f.name ? f.qname : null);
762
1680
  }
763
- const insStr = this.prepare('INSERT INTO strings(file_id, fn_id, start, "end", kind, value) VALUES(?,?,?,?,?,?)');
1681
+ const insClass = this.prepare("INSERT INTO classes VALUES(?,?,?,?)");
1682
+ for (const c of rows.classes)
1683
+ insClass.run(id, c.name, c.start, c.end);
1684
+ const insStr = this.prepare('INSERT INTO strings(file_id, fn_id, start, "end", kind, value, cut) VALUES(?,?,?,?,?,?,?)');
764
1685
  const insLit = this.fts ? this.prepare("INSERT INTO lit(rowid, value) VALUES(?, ?)") : void 0;
765
1686
  for (const s of rows.strings) {
766
- const r = insStr.run(id, remap(s.fnId), s.start, s.end, s.kind, s.value);
1687
+ const r = insStr.run(id, remap(s.fnId), s.start, s.end, s.kind, s.value, s.cut);
767
1688
  if (insLit && s.value.length >= 3)
768
1689
  insLit.run(Number(r.lastInsertRowid), s.value);
769
1690
  }
770
- const insCall = this.prepare("INSERT INTO calls VALUES(?,?,?,?,?,?,?)");
771
- for (const c of rows.calls)
772
- insCall.run(id, remap(c.fnId), c.start, c.end, c.callee, c.kind, c.nargs);
1691
+ const insCall = this.prepare("INSERT INTO calls VALUES(?,?,?,?,?,?,?,?,?)");
1692
+ for (const c of rows.calls) {
1693
+ const unresolved = c.callee === "?" || c.callee.endsWith("[]") ? 1 : 0;
1694
+ insCall.run(id, remap(c.fnId), c.start, c.end, c.callee, c.kind, c.nargs, c.owner, unresolved);
1695
+ }
773
1696
  const insImp = this.prepare("INSERT INTO imports VALUES(?,?,?,?,?)");
774
1697
  for (const i of rows.imports)
775
1698
  insImp.run(id, i.kind, i.source, i.names, i.start);
@@ -817,7 +1740,11 @@ var DEFAULT_IGNORED_DIRS = [
817
1740
  ".namzu",
818
1741
  ".turbo",
819
1742
  ".cache",
820
- "coverage"
1743
+ "coverage",
1744
+ "dist",
1745
+ "build",
1746
+ "out",
1747
+ ".next"
821
1748
  ];
822
1749
  var DEFAULT_MAX_FILE_BYTES = 32 * 1024 * 1024;
823
1750
  var DEFAULT_MAX_FILES = 15e4;
@@ -826,6 +1753,26 @@ var DEFAULT_MAX_MILLIS = 45e3;
826
1753
  var SLICE_MS = 20;
827
1754
  var NAMED_LIMIT = 20;
828
1755
  var decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
1756
+ function truncationOf(limits, o) {
1757
+ if (limits.size === 0)
1758
+ return void 0;
1759
+ const order = ["dirs", "files", "time"];
1760
+ const kinds = order.filter((l) => limits.has(l));
1761
+ const words = kinds.map((l) => l === "dirs" ? `after walking ${o.maxDirectories.toLocaleString("en-US")} directories` : l === "files" ? `at the ${o.maxFiles.toLocaleString("en-US")}-file limit` : `after ${Math.round(o.maxMillis / 1e3)} seconds`);
1762
+ return { text: `stopped ${words.join(" and ")}`, limits: kinds };
1763
+ }
1764
+ __name(truncationOf, "truncationOf");
1765
+ function nextStep(limits) {
1766
+ const time = limits?.includes("time") ?? false;
1767
+ const reach = (limits ?? []).some((l) => l === "dirs" || l === "files");
1768
+ if (time && reach) {
1769
+ return "Call the index operation again to continue where the time ran out, and index a narrower path to reach what the directory or file limit cut off";
1770
+ }
1771
+ if (time)
1772
+ return "Call the index operation again to continue where it stopped";
1773
+ return "Call the index operation with a narrower path to cover the rest";
1774
+ }
1775
+ __name(nextStep, "nextStep");
829
1776
  function decodeText(buffer) {
830
1777
  const head = Math.min(buffer.length, 8192);
831
1778
  for (let i = 0; i < head; i++)
@@ -842,107 +1789,11 @@ function hashOf(buffer) {
842
1789
  return createHash2("sha1").update(buffer).digest("hex");
843
1790
  }
844
1791
  __name(hashOf, "hashOf");
845
- function toRel(root, abs) {
846
- if (abs === root)
847
- return "";
848
- const prefix = root.endsWith(sep3) ? root : root + sep3;
849
- if (!abs.startsWith(prefix))
850
- return void 0;
851
- return abs.slice(prefix.length).split(sep3).join("/");
852
- }
853
- __name(toRel, "toRel");
854
1792
  function checkAbort(signal) {
855
1793
  if (signal?.aborted)
856
1794
  throw abortError();
857
1795
  }
858
1796
  __name(checkAbort, "checkAbort");
859
- function overTime(b) {
860
- return performance.now() - b.started > b.options.maxMillis;
861
- }
862
- __name(overTime, "overTime");
863
- async function collect(root, start, b, skip) {
864
- const walk = { files: [], dirs: [], truncated: void 0 };
865
- const ignored = new Set(b.options.ignoreDirs);
866
- let first;
867
- try {
868
- first = await lstat2(start);
869
- } catch {
870
- return walk;
871
- }
872
- const startRel = toRel(root, start) ?? "";
873
- if (first.isSymbolicLink()) {
874
- skip("symbolic link");
875
- return walk;
876
- }
877
- if (first.isFile()) {
878
- if (languageOf(start) !== void 0 && !isDeclarationFile(start))
879
- walk.files.push({ rel: startRel, abs: start });
880
- return walk;
881
- }
882
- if (!first.isDirectory())
883
- return walk;
884
- const pending = [{ abs: start, rel: startRel }];
885
- let lastYield = performance.now();
886
- let visited = 0;
887
- while (pending.length > 0) {
888
- checkAbort(b.signal);
889
- if (visited >= b.options.maxDirectories) {
890
- walk.truncated = `stopped after walking ${visited.toLocaleString("en-US")} directories`;
891
- break;
892
- }
893
- if (overTime(b)) {
894
- walk.truncated = `stopped after ${Math.round(b.options.maxMillis / 1e3)} seconds`;
895
- break;
896
- }
897
- const dir = pending.pop();
898
- visited++;
899
- let entries;
900
- try {
901
- entries = await readdir2(dir.abs, { withFileTypes: true });
902
- walk.dirs.push({ rel: dir.rel, mtimeMs: (await lstat2(dir.abs)).mtimeMs });
903
- } catch {
904
- skip("unreadable directory");
905
- continue;
906
- }
907
- entries.sort((x, y) => x.name < y.name ? -1 : x.name > y.name ? 1 : 0);
908
- const subdirs = [];
909
- for (const entry of entries) {
910
- const rel = dir.rel === "" ? entry.name : `${dir.rel}/${entry.name}`;
911
- if (entry.isSymbolicLink()) {
912
- if (languageOf(entry.name) !== void 0)
913
- skip("symbolic link");
914
- continue;
915
- }
916
- if (entry.isDirectory()) {
917
- if (!ignored.has(entry.name))
918
- subdirs.push({ abs: join3(dir.abs, entry.name), rel });
919
- continue;
920
- }
921
- if (!entry.isFile() || languageOf(entry.name) === void 0)
922
- continue;
923
- if (isDeclarationFile(entry.name)) {
924
- skip("declaration file");
925
- continue;
926
- }
927
- if (walk.files.length >= b.options.maxFiles) {
928
- walk.truncated = `stopped at the ${b.options.maxFiles.toLocaleString("en-US")}-file limit`;
929
- break;
930
- }
931
- walk.files.push({ rel, abs: join3(dir.abs, entry.name) });
932
- }
933
- for (let i = subdirs.length - 1; i >= 0; i--)
934
- pending.push(subdirs[i]);
935
- if (walk.truncated)
936
- break;
937
- if (performance.now() - lastYield > SLICE_MS) {
938
- await nextTurn();
939
- lastYield = performance.now();
940
- }
941
- }
942
- walk.files.sort((x, y) => x.rel < y.rel ? -1 : x.rel > y.rel ? 1 : 0);
943
- return walk;
944
- }
945
- __name(collect, "collect");
946
1797
  function jsonList(store, key) {
947
1798
  try {
948
1799
  const parsed = JSON.parse(store.meta(key) ?? "[]");
@@ -980,9 +1831,11 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
980
1831
  }
981
1832
  } catch {
982
1833
  }
983
- const walk = await collect(root, scopeAbs, budget, skip);
984
- let truncated = walk.truncated;
985
- const stored = store.storedFiles(scopeRel);
1834
+ const shallow = options.shallow === true;
1835
+ const walk = await collect(root, scopeAbs, budget, skip, shallow ? new Set(store.childDirs(scopeRel)) : void 0);
1836
+ const limits = new Set(walk.limits);
1837
+ const truncatedNow = /* @__PURE__ */ __name(() => truncationOf(limits, options), "truncatedNow");
1838
+ const stored = shallow ? store.storedFiles(scopeRel, { shallow: true, vanished: walk.vanished }) : store.storedFiles(scopeRel);
986
1839
  const seen = new Set(walk.files.map((f) => f.rel));
987
1840
  let parsed = 0;
988
1841
  let unchanged = 0;
@@ -1031,8 +1884,8 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
1031
1884
  queue(() => store.setMeta("violations", "[]"));
1032
1885
  for (const candidate of walk.files) {
1033
1886
  checkAbort(signal);
1034
- if (overTime(budget)) {
1035
- truncated ??= `stopped after ${Math.round(options.maxMillis / 1e3)} seconds`;
1887
+ if (performance.now() - budget.started > options.maxMillis) {
1888
+ limits.add("time");
1036
1889
  break;
1037
1890
  }
1038
1891
  const before = stored.get(candidate.rel);
@@ -1097,18 +1950,23 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
1097
1950
  if (result.kind === "rows") {
1098
1951
  const rowCount = result.rows.strings.length + result.rows.calls.length + result.rows.functions.length;
1099
1952
  queue(() => {
1100
- store.writeFile({ ...base, parseErrors: result.parseErrors, rows: result.rows });
1953
+ store.writeFile({
1954
+ ...base,
1955
+ parseErrors: result.parseErrors,
1956
+ degraded: result.degraded,
1957
+ rows: result.rows
1958
+ });
1101
1959
  unnote(store, "crashed", candidate.rel);
1102
1960
  }, rowCount);
1103
1961
  parsed++;
1104
1962
  } else if (result.kind === "crash") {
1105
1963
  queue(() => {
1106
- store.writeFile({ ...base, parseErrors: CRASHED, rows: EMPTY_ROWS });
1964
+ store.writeFile({ ...base, parseErrors: CRASHED, degraded: 0, rows: EMPTY_ROWS });
1107
1965
  noteNamed(store, "crashed", candidate.rel);
1108
1966
  });
1109
1967
  skip("parser crashed");
1110
1968
  } else {
1111
- queue(() => store.writeFile({ ...base, parseErrors: 1, rows: EMPTY_ROWS }));
1969
+ queue(() => store.writeFile({ ...base, parseErrors: 1, degraded: 0, rows: EMPTY_ROWS }));
1112
1970
  skip("parser failure");
1113
1971
  }
1114
1972
  changed = true;
@@ -1119,7 +1977,7 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
1119
1977
  lastYield = performance.now();
1120
1978
  }
1121
1979
  }
1122
- if (!walk.truncated) {
1980
+ if (walk.limits.size === 0) {
1123
1981
  for (const [path, file] of stored) {
1124
1982
  if (seen.has(path))
1125
1983
  continue;
@@ -1134,16 +1992,30 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
1134
1992
  }
1135
1993
  }
1136
1994
  queue(() => {
1137
- if (!walk.truncated)
1138
- recordDirs(store, scopeRel, walk.dirs);
1995
+ if (shallow) {
1996
+ if (walk.limits.size === 0) {
1997
+ for (const v of walk.vanished)
1998
+ store.dropDirectoryRows(v);
1999
+ recordDirs(store, scopeRel, walk.dirs, true);
2000
+ }
2001
+ recordExcluded(store, scopeRel, false, walk.dirs, walk.excluded);
2002
+ } else {
2003
+ if (walk.limits.size === 0)
2004
+ recordDirs(store, scopeRel, walk.dirs);
2005
+ recordExcluded(store, scopeRel, walk.limits.size === 0, walk.dirs, walk.excluded);
2006
+ }
1139
2007
  store.ensureIndexes();
1140
- recordCoverage(store, scopeRel, skippedReasons, truncated);
2008
+ if (options.quiet !== true)
2009
+ recordCoverage(store, scopeRel, skippedReasons, truncatedNow());
1141
2010
  });
1142
2011
  await flush();
1143
2012
  } catch (err) {
1144
2013
  if (err instanceof Error && err.name === "AbortError") {
1145
2014
  try {
1146
- queue(() => recordCoverage(store, scopeRel, skippedReasons, "was cancelled before it finished", true));
2015
+ queue(() => {
2016
+ if (options.quiet !== true)
2017
+ recordCoverage(store, scopeRel, skippedReasons, "was cancelled before it finished", true);
2018
+ });
1147
2019
  dirty = true;
1148
2020
  await flush();
1149
2021
  } catch {
@@ -1154,11 +2026,29 @@ async function refreshIndex(store, root, scopeAbs, options, host, signal) {
1154
2026
  }
1155
2027
  throw err;
1156
2028
  }
1157
- return outcomeOf(store, skippedReasons, parsed, unchanged, removed, changed, truncated);
2029
+ return outcomeOf(store, skippedReasons, parsed, unchanged, removed, changed, truncatedNow());
1158
2030
  }
1159
2031
  __name(refreshIndex, "refreshIndex");
1160
- function recordDirs(store, scopeRel, dirs) {
1161
- if (scopeRel === "")
2032
+ function recordExcluded(store, scopeRel, finished, visited, rows) {
2033
+ if (finished) {
2034
+ if (scopeRel === "")
2035
+ store.exec("DELETE FROM excl");
2036
+ else
2037
+ store.prepare("DELETE FROM excl WHERE path = ? OR (path >= ? AND path < ?)").run(scopeRel, `${scopeRel}/`, `${scopeRel}0`);
2038
+ } else {
2039
+ const del = store.prepare("DELETE FROM excl WHERE path = ?");
2040
+ for (const d of visited)
2041
+ del.run(d.rel);
2042
+ }
2043
+ const ins = store.prepare("INSERT OR REPLACE INTO excl(path, kind, name, n) VALUES(?, ?, ?, ?)");
2044
+ for (const r of rows)
2045
+ ins.run(r.path, r.kind, r.name, r.n);
2046
+ }
2047
+ __name(recordExcluded, "recordExcluded");
2048
+ function recordDirs(store, scopeRel, dirs, shallow = false) {
2049
+ if (shallow)
2050
+ store.prepare("DELETE FROM dirs WHERE path = ?").run(scopeRel);
2051
+ else if (scopeRel === "")
1162
2052
  store.exec("DELETE FROM dirs");
1163
2053
  else
1164
2054
  store.prepare("DELETE FROM dirs WHERE path = ? OR (path >= ? AND path < ?)").run(scopeRel, `${scopeRel}/`, `${scopeRel}0`);
@@ -1178,7 +2068,7 @@ function outcomeOf(store, skippedReasons, parsed, unchanged, removed, changed, t
1178
2068
  withParseErrors: Number(counts.bad),
1179
2069
  indexed: Number(counts.indexed),
1180
2070
  changed,
1181
- ...truncated ? { truncated } : {}
2071
+ ...truncated ? { truncated: truncated.text, limits: truncated.limits } : {}
1182
2072
  };
1183
2073
  }
1184
2074
  __name(outcomeOf, "outcomeOf");
@@ -1204,10 +2094,12 @@ function coveringEntry(covered, scopeRel) {
1204
2094
  }
1205
2095
  __name(coveringEntry, "coveringEntry");
1206
2096
  function recordCoverage(store, scopeRel, skipped, truncated, cancelled = false) {
2097
+ const text = typeof truncated === "string" ? truncated : truncated?.text;
1207
2098
  const mine = {
1208
2099
  s: scopeRel,
1209
2100
  c: truncated ? 0 : 1,
1210
- ...truncated ? { r: truncated } : {},
2101
+ ...text ? { r: text } : {},
2102
+ ...typeof truncated === "object" ? { w: truncated.limits } : {},
1211
2103
  ...cancelled ? { k: "cancel" } : {}
1212
2104
  };
1213
2105
  let covered = readCovered(store);
@@ -1231,9 +2123,271 @@ function recordCoverage(store, scopeRel, skipped, truncated, cancelled = false)
1231
2123
  }
1232
2124
  __name(recordCoverage, "recordCoverage");
1233
2125
 
2126
+ // ../analysis/dist/collect.js
2127
+ var UNINDEXED_CODE_EXTENSIONS = /* @__PURE__ */ new Set([
2128
+ ".es",
2129
+ ".es5",
2130
+ ".es6",
2131
+ ".jsm",
2132
+ ".html",
2133
+ ".htm",
2134
+ ".vue",
2135
+ ".svelte",
2136
+ ".astro",
2137
+ ".coffee"
2138
+ ]);
2139
+ var MAY_HOLD_JS = UNINDEXED_CODE_EXTENSIONS;
2140
+ var BUILD_OUTPUT_NAMES = /* @__PURE__ */ new Set(["dist", "build", "out"]);
2141
+ function isDefaultList(list) {
2142
+ return list.length === DEFAULT_IGNORED_DIRS.length && list.every((n, i) => n === DEFAULT_IGNORED_DIRS[i]);
2143
+ }
2144
+ __name(isDefaultList, "isDefaultList");
2145
+ var NEVER_SOURCE_DIRS = /* @__PURE__ */ new Set([
2146
+ "node_modules",
2147
+ ".git",
2148
+ ".hg",
2149
+ ".svn",
2150
+ ".namzu"
2151
+ ]);
2152
+ var SHEBANG_BYTES = 256;
2153
+ var MAX_GITIGNORE_BYTES = 1024 * 1024;
2154
+ var MAX_PATTERN_CHARS = 4096;
2155
+ var MAX_CHECKED_LINES = 5e3;
2156
+ var SLICE_MS2 = 20;
2157
+ var NODE_SHEBANG = /^#!\s*(?:\S*\/)?(?:env\s+(?:-\S+\s+)*)?(?:node|nodejs|bun|deno)(?:\s|$)/;
2158
+ function hasNodeShebang(head) {
2159
+ if (head.length < 3 || head[0] !== 35 || head[1] !== 33)
2160
+ return false;
2161
+ const text = Buffer.from(head).toString("latin1");
2162
+ const line = text.split(/\r?\n/, 1)[0] ?? "";
2163
+ return NODE_SHEBANG.test(line);
2164
+ }
2165
+ __name(hasNodeShebang, "hasNodeShebang");
2166
+ function isExtensionless(name) {
2167
+ return !name.slice(1).includes(".");
2168
+ }
2169
+ __name(isExtensionless, "isExtensionless");
2170
+ async function shebangOf(root, abs) {
2171
+ const read = await readRegular(root, abs, SHEBANG_BYTES);
2172
+ return read.ok && hasNodeShebang(read.buffer);
2173
+ }
2174
+ __name(shebangOf, "shebangOf");
2175
+ async function loadGitignore(root, abs, base) {
2176
+ const read = await readRegular(root, join4(abs, ".gitignore"));
2177
+ if (!read.ok || read.buffer.length > MAX_GITIGNORE_BYTES)
2178
+ return void 0;
2179
+ const text = read.buffer.toString("utf8");
2180
+ const lines = text.split(/\r?\n/);
2181
+ try {
2182
+ if (lines.length > MAX_CHECKED_LINES)
2183
+ return { base, ig: (0, import_ignore.default)().add(text) };
2184
+ const kept = lines.filter((line) => {
2185
+ if (line.length > MAX_PATTERN_CHARS)
2186
+ return false;
2187
+ try {
2188
+ const probe = (0, import_ignore.default)().add(line);
2189
+ probe.test("probe/path.js");
2190
+ probe.test("probe/dir/");
2191
+ return true;
2192
+ } catch {
2193
+ return false;
2194
+ }
2195
+ });
2196
+ return { base, ig: (0, import_ignore.default)().add(kept.join("\n")) };
2197
+ } catch {
2198
+ return void 0;
2199
+ }
2200
+ }
2201
+ __name(loadGitignore, "loadGitignore");
2202
+ function gitIgnored(rules, rel, isDir) {
2203
+ let ignored = false;
2204
+ for (const { base, ig } of rules) {
2205
+ const within = base === "" ? rel : rel.startsWith(`${base}/`) ? rel.slice(base.length + 1) : void 0;
2206
+ if (within === void 0 || within === "")
2207
+ continue;
2208
+ let verdict;
2209
+ try {
2210
+ verdict = ig.test(isDir ? `${within}/` : within);
2211
+ } catch {
2212
+ continue;
2213
+ }
2214
+ if (verdict.unignored)
2215
+ ignored = false;
2216
+ else if (verdict.ignored)
2217
+ ignored = true;
2218
+ }
2219
+ return ignored;
2220
+ }
2221
+ __name(gitIgnored, "gitIgnored");
2222
+ function ancestors(rel) {
2223
+ if (rel === "")
2224
+ return [""];
2225
+ const parts = rel.split("/");
2226
+ const out = [""];
2227
+ for (let i = 1; i < parts.length; i++)
2228
+ out.push(parts.slice(0, i).join("/"));
2229
+ return out;
2230
+ }
2231
+ __name(ancestors, "ancestors");
2232
+ async function collect(root, start, b, skip, known) {
2233
+ const walk = { files: [], dirs: [], limits: /* @__PURE__ */ new Set(), excluded: [], vanished: [] };
2234
+ const ignored = new Set(b.options.ignoreDirs);
2235
+ const conditional = isDefaultList(b.options.ignoreDirs);
2236
+ const useGit = b.options.respectGitignore !== false;
2237
+ const abortIfAsked = /* @__PURE__ */ __name(() => {
2238
+ if (b.signal?.aborted)
2239
+ throw abortError();
2240
+ }, "abortIfAsked");
2241
+ let first;
2242
+ try {
2243
+ first = await lstat3(start);
2244
+ } catch {
2245
+ return walk;
2246
+ }
2247
+ const startRel = toRel(root, start) ?? "";
2248
+ if (first.isSymbolicLink()) {
2249
+ skip("symbolic link");
2250
+ return walk;
2251
+ }
2252
+ if (first.isFile()) {
2253
+ if (languageOf(start) !== void 0) {
2254
+ if (!isDeclarationFile(start))
2255
+ walk.files.push({ rel: startRel, abs: start });
2256
+ } else if (isExtensionless(basename(start)) && await shebangOf(root, start)) {
2257
+ walk.files.push({ rel: startRel, abs: start });
2258
+ }
2259
+ return walk;
2260
+ }
2261
+ if (!first.isDirectory())
2262
+ return walk;
2263
+ const inherited = [];
2264
+ if (useGit) {
2265
+ for (const dir of ancestors(startRel)) {
2266
+ if (dir === startRel)
2267
+ break;
2268
+ const rules = await loadGitignore(root, dir === "" ? root : join4(root, ...dir.split("/")), dir);
2269
+ if (rules)
2270
+ inherited.push(rules);
2271
+ }
2272
+ }
2273
+ if (inherited.length > 0 && gitIgnored(inherited, startRel, true))
2274
+ inherited.length = 0;
2275
+ const pending = [{ abs: start, rel: startRel, rules: inherited }];
2276
+ let lastYield = performance.now();
2277
+ let visited = 0;
2278
+ const tally2 = /* @__PURE__ */ new Map();
2279
+ const note = /* @__PURE__ */ __name((path, kind, name) => {
2280
+ const key = `${path}\0${kind}\0${name}`;
2281
+ const row = tally2.get(key);
2282
+ tally2.set(key, { path, kind, name, n: (row?.n ?? 0) + 1 });
2283
+ }, "note");
2284
+ while (pending.length > 0) {
2285
+ abortIfAsked();
2286
+ if (visited >= b.options.maxDirectories) {
2287
+ walk.limits.add("dirs");
2288
+ break;
2289
+ }
2290
+ if (performance.now() - b.started > b.options.maxMillis) {
2291
+ walk.limits.add("time");
2292
+ break;
2293
+ }
2294
+ const dir = pending.pop();
2295
+ visited++;
2296
+ let entries;
2297
+ try {
2298
+ const mtimeMs = (await lstat3(dir.abs)).mtimeMs;
2299
+ entries = await readdir2(dir.abs, { withFileTypes: true });
2300
+ walk.dirs.push({ rel: dir.rel, mtimeMs });
2301
+ } catch {
2302
+ skip("unreadable directory");
2303
+ continue;
2304
+ }
2305
+ entries.sort((x, y) => x.name < y.name ? -1 : x.name > y.name ? 1 : 0);
2306
+ let rules = dir.rules;
2307
+ if (useGit && entries.some((e) => e.name === ".gitignore" && e.isFile())) {
2308
+ const own = await loadGitignore(root, dir.abs, dir.rel);
2309
+ if (own)
2310
+ rules = [...rules, own];
2311
+ }
2312
+ const subdirs = [];
2313
+ const hasPackageJson = entries.some((e) => e.name === "package.json" && e.isFile());
2314
+ const kept = /* @__PURE__ */ new Set();
2315
+ for (const entry of entries) {
2316
+ const rel = dir.rel === "" ? entry.name : `${dir.rel}/${entry.name}`;
2317
+ if (entry.isSymbolicLink()) {
2318
+ if (languageOf(entry.name) !== void 0)
2319
+ skip("symbolic link");
2320
+ continue;
2321
+ }
2322
+ if (entry.isDirectory()) {
2323
+ const byName = ignored.has(entry.name) && !(conditional && BUILD_OUTPUT_NAMES.has(entry.name) && !hasPackageJson);
2324
+ if (byName)
2325
+ note(dir.rel, "dir", entry.name);
2326
+ else if (rules.length > 0 && gitIgnored(rules, rel, true))
2327
+ note(dir.rel, "git", `${entry.name}/`);
2328
+ else if (known?.has(rel) && dir.rel === startRel)
2329
+ kept.add(rel);
2330
+ else
2331
+ subdirs.push({ abs: join4(dir.abs, entry.name), rel, rules });
2332
+ continue;
2333
+ }
2334
+ if (!entry.isFile())
2335
+ continue;
2336
+ const abs = join4(dir.abs, entry.name);
2337
+ const lang = languageOf(entry.name);
2338
+ if (lang === void 0) {
2339
+ const ext = extname(entry.name).toLowerCase();
2340
+ if (UNINDEXED_CODE_EXTENSIONS.has(ext)) {
2341
+ note(dir.rel, "ext", ext);
2342
+ } else if (isExtensionless(entry.name) && await shebangOf(root, abs)) {
2343
+ if (rules.length > 0 && gitIgnored(rules, rel, false))
2344
+ note(dir.rel, "git", entry.name);
2345
+ else if (walk.files.length >= b.options.maxFiles) {
2346
+ walk.limits.add("files");
2347
+ break;
2348
+ } else
2349
+ walk.files.push({ rel, abs });
2350
+ }
2351
+ continue;
2352
+ }
2353
+ if (isDeclarationFile(entry.name)) {
2354
+ skip("declaration file");
2355
+ note(dir.rel, "dts", "");
2356
+ continue;
2357
+ }
2358
+ if (rules.length > 0 && gitIgnored(rules, rel, false)) {
2359
+ note(dir.rel, "git", entry.name);
2360
+ continue;
2361
+ }
2362
+ if (walk.files.length >= b.options.maxFiles) {
2363
+ walk.limits.add("files");
2364
+ break;
2365
+ }
2366
+ walk.files.push({ rel, abs });
2367
+ }
2368
+ for (let i = subdirs.length - 1; i >= 0; i--)
2369
+ pending.push(subdirs[i]);
2370
+ if (known && dir.rel === startRel) {
2371
+ for (const k of known)
2372
+ if (!kept.has(k))
2373
+ walk.vanished.push(k);
2374
+ }
2375
+ if (walk.limits.has("files"))
2376
+ break;
2377
+ if (performance.now() - lastYield > SLICE_MS2) {
2378
+ await nextTurn2();
2379
+ lastYield = performance.now();
2380
+ }
2381
+ }
2382
+ walk.files.sort((x, y) => x.rel < y.rel ? -1 : x.rel > y.rel ? 1 : 0);
2383
+ walk.excluded.push(...tally2.values());
2384
+ return walk;
2385
+ }
2386
+ __name(collect, "collect");
2387
+
1234
2388
  // ../analysis/dist/context.js
1235
2389
  async function refreshFile(env, rel) {
1236
- await refreshIndex(env.store, env.root, join4(env.root, ...rel.split("/")), { ...env.options, force: false }, env.host, env.signal);
2390
+ await refreshIndex(env.store, env.root, join5(env.root, ...rel.split("/")), { ...env.options, force: false }, env.host, env.signal);
1237
2391
  }
1238
2392
  __name(refreshFile, "refreshFile");
1239
2393
  var DEFAULT_LIMIT = 50;
@@ -1307,9 +2461,10 @@ var Files = class {
1307
2461
  return {
1308
2462
  id: Number(row.id),
1309
2463
  rel,
1310
- abs: join4(this.root, ...rel.split("/")),
2464
+ abs: join5(this.root, ...rel.split("/")),
1311
2465
  chars: Number(row.chars),
1312
2466
  parseErrors: Number(row.parse_errors),
2467
+ degraded: Number(row.degraded ?? 0),
1313
2468
  size: Number(row.size),
1314
2469
  mtimeMs: Number(row.mtime_ms),
1315
2470
  hash: String(row.hash),
@@ -1432,6 +2587,7 @@ function toFunction(row, info) {
1432
2587
  return {
1433
2588
  id: Number(row.id),
1434
2589
  name: row.name === null || row.name === void 0 ? null : String(row.name),
2590
+ ...row.qname !== null && row.qname !== void 0 ? { qualifiedName: String(row.qname) } : {},
1435
2591
  kind: String(row.kind),
1436
2592
  path: info.abs,
1437
2593
  line: at.line,
@@ -1455,15 +2611,48 @@ function parentsOf(store, files, parentId) {
1455
2611
  return out;
1456
2612
  }
1457
2613
  __name(parentsOf, "parentsOf");
1458
- function sliceOf(text, start, end, maxChars) {
2614
+ function safeEnd(text, at) {
2615
+ const last = text.charCodeAt(at - 1);
2616
+ return last >= 55296 && last <= 56319 ? at - 1 : at;
2617
+ }
2618
+ __name(safeEnd, "safeEnd");
2619
+ var HEADER_CHARS = 400;
2620
+ function sliceOf(text, start, end, maxChars, around) {
1459
2621
  const chars = end - start;
1460
2622
  if (chars <= maxChars)
1461
2623
  return { text: text.slice(start, end), chars, truncated: false };
1462
- let stop = start + maxChars;
1463
- const last = text.charCodeAt(stop - 1);
1464
- if (last >= 55296 && last <= 56319)
1465
- stop--;
1466
- return { text: text.slice(start, stop), chars, truncated: true };
2624
+ if (around === void 0 || around < start || around >= end) {
2625
+ return { text: text.slice(start, safeEnd(text, start + maxChars)), chars, truncated: true };
2626
+ }
2627
+ const header = Math.min(Math.floor(maxChars / 4), HEADER_CHARS);
2628
+ const headerEnd = safeEnd(text, start + header);
2629
+ const budget = maxChars - header;
2630
+ let from = around - Math.floor(budget / 2);
2631
+ let to = from + budget;
2632
+ if (from < headerEnd) {
2633
+ from = headerEnd;
2634
+ to = from + budget;
2635
+ }
2636
+ if (to > end) {
2637
+ to = end;
2638
+ from = Math.max(headerEnd, to - budget);
2639
+ }
2640
+ const first = text.charCodeAt(from);
2641
+ if (from > headerEnd && first >= 56320 && first <= 57343)
2642
+ from--;
2643
+ to = safeEnd(text, to);
2644
+ const gapBefore = from - headerEnd;
2645
+ const gapAfter = end - to;
2646
+ const cut = text.slice(start, headerEnd) + (gapBefore > 0 ? `
2647
+ /* \u2026 ${gapBefore.toLocaleString("en-US")} characters omitted \u2026 */
2648
+ ` : "") + text.slice(from, to) + (gapAfter > 0 ? `
2649
+ /* \u2026 ${gapAfter.toLocaleString("en-US")} characters omitted \u2026 */` : "");
2650
+ return {
2651
+ text: cut,
2652
+ chars,
2653
+ truncated: true,
2654
+ window: { headerChars: headerEnd - start, from, to }
2655
+ };
1467
2656
  }
1468
2657
  __name(sliceOf, "sliceOf");
1469
2658
  var BENIGN_SKIPS = /* @__PURE__ */ new Set(["declaration file", "symbolic link"]);
@@ -1480,6 +2669,17 @@ function named(list) {
1480
2669
  return list.length > 3 ? `${list.slice(0, 3).join(", ")} and ${list.length - 3} more` : list.join(", ");
1481
2670
  }
1482
2671
  __name(named, "named");
2672
+ function inScope(path, scopeRel) {
2673
+ return scopeRel === "" || path === scopeRel || path.startsWith(`${scopeRel}/`);
2674
+ }
2675
+ __name(inScope, "inScope");
2676
+ function scopeWhere(scopeRel) {
2677
+ return {
2678
+ sql: "path = ? OR (path >= ? AND path < ?)",
2679
+ params: [scopeRel, `${scopeRel}/`, `${scopeRel}0`]
2680
+ };
2681
+ }
2682
+ __name(scopeWhere, "scopeWhere");
1483
2683
  function workspaceGaps(store, scopeRel = "") {
1484
2684
  const reasons = [];
1485
2685
  const covered = readCovered(store);
@@ -1493,7 +2693,7 @@ function workspaceGaps(store, scopeRel = "") {
1493
2693
  for (const e of covered) {
1494
2694
  if (e.c === 0 && (scopeRel === "" || e === covering)) {
1495
2695
  const where = e.s === "" ? "the root" : e.s;
1496
- reasons.push(e.k === "cancel" ? `indexing ${where} ${e.r}, so what was indexed is partial. Call the index operation to continue` : `indexing ${where} ${e.r ?? "stopped at a limit"}, so what was indexed is partial. Call the index operation with a narrower path to cover more`);
2696
+ reasons.push(e.k === "cancel" ? `indexing ${where} ${e.r}, so what was indexed is partial. Call the index operation to continue` : `indexing ${where} ${e.r ?? "stopped at a limit"}, so what was indexed is partial. ${nextStep(e.w)}`);
1497
2697
  }
1498
2698
  }
1499
2699
  let skipped = {};
@@ -1514,49 +2714,201 @@ function workspaceGaps(store, scopeRel = "") {
1514
2714
  if (totals.size > 0) {
1515
2715
  reasons.push(`not indexed: ${[...totals].map(([why, n]) => `${n} ${why}`).join(", ")}`);
1516
2716
  }
1517
- const crashed = listOf(store, "crashed");
2717
+ const excluded = exclusionReasons(store, scopeRel);
2718
+ reasons.push(...excluded.gaps);
2719
+ const scoped = scopeRel === "" ? void 0 : scopeWhere(scopeRel);
2720
+ const and = scoped ? ` AND (${scoped.sql})` : "";
2721
+ const crashed = store.all(`SELECT path FROM files WHERE parse_errors < 0${and} ORDER BY path`, ...scoped?.params ?? []).map((r) => String(r.path));
1518
2722
  if (crashed.length > 0) {
1519
2723
  reasons.push(`the parser crashed on ${crashed.length} file(s) (${named(crashed)}), which are recorded with no rows`);
1520
2724
  }
1521
- const violations = listOf(store, "violations");
2725
+ const violations = listOf(store, "violations").filter((path) => inScope(path, scopeRel));
1522
2726
  if (violations.length > 0) {
1523
2727
  reasons.push(`${violations.length} file(s) (${named(violations)}) became a link or resolved outside the root after they were indexed, and were dropped without being read`);
1524
2728
  }
1525
- const bad = store.get("SELECT count(*) AS n FROM files WHERE parse_errors > 0");
2729
+ const bad = store.get(`SELECT count(*) AS n, coalesce(sum(degraded = 1), 0) AS repaired, coalesce(sum(degraded = 2), 0) AS scanned FROM files WHERE parse_errors > 0${and}`, ...scoped?.params ?? []);
1526
2730
  if (bad && Number(bad.n) > 0) {
1527
- reasons.push(`${bad.n} file(s) had syntax errors; the parser kept whatever tree it could recover, often none, so rows from them may be missing`);
2731
+ const repaired = Number(bad.repaired);
2732
+ const scanned = Number(bad.scanned);
2733
+ reasons.push(`${bad.n} file(s) had syntax errors, so rows from them may be missing${repaired > 0 ? `; ${repaired} read after setting the broken lines aside` : ""}${scanned > 0 ? `; ${scanned} degraded to a tolerant scan that finds strings and function declarations only, with no calls, methods or imports` : ""}`);
1528
2734
  }
1529
- return reasons;
2735
+ return { gaps: reasons, notes: excluded.notes };
1530
2736
  }
1531
2737
  __name(workspaceGaps, "workspaceGaps");
1532
- var NEW_FILE_CHECK_DIRS = 400;
1533
- async function newFileReasons(store, root, scopeRel) {
1534
- const rows = scopeRel === "" ? store.all("SELECT path, mtime_ms FROM dirs ORDER BY path LIMIT ?", NEW_FILE_CHECK_DIRS + 1) : store.all("SELECT path, mtime_ms FROM dirs WHERE path = ? OR (path >= ? AND path < ?) ORDER BY path LIMIT ?", scopeRel, `${scopeRel}/`, `${scopeRel}0`, NEW_FILE_CHECK_DIRS + 1);
1535
- const changed = [];
1536
- for (const row of rows.slice(0, NEW_FILE_CHECK_DIRS)) {
1537
- const rel = String(row.path);
2738
+ function tally(rows, shown = 6) {
2739
+ const sorted = [...rows].sort((a, b) => b.n - a.n || (a.name < b.name ? -1 : 1));
2740
+ const head = sorted.slice(0, shown).map((r) => `${r.name || "(none)"} \xD7${r.n}`);
2741
+ return sorted.length > shown ? `${head.join(", ")} and ${sorted.length - shown} more` : head.join(", ");
2742
+ }
2743
+ __name(tally, "tally");
2744
+ function exclusionReasons(store, scopeRel) {
2745
+ const where = scopeRel === "" ? { sql: "", params: [] } : {
2746
+ sql: " WHERE path = ? OR (path >= ? AND path < ?)",
2747
+ params: [scopeRel, `${scopeRel}/`, `${scopeRel}0`]
2748
+ };
2749
+ let rows;
2750
+ try {
2751
+ rows = store.all(`SELECT kind, name, sum(n) AS n FROM excl${where.sql} GROUP BY kind, name`, ...where.params);
2752
+ } catch {
2753
+ return { gaps: [], notes: [] };
2754
+ }
2755
+ const pick = /* @__PURE__ */ __name((kind, keep = () => true) => rows.filter((r) => r.kind === kind && keep(String(r.name))).map((r) => ({ name: String(r.name), n: Number(r.n) })), "pick");
2756
+ const isDefaultDir = /* @__PURE__ */ __name((name) => DEFAULT_IGNORED_DIRS.includes(name), "isDefaultDir");
2757
+ const dirs = pick("dir");
2758
+ const neverSource = dirs.filter((r) => NEVER_SOURCE_DIRS.has(r.name));
2759
+ const buildDirs = dirs.filter((r) => !NEVER_SOURCE_DIRS.has(r.name) && isDefaultDir(r.name));
2760
+ const ownDirs = dirs.filter((r) => !isDefaultDir(r.name));
2761
+ const gitDirs = pick("git", (name) => name.endsWith("/"));
2762
+ const gitFiles = pick("git", (name) => !name.endsWith("/"));
2763
+ const exts = pick("ext");
2764
+ const jsExts = exts.filter((r) => MAY_HOLD_JS.has(r.name));
2765
+ const otherExts = exts.filter((r) => !MAY_HOLD_JS.has(r.name));
2766
+ const dts = pick("dts").reduce((a, r) => a + r.n, 0);
2767
+ const gaps = [];
2768
+ const notes = [];
2769
+ if (ownDirs.length > 0) {
2770
+ gaps.push(`not indexed: ignored directories ${tally(ownDirs)}. To search one, pass its path to the index operation`);
2771
+ }
2772
+ if (gitFiles.length > 0) {
2773
+ gaps.push(`not indexed: source files a .gitignore lists, ${tally(gitFiles)}. Index one by path to search it`);
2774
+ }
2775
+ if (jsExts.length > 0) {
2776
+ gaps.push(`not indexed: files in languages this index does not parse (${tally(jsExts)}); a string in one cannot be found`);
2777
+ }
2778
+ const left = [...neverSource, ...buildDirs];
2779
+ if (left.length > 0) {
2780
+ notes.push(`left out as never or build-output directories: ${tally(left)} (to search one, pass its path to the index operation)`);
2781
+ }
2782
+ if (gitDirs.length > 0) {
2783
+ notes.push(`left out as directories a .gitignore lists: ${tally(gitDirs)}`);
2784
+ }
2785
+ if (otherExts.length > 0) {
2786
+ notes.push(`files in other languages are not parsed (${tally(otherExts)})`);
2787
+ }
2788
+ if (dts > 0) {
2789
+ notes.push(`${dts} declaration file(s) (.d.ts) are not indexed; they hold types only, so no literal or call is missing, but a signature there cannot be shown`);
2790
+ }
2791
+ return { gaps, notes };
2792
+ }
2793
+ __name(exclusionReasons, "exclusionReasons");
2794
+ function coverageOf(reasons) {
2795
+ return reasons.length === 0 ? { status: "complete" } : { status: "partial", reasons };
2796
+ }
2797
+ __name(coverageOf, "coverageOf");
2798
+
2799
+ // ../analysis/dist/freshen.js
2800
+ import { lstatSync } from "node:fs";
2801
+ import { lstat as lstat4 } from "node:fs/promises";
2802
+ import { basename as basename2, join as join6 } from "node:path";
2803
+ import { setImmediate as nextTurn3 } from "node:timers/promises";
2804
+ var FEW_FILES = 25;
2805
+ var FEW_DIRS = 25;
2806
+ var FEW_BYTES = 16 * 1024 * 1024;
2807
+ var MAX_FILES_CHECKED = 25e4;
2808
+ var MAX_DIRS_CHECKED = 2e4;
2809
+ var SLICE_MS3 = 4;
2810
+ function scopeWhere2(column, scopeRel) {
2811
+ if (scopeRel === "")
2812
+ return { sql: "", params: [] };
2813
+ return {
2814
+ sql: ` WHERE ${column} = ? OR (${column} >= ? AND ${column} < ?)`,
2815
+ params: [scopeRel, `${scopeRel}/`, `${scopeRel}0`]
2816
+ };
2817
+ }
2818
+ __name(scopeWhere2, "scopeWhere");
2819
+ async function statAll(paths, visit) {
2820
+ let sliceStart = performance.now();
2821
+ for (let i = 0; i < paths.length; i++) {
2822
+ let stats;
1538
2823
  try {
1539
- const s = await lstat3(join4(root, ...rel.split("/").filter(Boolean)));
1540
- if (s.mtimeMs !== Number(row.mtime_ms))
1541
- changed.push(rel === "" ? "." : rel);
2824
+ stats = lstatSync(paths[i]);
1542
2825
  } catch {
1543
- changed.push(rel === "" ? "." : rel);
2826
+ stats = void 0;
2827
+ }
2828
+ visit(i, stats);
2829
+ if ((i & 63) === 63 && performance.now() - sliceStart > SLICE_MS3) {
2830
+ await nextTurn3();
2831
+ sliceStart = performance.now();
1544
2832
  }
1545
2833
  }
1546
- const reasons = [];
1547
- if (changed.length > 0) {
1548
- reasons.push(`${changed.length} director${changed.length === 1 ? "y" : "ies"} changed since the index was built (${named(changed)}), so files added there may be missing. Run the index operation to pick them up`);
2834
+ }
2835
+ __name(statAll, "statAll");
2836
+ function named2(list) {
2837
+ return list.length > 3 ? `${list.slice(0, 3).join(", ")} and ${list.length - 3} more` : list.join(", ");
2838
+ }
2839
+ __name(named2, "named");
2840
+ async function freshenScope(env, scopeRel) {
2841
+ const { store, root } = env;
2842
+ const notes = [];
2843
+ const gaps = [];
2844
+ const fileScope = scopeWhere2("path", scopeRel);
2845
+ const stored = store.all(`SELECT path, size, mtime_ms FROM files${fileScope.sql} LIMIT ?`, ...fileScope.params, MAX_FILES_CHECKED + 1);
2846
+ const dirScope = scopeWhere2("path", scopeRel);
2847
+ const dirRows = store.all(`SELECT path, mtime_ms FROM dirs${dirScope.sql} LIMIT ?`, ...dirScope.params, MAX_DIRS_CHECKED + 1);
2848
+ const changedFiles = [];
2849
+ const checkedFiles = stored.slice(0, MAX_FILES_CHECKED);
2850
+ await statAll(checkedFiles.map((row) => join6(root, ...String(row.path).split("/"))), (i, s) => {
2851
+ const row = checkedFiles[i];
2852
+ if (!s)
2853
+ changedFiles.push({ rel: String(row.path), size: 0 });
2854
+ else if (!s.isFile() || s.size !== Number(row.size) || s.mtimeMs !== Number(row.mtime_ms))
2855
+ changedFiles.push({ rel: String(row.path), size: s.size });
2856
+ });
2857
+ const changedDirs = [];
2858
+ const checkedDirs = dirRows.slice(0, MAX_DIRS_CHECKED);
2859
+ await statAll(checkedDirs.map((row) => join6(root, ...String(row.path).split("/").filter(Boolean))), (i, s) => {
2860
+ const row = checkedDirs[i];
2861
+ if (!s || s.mtimeMs !== Number(row.mtime_ms))
2862
+ changedDirs.push(String(row.path));
2863
+ });
2864
+ if (scopeRel !== "" && !stored.some((r) => String(r.path) === scopeRel) && !dirRows.some((r) => String(r.path) === scopeRel)) {
2865
+ const s = await lstat4(join6(root, ...scopeRel.split("/"))).catch(() => void 0);
2866
+ if (s?.isFile()) {
2867
+ const source = languageOf(scopeRel) !== void 0 || isExtensionless(basename2(scopeRel)) && await shebangOf(root, join6(root, ...scopeRel.split("/")));
2868
+ if (source)
2869
+ changedFiles.push({ rel: scopeRel, size: s.size });
2870
+ } else if (s?.isDirectory())
2871
+ changedDirs.push(scopeRel);
2872
+ }
2873
+ if (stored.length > MAX_FILES_CHECKED || dirRows.length > MAX_DIRS_CHECKED) {
2874
+ gaps.push(`only the first ${checkedFiles.length.toLocaleString("en-US")} files and ${checkedDirs.length.toLocaleString("en-US")} directories were compared with the disk, so later edits may be missing. Run the index operation`);
2875
+ }
2876
+ if (changedFiles.length === 0 && changedDirs.length === 0)
2877
+ return { notes, gaps };
2878
+ const bytes = changedFiles.reduce((a, f) => a + f.size, 0);
2879
+ const few = changedFiles.length <= FEW_FILES && changedDirs.length <= FEW_DIRS && bytes <= FEW_BYTES;
2880
+ if (!few) {
2881
+ const files = changedFiles.map((f) => f.rel).sort();
2882
+ const parts = [];
2883
+ if (files.length > 0) {
2884
+ parts.push(`${files.length} file(s) changed since indexing (${named2(files)})`);
2885
+ }
2886
+ if (changedDirs.length > 0) {
2887
+ parts.push(`${changedDirs.length} director${changedDirs.length === 1 ? "y" : "ies"} changed since indexing (${named2([...changedDirs].sort().map((d) => d || "."))}), so files added there may be missing`);
2888
+ }
2889
+ gaps.push(`${parts.join("; ")}; too many to re-read for one query. Run the index operation to refresh`);
2890
+ return { notes, gaps };
2891
+ }
2892
+ const dirs = [...new Set(changedDirs)].sort();
2893
+ const dirSet = new Set(dirs);
2894
+ const parentOf = /* @__PURE__ */ __name((rel) => rel.includes("/") ? rel.slice(0, rel.lastIndexOf("/")) : "", "parentOf");
2895
+ const lone = changedFiles.map((f) => f.rel).filter((rel) => !dirSet.has(parentOf(rel)));
2896
+ let incomplete;
2897
+ for (const target of [...dirs, ...lone]) {
2898
+ const abs = target === "" ? root : join6(root, ...target.split("/"));
2899
+ if (toRel(root, abs) === void 0)
2900
+ continue;
2901
+ const out = await refreshIndex(store, root, abs, { ...env.options, force: false, quiet: true, shallow: dirSet.has(target) }, env.host, env.signal);
2902
+ incomplete ??= out.truncated;
1549
2903
  }
1550
- if (rows.length > NEW_FILE_CHECK_DIRS) {
1551
- reasons.push(`only the first ${NEW_FILE_CHECK_DIRS} directories were checked for new files`);
2904
+ const total = changedFiles.length + changedDirs.length;
2905
+ notes.push(`${changedFiles.length} file(s) and ${changedDirs.length} director${changedDirs.length === 1 ? "y" : "ies"} had changed since the index was built and were re-read before this answer`);
2906
+ if (incomplete) {
2907
+ gaps.push(`the re-read of ${total} changed path(s) ${incomplete}, so the answer may miss recent edits. Run the index operation`);
1552
2908
  }
1553
- return reasons;
1554
- }
1555
- __name(newFileReasons, "newFileReasons");
1556
- function coverageOf(reasons) {
1557
- return reasons.length === 0 ? { status: "complete" } : { status: "partial", reasons };
2909
+ return { notes, gaps };
1558
2910
  }
1559
- __name(coverageOf, "coverageOf");
2911
+ __name(freshenScope, "freshenScope");
1560
2912
 
1561
2913
  // ../analysis/dist/provider.js
1562
2914
  var failed = /* @__PURE__ */ __name((error) => ({ kind: "failed", error }), "failed");
@@ -1580,6 +2932,7 @@ function createCodeAnalysisProvider(options = {}) {
1580
2932
  maxFiles: options.maxFiles ?? DEFAULT_MAX_FILES,
1581
2933
  maxDirectories: options.maxDirectories ?? DEFAULT_MAX_DIRECTORIES,
1582
2934
  maxMillis: options.maxMillis ?? DEFAULT_MAX_MILLIS,
2935
+ respectGitignore: options.respectGitignore !== false,
1583
2936
  force
1584
2937
  }), "indexOptions");
1585
2938
  const envOf = /* @__PURE__ */ __name((o, signal, force = false) => ({
@@ -1651,7 +3004,7 @@ function createCodeAnalysisProvider(options = {}) {
1651
3004
  return void 0;
1652
3005
  if (coveringEntry(readCovered(env.store), rel))
1653
3006
  return void 0;
1654
- if (rel !== "" && !await lstat4(scopeAbs).then(() => true, () => false))
3007
+ if (rel !== "" && !await lstat5(scopeAbs).then(() => true, () => false))
1655
3008
  return void 0;
1656
3009
  const started = performance.now();
1657
3010
  const out = await refreshIndex(env.store, env.root, scopeAbs, env.options, env.host, env.signal);
@@ -1659,7 +3012,7 @@ function createCodeAnalysisProvider(options = {}) {
1659
3012
  }
1660
3013
  __name(ensureCovered, "ensureCovered");
1661
3014
  const evidence = /* @__PURE__ */ __name((observed, inferred, gaps, built) => ({
1662
- observed: built ? [...observed, built] : observed,
3015
+ observed: built === void 0 || built === "" ? observed : [...observed, ...typeof built === "string" ? [built] : built],
1663
3016
  inferred,
1664
3017
  coverage: coverageOf(gaps)
1665
3018
  }), "evidence");
@@ -1672,7 +3025,7 @@ function createCodeAnalysisProvider(options = {}) {
1672
3025
  if (info)
1673
3026
  return info;
1674
3027
  return {
1675
- error: `${rel} is not in the index. Only .js .mjs .cjs .jsx .ts .mts .cts .tsx files are indexed, and not declaration files, symbolic links, files in ignored directories (${(options.ignoreDirs ?? DEFAULT_IGNORED_DIRS).join(", ")}), or files that are binary, too large or unparseable.`
3028
+ error: `${rel} is not in the index. Only .js .mjs .cjs .jsx .ts .mts .cts .tsx files (and extension-less scripts that start with a node, bun or deno shebang) are indexed, and not declaration files, symbolic links, files in ignored directories (${(options.ignoreDirs ?? DEFAULT_IGNORED_DIRS).join(", ")}), files a .gitignore lists, or files that are binary, too large or unparseable.`
1676
3029
  };
1677
3030
  }
1678
3031
  __name(fileAt, "fileAt");
@@ -1726,6 +3079,7 @@ function createCodeAnalysisProvider(options = {}) {
1726
3079
  if (scopeRel === void 0)
1727
3080
  return failed(`${scopeAbs} is outside the indexed root ${o.root}.`);
1728
3081
  const out = await refreshIndex(o.store, o.root, scopeAbs, indexOptions(request.force === true), host, signal);
3082
+ const left = workspaceGaps(o.store, scopeRel);
1729
3083
  const count = /* @__PURE__ */ __name((table) => Number(o.store.get(`SELECT count(*) AS n FROM ${table}`).n), "count");
1730
3084
  const summary = {
1731
3085
  root: o.root,
@@ -1744,29 +3098,37 @@ function createCodeAnalysisProvider(options = {}) {
1744
3098
  calls: count("calls"),
1745
3099
  durationMs: Math.round(performance.now() - started),
1746
3100
  ...out.truncated ? {
1747
- truncated: `Indexing ${scopeRel === "" ? "the root" : scopeRel} ${out.truncated}, so the index is partial. Index a narrower path to cover the rest; what was indexed is kept and answers queries now.`
3101
+ truncated: `Indexing ${scopeRel === "" ? "the root" : scopeRel} ${out.truncated}, so the index is partial. ${nextStep(out.limits)}; what was indexed is kept and answers queries now.`
1748
3102
  } : {}
1749
3103
  };
1750
3104
  return {
1751
3105
  kind: "ok",
1752
3106
  value: summary,
1753
3107
  evidence: evidence([
1754
- `walked ${scopeRel === "" ? o.root : scopeRel}: ${out.parsed} file(s) parsed, ${out.unchanged} unchanged by size, mtime or content hash, ${out.removed} removed`
3108
+ `walked ${scopeRel === "" ? o.root : scopeRel}: ${out.parsed} file(s) parsed, ${out.unchanged} unchanged by size, mtime or content hash, ${out.removed} removed`,
3109
+ ...left.notes
1755
3110
  ], o.store.fts ? [] : [
1756
3111
  "this Node.js has no FTS5, so find_literal scans every literal instead of using a substring index; answers are the same, slower"
1757
- ], workspaceGaps(o.store, scopeRel))
3112
+ ], left.gaps)
1758
3113
  };
1759
3114
  });
1760
3115
  },
1761
- findLiteral: /* @__PURE__ */ __name((request) => withScope(request.root, request.path, request.signal, async (o, _env, built) => {
3116
+ findLiteral: /* @__PURE__ */ __name((request) => withScope(request.root, request.path, request.signal, async (o, env, built) => {
1762
3117
  const files = new Files(o.store, o.root);
3118
+ if (CUT_MARK_CHARS.some((c) => request.text.includes(c))) {
3119
+ return failed("the search text contains U+0001 or U+0002, which the index uses to mark where a long literal was cut; they cannot be searched for");
3120
+ }
3121
+ const asked = request.path === void 0 ? "" : toRel(o.root, request.path);
3122
+ if (asked === void 0)
3123
+ return failed(`${request.path} is outside the indexed root ${o.root}.`);
3124
+ const current = await freshenScope(env, asked);
1763
3125
  const scope = scopeSql(o, files, request.path, "s.file_id");
1764
3126
  if ("error" in scope)
1765
3127
  return failed(scope.error);
1766
3128
  const limit = clampLimit(request.limit);
1767
3129
  const insensitive = request.caseSensitive === false;
1768
3130
  const codePoints = Array.from(request.text).length;
1769
- const useFts = o.store.fts && codePoints >= 3;
3131
+ const useFts = o.store.fts && codePoints >= 3 && !request.text.includes("\0");
1770
3132
  const test = insensitive ? "instr(lower(s.value), lower(?)) > 0" : "instr(s.value, ?) > 0";
1771
3133
  const prefilter = useFts ? " AND s.id IN (SELECT rowid FROM lit WHERE lit MATCH ?)" : "";
1772
3134
  const where = `WHERE ${test}${prefilter}${scope.sql}`;
@@ -1820,7 +3182,7 @@ function createCodeAnalysisProvider(options = {}) {
1820
3182
  start: Number(r.start),
1821
3183
  end: Number(r.end),
1822
3184
  kind: String(r.kind),
1823
- value: value.length > PREVIEW_CHARS ? value.slice(0, PREVIEW_CHARS) : value,
3185
+ value: previewOf(value, request.text, insensitive),
1824
3186
  valueTruncated: value.length > PREVIEW_CHARS,
1825
3187
  ...fn ? { function: fn } : {},
1826
3188
  ...mark ? { stale: mark } : {}
@@ -1832,6 +3194,7 @@ function createCodeAnalysisProvider(options = {}) {
1832
3194
  total,
1833
3195
  ...next < total ? { nextCursor: encodeCursor({ g: generation, o: next, q }) } : {}
1834
3196
  };
3197
+ const left = workspaceGaps(o.store, scope.rel);
1835
3198
  return {
1836
3199
  kind: "ok",
1837
3200
  value: page,
@@ -1839,12 +3202,15 @@ function createCodeAnalysisProvider(options = {}) {
1839
3202
  `${total} string or template literal(s) contain ${JSON.stringify(request.text)}${insensitive ? " (ASCII case-insensitive)" : ""}`,
1840
3203
  "each hit lists the innermost function whose source range contains it"
1841
3204
  ], [
1842
- "literals are indexed up to 4096 characters, and a template literal is indexed per static chunk, so a match cannot span a ${...} or sit past the cut"
3205
+ "a template literal is indexed per static chunk, so a match cannot span a ${...}; a literal over 8192 characters is indexed by its first and last 4096"
1843
3206
  ], [
1844
- ...workspaceGaps(o.store, scope.rel),
3207
+ ...left.gaps,
1845
3208
  ...markReasons(fresh.marks),
1846
- ...await newFileReasons(o.store, o.root, scope.rel)
1847
- ], built)
3209
+ // One character is not a search for a passage; what a cut literal
3210
+ // dropped is only worth reporting for a needle that could be in it.
3211
+ ...codePoints > 1 ? cutReasons(o.store, scope.sql, scope.params) : [],
3212
+ ...current.gaps
3213
+ ], [...left.notes, ...built ? [built] : [], ...current.notes])
1848
3214
  };
1849
3215
  }), "findLiteral"),
1850
3216
  enclosingFunction: /* @__PURE__ */ __name((request) => withScope(request.root, request.path, request.signal, async (o, env, built) => {
@@ -1866,12 +3232,19 @@ function createCodeAnalysisProvider(options = {}) {
1866
3232
  ...built ? [built] : []
1867
3233
  ];
1868
3234
  if (!row) {
3235
+ const cls = o.store.get('SELECT name FROM classes WHERE file_id = ? AND start <= ? AND "end" > ? ORDER BY start DESC LIMIT 1', info.id, at.offset, at.offset);
3236
+ const place = `${info.rel}:${request.line}:${request.column ?? 1}`;
3237
+ const className = cls && cls.name !== null ? String(cls.name) : void 0;
1869
3238
  return {
1870
3239
  kind: "ok",
1871
- value: { function: null, parents: [] },
3240
+ value: {
3241
+ function: null,
3242
+ parents: [],
3243
+ ...cls ? { inClass: className ?? "(anonymous class)" } : {}
3244
+ },
1872
3245
  evidence: {
1873
3246
  observed: [
1874
- `${info.rel}:${request.line}:${request.column ?? 1} lies in no function body; it is at the top level of the file`,
3247
+ cls ? `${place} is in the body of class ${className ?? "(anonymous)"} outside every method (a field initializer or a static block), not in a function` : `${place} lies in no function body; it is at the top level of the file`,
1875
3248
  ...notes
1876
3249
  ],
1877
3250
  inferred: [],
@@ -1886,7 +3259,7 @@ function createCodeAnalysisProvider(options = {}) {
1886
3259
  value: {
1887
3260
  function: fn,
1888
3261
  parents,
1889
- source: sliceOf(text, fn.start, fn.end, clampChars(request.maxChars))
3262
+ source: sliceOf(text, fn.start, fn.end, clampChars(request.maxChars), at.offset)
1890
3263
  },
1891
3264
  evidence: {
1892
3265
  observed: [
@@ -1941,8 +3314,8 @@ function createCodeAnalysisProvider(options = {}) {
1941
3314
  if ("error" in fresh)
1942
3315
  return failed(fresh.error);
1943
3316
  info = fresh.info;
1944
- total = Number(o.store.get("SELECT count(*) AS n FROM functions WHERE file_id = ? AND name = ?", info.id, request.name).n);
1945
- rows = o.store.all("SELECT * FROM functions WHERE file_id = ? AND name = ? ORDER BY start LIMIT ? OFFSET ?", info.id, request.name, limit, cursor.offset);
3317
+ total = Number(o.store.get("SELECT count(*) AS n FROM functions WHERE file_id = ? AND (name = ? OR qname = ?)", info.id, request.name, request.name).n);
3318
+ rows = o.store.all("SELECT * FROM functions WHERE file_id = ? AND (name = ? OR qname = ?) ORDER BY start LIMIT ? OFFSET ?", info.id, request.name, request.name, limit, cursor.offset);
1946
3319
  } else {
1947
3320
  return failed("functionSource needs `id`, or `path` together with `name`.");
1948
3321
  }
@@ -1951,12 +3324,15 @@ function createCodeAnalysisProvider(options = {}) {
1951
3324
  });
1952
3325
  if ("error" in verified)
1953
3326
  return failed(verified.error);
3327
+ const aroundOffset = request.around ? offsetOf(verified.info.starts, verified.info.chars, request.around.line, request.around.column ?? 1) : void 0;
3328
+ if (aroundOffset && "error" in aroundOffset)
3329
+ return failed(`${verified.info.rel}: ${aroundOffset.error}`);
1954
3330
  const items = rows.map((row) => {
1955
3331
  const fn = toFunction(row, verified.info);
1956
3332
  return {
1957
3333
  function: fn,
1958
3334
  parents: parentsOf(o.store, files, row.parent_id === null ? null : Number(row.parent_id)),
1959
- source: sliceOf(verified.text, fn.start, fn.end, maxChars)
3335
+ source: sliceOf(verified.text, fn.start, fn.end, maxChars, aroundOffset?.offset)
1960
3336
  };
1961
3337
  });
1962
3338
  const next = cursor.offset + items.length;
@@ -2000,6 +3376,12 @@ function createCodeAnalysisProvider(options = {}) {
2000
3376
  gaps.push(...fileGaps(fresh.info));
2001
3377
  scoped = { sql: " AND c.file_id = ?", params: [fresh.info.id] };
2002
3378
  } else {
3379
+ const asked = request.path === void 0 ? "" : toRel(o.root, request.path);
3380
+ if (asked === void 0)
3381
+ return failed(`${request.path} is outside the indexed root ${o.root}.`);
3382
+ const current = await freshenScope(env, asked);
3383
+ notes.push(...current.notes);
3384
+ gaps.push(...current.gaps);
2003
3385
  const s = scopeSql(o, files, request.path, "c.file_id");
2004
3386
  if ("error" in s)
2005
3387
  return failed(s.error);
@@ -2007,10 +3389,17 @@ function createCodeAnalysisProvider(options = {}) {
2007
3389
  scopeRel = s.rel;
2008
3390
  }
2009
3391
  const limit = clampLimit(request.limit);
2010
- const test = member ? "(c.callee = ? OR (length(c.callee) > length(?) AND substr(c.callee, -(length(?) + 1)) = '.' || ?))" : "c.callee = ?";
2011
- const testParams = member ? [request.name, request.name, request.name, request.name] : [request.name];
3392
+ const dot = request.name.lastIndexOf(".");
3393
+ const method = dot > 0 && !request.name.startsWith("this.") && o.store.get("SELECT 1 AS x FROM functions WHERE qname = ? LIMIT 1", request.name) !== void 0 ? { cls: request.name.slice(0, dot), member: request.name.slice(dot + 1) } : void 0;
3394
+ const suffix = `.${method ? method.member : request.name}`;
3395
+ const endsWith = "(length(c.callee) > ? AND substr(c.callee, -?) = ?)";
3396
+ const test = method ? `(c.callee = ? OR ${endsWith})` : member ? `(c.callee = ? OR ${endsWith})` : "c.callee = ?";
3397
+ const testParams = method || member ? [request.name, suffix.length, suffix.length, suffix] : [request.name];
2012
3398
  const where = `WHERE ${test}${scoped.sql}`;
2013
3399
  const params = [...testParams, ...scoped.params];
3400
+ const resolvedTest = method ? "(c.callee = ? OR (c.callee = 'this.' || ? AND c.owner = ?))" : void 0;
3401
+ const resolvedParams = method ? [request.name, method.member, method.cls] : [];
3402
+ const tierSql = resolvedTest ? `CASE WHEN ${resolvedTest} THEN 0 ELSE 1 END` : "0";
2014
3403
  let offset = 0;
2015
3404
  let rows = [];
2016
3405
  let total = 0;
@@ -2025,7 +3414,7 @@ function createCodeAnalysisProvider(options = {}) {
2025
3414
  return failed(cursor.error);
2026
3415
  offset = cursor.offset;
2027
3416
  total = Number(o.store.get(`SELECT count(*) AS n FROM calls c ${where}`, ...params).n);
2028
- rows = o.store.all(`SELECT c.rowid AS rid, c.file_id, c.fn_id, c.start, c.callee, c.kind, c.nargs FROM calls c ${where} ORDER BY c.rowid LIMIT ? OFFSET ?`, ...params, limit, offset);
3417
+ rows = o.store.all(`SELECT c.rowid AS rid, c.file_id, c.fn_id, c.start, c.callee, c.kind, c.nargs, ${tierSql} AS tier FROM calls c ${where} ORDER BY tier, c.rowid LIMIT ? OFFSET ?`, ...resolvedParams, ...params, limit, offset);
2029
3418
  freshness = await checkFreshness(o.store, files, o.root, rows.map((r) => Number(r.file_id)));
2030
3419
  if (freshness.dropped.length === 0)
2031
3420
  break;
@@ -2055,12 +3444,23 @@ function createCodeAnalysisProvider(options = {}) {
2055
3444
  callee: String(r.callee),
2056
3445
  kind: String(r.kind),
2057
3446
  argumentCount: Number(r.nargs),
3447
+ ...method ? { resolution: Number(r.tier) === 0 ? "resolved" : "text-only" } : {},
2058
3448
  ...caller ? { caller } : {},
2059
3449
  ...mark ? { stale: mark } : {}
2060
3450
  };
2061
3451
  });
3452
+ const unresolved = Number(o.store.get(`SELECT count(*) AS n FROM calls c WHERE c.unres = 1${scoped.sql}`, ...scoped.params).n);
3453
+ const callsInScope = Number(o.store.get(`SELECT count(*) AS n FROM calls c WHERE 1 = 1${scoped.sql}`, ...scoped.params).n);
3454
+ if (unresolved > 0 && total === 0) {
3455
+ gaps.push(`no static call to ${JSON.stringify(request.name)} found; ${unresolved} call(s) in scope use a computed callee and could reach it`);
3456
+ } else if (unresolved > 0 && unresolved >= callsInScope * UNRESOLVED_SHARE) {
3457
+ gaps.push(`${unresolved} of ${callsInScope} calls in scope use a computed callee (${Math.round(unresolved / callsInScope * 100)}%), so a call to ${JSON.stringify(request.name)} made through one of them is not in these results`);
3458
+ }
3459
+ const resolvedCount = method ? Number(o.store.get(`SELECT count(*) AS n FROM calls c ${where} AND ${resolvedTest}`, ...params, ...resolvedParams).n) : 0;
2062
3460
  if (scope === "workspace") {
2063
- gaps.push(...workspaceGaps(o.store, scopeRel), ...markReasons(freshness.marks), ...await newFileReasons(o.store, o.root, scopeRel));
3461
+ const left = workspaceGaps(o.store, scopeRel);
3462
+ gaps.push(...left.gaps, ...markReasons(freshness.marks));
3463
+ notes.push(...left.notes);
2064
3464
  } else {
2065
3465
  gaps.push(...markReasons(freshness.marks));
2066
3466
  }
@@ -2074,11 +3474,15 @@ function createCodeAnalysisProvider(options = {}) {
2074
3474
  ...next < total ? { nextCursor: encodeCursor({ g: generation, o: next, q }) } : {}
2075
3475
  },
2076
3476
  evidence: evidence([
2077
- `${total} call expression(s) whose callee text is ${member ? `${JSON.stringify(request.name)} or ends in .${request.name}` : JSON.stringify(request.name)}, in ${distinct} file(s)`,
3477
+ method ? `${total} call expression(s) of ${JSON.stringify(request.name)} or of a .${method.member}() on some other receiver, in ${distinct} file(s): ${resolvedCount} resolved (this.${method.member}() inside ${method.cls}, or the qualified text), ${total - resolvedCount} text-only` : `${total} call expression(s) whose callee text is ${member ? `${JSON.stringify(request.name)} or ends in .${request.name}` : JSON.stringify(request.name)}, in ${distinct} file(s)`,
3478
+ `${unresolved} of ${callsInScope} calls in scope use a computed callee`,
2078
3479
  ...notes
2079
3480
  ], [
2080
3481
  "callers are matched by the callee TEXT, not by scope or binding: two unrelated functions called by the same name are the same callee here",
2081
- "a call through an alias, a destructured binding, .call/.apply or computed access (obj[name]()) is not matched",
3482
+ '(0, a.b)() is read as a.b() and obj["b"]() as obj.b(); f.call(), f.apply() and f.bind() are listed as call-via and tagged templates as tagged; a call through an alias, a destructured binding or a computed key that is not a string literal is not matched',
3483
+ ...method ? [
3484
+ `${request.name} is a method: only this.${method.member}() inside ${method.cls} is resolved. A text-only match may be a different class's ${method.member}, or a subclass's; the receiver's type is not known`
3485
+ ] : [],
2082
3486
  ...scope === "workspace" && distinct > 1 ? [
2083
3487
  `the matches span ${distinct} files and may be different functions that share a name`
2084
3488
  ] : []
@@ -2157,6 +3561,25 @@ function createCodeAnalysisProvider(options = {}) {
2157
3561
  return provider;
2158
3562
  }
2159
3563
  __name(createCodeAnalysisProvider, "createCodeAnalysisProvider");
3564
+ function previewOf(value, needle, insensitive) {
3565
+ if (value.length <= PREVIEW_CHARS)
3566
+ return value;
3567
+ const at = insensitive ? value.toLowerCase().indexOf(needle.toLowerCase()) : value.indexOf(needle);
3568
+ if (at < 0 || at + needle.length <= PREVIEW_CHARS)
3569
+ return value.slice(0, PREVIEW_CHARS);
3570
+ const from = Math.max(0, Math.min(at - 60, value.length - PREVIEW_CHARS));
3571
+ const first = value.charCodeAt(from);
3572
+ return value.slice(first >= 56320 && first <= 57343 ? from + 1 : from, from + PREVIEW_CHARS);
3573
+ }
3574
+ __name(previewOf, "previewOf");
3575
+ var UNRESOLVED_SHARE = 0.05;
3576
+ function cutReasons(store, scopeSql, params) {
3577
+ const n = Number(store.get(`SELECT count(*) AS n FROM strings s WHERE s.cut > 0${scopeSql}`, ...params).n);
3578
+ return n === 0 ? [] : [
3579
+ `${n} literal(s) in scope are longer than 8192 characters and keep only their first and last 4096, so a match in the middle of one cannot be found`
3580
+ ];
3581
+ }
3582
+ __name(cutReasons, "cutReasons");
2160
3583
  function fileGaps(info) {
2161
3584
  if (info.parseErrors < 0) {
2162
3585
  return [
@@ -2165,7 +3588,7 @@ function fileGaps(info) {
2165
3588
  }
2166
3589
  if (info.parseErrors > 0) {
2167
3590
  return [
2168
- `${info.rel} had syntax errors; the parser kept whatever tree it could recover, which is often none, so rows from it may be missing`
3591
+ info.degraded === 2 ? `${info.rel} had syntax errors and was read by a tolerant scan: strings and function declarations only, no calls, methods or imports` : info.degraded === 1 ? `${info.rel} had syntax errors; it was read after setting the broken lines aside, so rows from those lines are missing` : `${info.rel} had syntax errors; the parser kept whatever tree it could recover, which is often none, so rows from it may be missing`
2169
3592
  ];
2170
3593
  }
2171
3594
  return [];
@@ -2179,4 +3602,4 @@ export {
2179
3602
  DEFAULT_MAX_MILLIS,
2180
3603
  createCodeAnalysisProvider
2181
3604
  };
2182
- //# sourceMappingURL=dist-KGLSBIES.js.map
3605
+ //# sourceMappingURL=dist-ADL22Y3L.js.map