@smthrs/std 0.0.0-stage → 1.0.0-rc.3

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 (555) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/LICENSE +21 -0
  3. package/README.md +152 -2
  4. package/dist/cjs/ApplyPatch.d.ts +174 -0
  5. package/dist/cjs/ApplyPatch.d.ts.map +1 -0
  6. package/dist/cjs/ApplyPatch.js +309 -0
  7. package/dist/cjs/ApplyPatch.js.map +7 -0
  8. package/dist/cjs/Bash.d.ts +304 -0
  9. package/dist/cjs/Bash.d.ts.map +1 -0
  10. package/dist/cjs/Bash.js +321 -0
  11. package/dist/cjs/Bash.js.map +7 -0
  12. package/dist/cjs/Checkpoints.d.ts +279 -0
  13. package/dist/cjs/Checkpoints.d.ts.map +1 -0
  14. package/dist/cjs/Checkpoints.js +145 -0
  15. package/dist/cjs/Checkpoints.js.map +7 -0
  16. package/dist/cjs/Container.d.ts +132 -0
  17. package/dist/cjs/Container.d.ts.map +1 -0
  18. package/dist/cjs/Container.js +113 -0
  19. package/dist/cjs/Container.js.map +7 -0
  20. package/dist/cjs/Edit.d.ts +203 -0
  21. package/dist/cjs/Edit.d.ts.map +1 -0
  22. package/dist/cjs/Edit.js +258 -0
  23. package/dist/cjs/Edit.js.map +7 -0
  24. package/dist/cjs/ExaWebSearch.d.ts +22 -0
  25. package/dist/cjs/ExaWebSearch.d.ts.map +1 -0
  26. package/dist/cjs/ExaWebSearch.js +138 -0
  27. package/dist/cjs/ExaWebSearch.js.map +7 -0
  28. package/dist/cjs/Explore.d.ts +328 -0
  29. package/dist/cjs/Explore.d.ts.map +1 -0
  30. package/dist/cjs/Explore.js +90 -0
  31. package/dist/cjs/Explore.js.map +7 -0
  32. package/dist/cjs/Fetch.d.ts +130 -0
  33. package/dist/cjs/Fetch.d.ts.map +1 -0
  34. package/dist/cjs/Fetch.js +64 -0
  35. package/dist/cjs/Fetch.js.map +7 -0
  36. package/dist/cjs/Glob.d.ts +204 -0
  37. package/dist/cjs/Glob.d.ts.map +1 -0
  38. package/dist/cjs/Glob.js +94 -0
  39. package/dist/cjs/Glob.js.map +7 -0
  40. package/dist/cjs/Grep.d.ts +347 -0
  41. package/dist/cjs/Grep.d.ts.map +1 -0
  42. package/dist/cjs/Grep.js +181 -0
  43. package/dist/cjs/Grep.js.map +7 -0
  44. package/dist/cjs/HttpPost.d.ts +130 -0
  45. package/dist/cjs/HttpPost.d.ts.map +1 -0
  46. package/dist/cjs/HttpPost.js +72 -0
  47. package/dist/cjs/HttpPost.js.map +7 -0
  48. package/dist/cjs/LanguageServer.d.ts +90 -0
  49. package/dist/cjs/LanguageServer.d.ts.map +1 -0
  50. package/dist/cjs/LanguageServer.js +60 -0
  51. package/dist/cjs/LanguageServer.js.map +7 -0
  52. package/dist/cjs/Ls.d.ts +164 -0
  53. package/dist/cjs/Ls.d.ts.map +1 -0
  54. package/dist/cjs/Ls.js +136 -0
  55. package/dist/cjs/Ls.js.map +7 -0
  56. package/dist/cjs/Lsp.d.ts +125 -0
  57. package/dist/cjs/Lsp.d.ts.map +1 -0
  58. package/dist/cjs/Lsp.js +137 -0
  59. package/dist/cjs/Lsp.js.map +7 -0
  60. package/dist/cjs/Manifest.d.ts +918 -0
  61. package/dist/cjs/Manifest.d.ts.map +1 -0
  62. package/dist/cjs/Manifest.js +144 -0
  63. package/dist/cjs/Manifest.js.map +7 -0
  64. package/dist/cjs/NativeSearch.d.ts +38 -0
  65. package/dist/cjs/NativeSearch.d.ts.map +1 -0
  66. package/dist/cjs/NativeSearch.js +326 -0
  67. package/dist/cjs/NativeSearch.js.map +7 -0
  68. package/dist/cjs/NodeLanguageServer.d.ts +128 -0
  69. package/dist/cjs/NodeLanguageServer.d.ts.map +1 -0
  70. package/dist/cjs/NodeLanguageServer.js +796 -0
  71. package/dist/cjs/NodeLanguageServer.js.map +7 -0
  72. package/dist/cjs/PortableSearch.d.ts +24 -0
  73. package/dist/cjs/PortableSearch.d.ts.map +1 -0
  74. package/dist/cjs/PortableSearch.js +233 -0
  75. package/dist/cjs/PortableSearch.js.map +7 -0
  76. package/dist/cjs/Probe.d.ts +193 -0
  77. package/dist/cjs/Probe.d.ts.map +1 -0
  78. package/dist/cjs/Probe.js +134 -0
  79. package/dist/cjs/Probe.js.map +7 -0
  80. package/dist/cjs/Read.d.ts +189 -0
  81. package/dist/cjs/Read.d.ts.map +1 -0
  82. package/dist/cjs/Read.js +223 -0
  83. package/dist/cjs/Read.js.map +7 -0
  84. package/dist/cjs/Relocate.d.ts +73 -0
  85. package/dist/cjs/Relocate.d.ts.map +1 -0
  86. package/dist/cjs/Relocate.js +72 -0
  87. package/dist/cjs/Relocate.js.map +7 -0
  88. package/dist/cjs/Search.d.ts +163 -0
  89. package/dist/cjs/Search.d.ts.map +1 -0
  90. package/dist/cjs/Search.js +51 -0
  91. package/dist/cjs/Search.js.map +7 -0
  92. package/dist/cjs/SearchConformance.d.ts +115 -0
  93. package/dist/cjs/SearchConformance.d.ts.map +1 -0
  94. package/dist/cjs/SearchConformance.js +172 -0
  95. package/dist/cjs/SearchConformance.js.map +7 -0
  96. package/dist/cjs/SearchContract.d.ts +114 -0
  97. package/dist/cjs/SearchContract.d.ts.map +1 -0
  98. package/dist/cjs/SearchContract.js +339 -0
  99. package/dist/cjs/SearchContract.js.map +7 -0
  100. package/dist/cjs/ShellCommand.d.ts +164 -0
  101. package/dist/cjs/ShellCommand.d.ts.map +1 -0
  102. package/dist/cjs/ShellCommand.js +102 -0
  103. package/dist/cjs/ShellCommand.js.map +7 -0
  104. package/dist/cjs/StdError.d.ts +55 -0
  105. package/dist/cjs/StdError.d.ts.map +1 -0
  106. package/dist/cjs/StdError.js +74 -0
  107. package/dist/cjs/StdError.js.map +7 -0
  108. package/dist/cjs/TestRun.d.ts +311 -0
  109. package/dist/cjs/TestRun.d.ts.map +1 -0
  110. package/dist/cjs/TestRun.js +228 -0
  111. package/dist/cjs/TestRun.js.map +7 -0
  112. package/dist/cjs/TestRunner.d.ts +102 -0
  113. package/dist/cjs/TestRunner.d.ts.map +1 -0
  114. package/dist/cjs/TestRunner.js +54 -0
  115. package/dist/cjs/TestRunner.js.map +7 -0
  116. package/dist/cjs/TreeFingerprint.d.ts +140 -0
  117. package/dist/cjs/TreeFingerprint.d.ts.map +1 -0
  118. package/dist/cjs/TreeFingerprint.js +87 -0
  119. package/dist/cjs/TreeFingerprint.js.map +7 -0
  120. package/dist/cjs/UpdatePlan.d.ts +152 -0
  121. package/dist/cjs/UpdatePlan.d.ts.map +1 -0
  122. package/dist/cjs/UpdatePlan.js +87 -0
  123. package/dist/cjs/UpdatePlan.js.map +7 -0
  124. package/dist/cjs/WebFetch.d.ts +134 -0
  125. package/dist/cjs/WebFetch.d.ts.map +1 -0
  126. package/dist/cjs/WebFetch.js +140 -0
  127. package/dist/cjs/WebFetch.js.map +7 -0
  128. package/dist/cjs/WebSearch.d.ts +181 -0
  129. package/dist/cjs/WebSearch.d.ts.map +1 -0
  130. package/dist/cjs/WebSearch.js +86 -0
  131. package/dist/cjs/WebSearch.js.map +7 -0
  132. package/dist/cjs/Write.d.ts +147 -0
  133. package/dist/cjs/Write.d.ts.map +1 -0
  134. package/dist/cjs/Write.js +122 -0
  135. package/dist/cjs/Write.js.map +7 -0
  136. package/dist/cjs/index.d.ts +127 -0
  137. package/dist/cjs/index.d.ts.map +1 -0
  138. package/dist/cjs/index.js +99 -0
  139. package/dist/cjs/index.js.map +7 -0
  140. package/dist/cjs/internal/ApplyPatch.d.ts +145 -0
  141. package/dist/cjs/internal/ApplyPatch.d.ts.map +1 -0
  142. package/dist/cjs/internal/ApplyPatch.js +462 -0
  143. package/dist/cjs/internal/ApplyPatch.js.map +7 -0
  144. package/dist/cjs/internal/CodexText.d.ts +73 -0
  145. package/dist/cjs/internal/CodexText.d.ts.map +1 -0
  146. package/dist/cjs/internal/CodexText.js +108 -0
  147. package/dist/cjs/internal/CodexText.js.map +7 -0
  148. package/dist/cjs/internal/Declaration.d.ts +49 -0
  149. package/dist/cjs/internal/Declaration.d.ts.map +1 -0
  150. package/dist/cjs/internal/Declaration.js +46 -0
  151. package/dist/cjs/internal/Declaration.js.map +7 -0
  152. package/dist/cjs/internal/Diagnostics.d.ts +77 -0
  153. package/dist/cjs/internal/Diagnostics.d.ts.map +1 -0
  154. package/dist/cjs/internal/Diagnostics.js +89 -0
  155. package/dist/cjs/internal/Diagnostics.js.map +7 -0
  156. package/dist/cjs/internal/EnvelopePrecheck.d.ts +67 -0
  157. package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -0
  158. package/dist/cjs/internal/EnvelopePrecheck.js +124 -0
  159. package/dist/cjs/internal/EnvelopePrecheck.js.map +7 -0
  160. package/dist/cjs/internal/Exec.d.ts +139 -0
  161. package/dist/cjs/internal/Exec.d.ts.map +1 -0
  162. package/dist/cjs/internal/Exec.js +158 -0
  163. package/dist/cjs/internal/Exec.js.map +7 -0
  164. package/dist/cjs/internal/FileMutation.d.ts +109 -0
  165. package/dist/cjs/internal/FileMutation.d.ts.map +1 -0
  166. package/dist/cjs/internal/FileMutation.js +116 -0
  167. package/dist/cjs/internal/FileMutation.js.map +7 -0
  168. package/dist/cjs/internal/FsFailure.d.ts +38 -0
  169. package/dist/cjs/internal/FsFailure.d.ts.map +1 -0
  170. package/dist/cjs/internal/FsFailure.js +40 -0
  171. package/dist/cjs/internal/FsFailure.js.map +7 -0
  172. package/dist/cjs/internal/GitWorktree.d.ts +98 -0
  173. package/dist/cjs/internal/GitWorktree.d.ts.map +1 -0
  174. package/dist/cjs/internal/GitWorktree.js +270 -0
  175. package/dist/cjs/internal/GitWorktree.js.map +7 -0
  176. package/dist/cjs/internal/Grouping.d.ts +51 -0
  177. package/dist/cjs/internal/Grouping.d.ts.map +1 -0
  178. package/dist/cjs/internal/Grouping.js +83 -0
  179. package/dist/cjs/internal/Grouping.js.map +7 -0
  180. package/dist/cjs/internal/Html.d.ts +20 -0
  181. package/dist/cjs/internal/Html.d.ts.map +1 -0
  182. package/dist/cjs/internal/Html.js +81 -0
  183. package/dist/cjs/internal/Html.js.map +7 -0
  184. package/dist/cjs/internal/Http.d.ts +95 -0
  185. package/dist/cjs/internal/Http.d.ts.map +1 -0
  186. package/dist/cjs/internal/Http.js +153 -0
  187. package/dist/cjs/internal/Http.js.map +7 -0
  188. package/dist/cjs/internal/HttpNetwork.d.ts +27 -0
  189. package/dist/cjs/internal/HttpNetwork.d.ts.map +1 -0
  190. package/dist/cjs/internal/HttpNetwork.js +146 -0
  191. package/dist/cjs/internal/HttpNetwork.js.map +7 -0
  192. package/dist/cjs/internal/Ignore.d.ts +37 -0
  193. package/dist/cjs/internal/Ignore.d.ts.map +1 -0
  194. package/dist/cjs/internal/Ignore.js +100 -0
  195. package/dist/cjs/internal/Ignore.js.map +7 -0
  196. package/dist/cjs/internal/LinearRegex.d.ts +19 -0
  197. package/dist/cjs/internal/LinearRegex.d.ts.map +1 -0
  198. package/dist/cjs/internal/LinearRegex.js +166 -0
  199. package/dist/cjs/internal/LinearRegex.js.map +7 -0
  200. package/dist/cjs/internal/Match.d.ts +85 -0
  201. package/dist/cjs/internal/Match.d.ts.map +1 -0
  202. package/dist/cjs/internal/Match.js +99 -0
  203. package/dist/cjs/internal/Match.js.map +7 -0
  204. package/dist/cjs/internal/Paths.d.ts +23 -0
  205. package/dist/cjs/internal/Paths.d.ts.map +1 -0
  206. package/dist/cjs/internal/Paths.js +52 -0
  207. package/dist/cjs/internal/Paths.js.map +7 -0
  208. package/dist/cjs/internal/Preserve.d.ts +25 -0
  209. package/dist/cjs/internal/Preserve.d.ts.map +1 -0
  210. package/dist/cjs/internal/Preserve.js +88 -0
  211. package/dist/cjs/internal/Preserve.js.map +7 -0
  212. package/dist/cjs/internal/Prune.d.ts +35 -0
  213. package/dist/cjs/internal/Prune.d.ts.map +1 -0
  214. package/dist/cjs/internal/Prune.js +54 -0
  215. package/dist/cjs/internal/Prune.js.map +7 -0
  216. package/dist/cjs/internal/SearchContract.d.ts +63 -0
  217. package/dist/cjs/internal/SearchContract.d.ts.map +1 -0
  218. package/dist/cjs/internal/SearchContract.js +46 -0
  219. package/dist/cjs/internal/SearchContract.js.map +7 -0
  220. package/dist/cjs/internal/Symbols.d.ts +39 -0
  221. package/dist/cjs/internal/Symbols.d.ts.map +1 -0
  222. package/dist/cjs/internal/Symbols.js +59 -0
  223. package/dist/cjs/internal/Symbols.js.map +7 -0
  224. package/dist/cjs/internal/TestReport.d.ts +52 -0
  225. package/dist/cjs/internal/TestReport.d.ts.map +1 -0
  226. package/dist/cjs/internal/TestReport.js +131 -0
  227. package/dist/cjs/internal/TestReport.js.map +7 -0
  228. package/dist/cjs/internal/Text.d.ts +114 -0
  229. package/dist/cjs/internal/Text.d.ts.map +1 -0
  230. package/dist/cjs/internal/Text.js +82 -0
  231. package/dist/cjs/internal/Text.js.map +7 -0
  232. package/dist/cjs/internal/Url.d.ts +13 -0
  233. package/dist/cjs/internal/Url.d.ts.map +1 -0
  234. package/dist/cjs/internal/Url.js +35 -0
  235. package/dist/cjs/internal/Url.js.map +7 -0
  236. package/dist/cjs/internal/Walk.d.ts +72 -0
  237. package/dist/cjs/internal/Walk.d.ts.map +1 -0
  238. package/dist/cjs/internal/Walk.js +108 -0
  239. package/dist/cjs/internal/Walk.js.map +7 -0
  240. package/dist/cjs/package.json +1 -0
  241. package/dist/esm/ApplyPatch.d.ts +174 -0
  242. package/dist/esm/ApplyPatch.d.ts.map +1 -0
  243. package/dist/esm/ApplyPatch.js +346 -0
  244. package/dist/esm/ApplyPatch.js.map +1 -0
  245. package/dist/esm/Bash.d.ts +304 -0
  246. package/dist/esm/Bash.d.ts.map +1 -0
  247. package/dist/esm/Bash.js +469 -0
  248. package/dist/esm/Bash.js.map +1 -0
  249. package/dist/esm/Checkpoints.d.ts +279 -0
  250. package/dist/esm/Checkpoints.d.ts.map +1 -0
  251. package/dist/esm/Checkpoints.js +298 -0
  252. package/dist/esm/Checkpoints.js.map +1 -0
  253. package/dist/esm/Container.d.ts +132 -0
  254. package/dist/esm/Container.d.ts.map +1 -0
  255. package/dist/esm/Container.js +151 -0
  256. package/dist/esm/Container.js.map +1 -0
  257. package/dist/esm/Edit.d.ts +203 -0
  258. package/dist/esm/Edit.d.ts.map +1 -0
  259. package/dist/esm/Edit.js +296 -0
  260. package/dist/esm/Edit.js.map +1 -0
  261. package/dist/esm/ExaWebSearch.d.ts +22 -0
  262. package/dist/esm/ExaWebSearch.d.ts.map +1 -0
  263. package/dist/esm/ExaWebSearch.js +107 -0
  264. package/dist/esm/ExaWebSearch.js.map +1 -0
  265. package/dist/esm/Explore.d.ts +328 -0
  266. package/dist/esm/Explore.d.ts.map +1 -0
  267. package/dist/esm/Explore.js +106 -0
  268. package/dist/esm/Explore.js.map +1 -0
  269. package/dist/esm/Fetch.d.ts +130 -0
  270. package/dist/esm/Fetch.d.ts.map +1 -0
  271. package/dist/esm/Fetch.js +91 -0
  272. package/dist/esm/Fetch.js.map +1 -0
  273. package/dist/esm/Glob.d.ts +204 -0
  274. package/dist/esm/Glob.d.ts.map +1 -0
  275. package/dist/esm/Glob.js +177 -0
  276. package/dist/esm/Glob.js.map +1 -0
  277. package/dist/esm/Grep.d.ts +347 -0
  278. package/dist/esm/Grep.d.ts.map +1 -0
  279. package/dist/esm/Grep.js +289 -0
  280. package/dist/esm/Grep.js.map +1 -0
  281. package/dist/esm/HttpPost.d.ts +130 -0
  282. package/dist/esm/HttpPost.d.ts.map +1 -0
  283. package/dist/esm/HttpPost.js +89 -0
  284. package/dist/esm/HttpPost.js.map +1 -0
  285. package/dist/esm/LanguageServer.d.ts +90 -0
  286. package/dist/esm/LanguageServer.d.ts.map +1 -0
  287. package/dist/esm/LanguageServer.js +57 -0
  288. package/dist/esm/LanguageServer.js.map +1 -0
  289. package/dist/esm/Ls.d.ts +164 -0
  290. package/dist/esm/Ls.d.ts.map +1 -0
  291. package/dist/esm/Ls.js +178 -0
  292. package/dist/esm/Ls.js.map +1 -0
  293. package/dist/esm/Lsp.d.ts +125 -0
  294. package/dist/esm/Lsp.d.ts.map +1 -0
  295. package/dist/esm/Lsp.js +165 -0
  296. package/dist/esm/Lsp.js.map +1 -0
  297. package/dist/esm/Manifest.d.ts +918 -0
  298. package/dist/esm/Manifest.d.ts.map +1 -0
  299. package/dist/esm/Manifest.js +153 -0
  300. package/dist/esm/Manifest.js.map +1 -0
  301. package/dist/esm/NativeSearch.d.ts +38 -0
  302. package/dist/esm/NativeSearch.d.ts.map +1 -0
  303. package/dist/esm/NativeSearch.js +378 -0
  304. package/dist/esm/NativeSearch.js.map +1 -0
  305. package/dist/esm/NodeLanguageServer.d.ts +128 -0
  306. package/dist/esm/NodeLanguageServer.d.ts.map +1 -0
  307. package/dist/esm/NodeLanguageServer.js +843 -0
  308. package/dist/esm/NodeLanguageServer.js.map +1 -0
  309. package/dist/esm/PortableSearch.d.ts +24 -0
  310. package/dist/esm/PortableSearch.d.ts.map +1 -0
  311. package/dist/esm/PortableSearch.js +240 -0
  312. package/dist/esm/PortableSearch.js.map +1 -0
  313. package/dist/esm/Probe.d.ts +193 -0
  314. package/dist/esm/Probe.d.ts.map +1 -0
  315. package/dist/esm/Probe.js +225 -0
  316. package/dist/esm/Probe.js.map +1 -0
  317. package/dist/esm/Read.d.ts +189 -0
  318. package/dist/esm/Read.d.ts.map +1 -0
  319. package/dist/esm/Read.js +300 -0
  320. package/dist/esm/Read.js.map +1 -0
  321. package/dist/esm/Relocate.d.ts +73 -0
  322. package/dist/esm/Relocate.d.ts.map +1 -0
  323. package/dist/esm/Relocate.js +153 -0
  324. package/dist/esm/Relocate.js.map +1 -0
  325. package/dist/esm/Search.d.ts +163 -0
  326. package/dist/esm/Search.d.ts.map +1 -0
  327. package/dist/esm/Search.js +47 -0
  328. package/dist/esm/Search.js.map +1 -0
  329. package/dist/esm/SearchConformance.d.ts +115 -0
  330. package/dist/esm/SearchConformance.d.ts.map +1 -0
  331. package/dist/esm/SearchConformance.js +193 -0
  332. package/dist/esm/SearchConformance.js.map +1 -0
  333. package/dist/esm/SearchContract.d.ts +114 -0
  334. package/dist/esm/SearchContract.d.ts.map +1 -0
  335. package/dist/esm/SearchContract.js +461 -0
  336. package/dist/esm/SearchContract.js.map +1 -0
  337. package/dist/esm/ShellCommand.d.ts +164 -0
  338. package/dist/esm/ShellCommand.d.ts.map +1 -0
  339. package/dist/esm/ShellCommand.js +159 -0
  340. package/dist/esm/ShellCommand.js.map +1 -0
  341. package/dist/esm/StdError.d.ts +55 -0
  342. package/dist/esm/StdError.d.ts.map +1 -0
  343. package/dist/esm/StdError.js +71 -0
  344. package/dist/esm/StdError.js.map +1 -0
  345. package/dist/esm/TestRun.d.ts +311 -0
  346. package/dist/esm/TestRun.d.ts.map +1 -0
  347. package/dist/esm/TestRun.js +316 -0
  348. package/dist/esm/TestRun.js.map +1 -0
  349. package/dist/esm/TestRunner.d.ts +102 -0
  350. package/dist/esm/TestRunner.d.ts.map +1 -0
  351. package/dist/esm/TestRunner.js +68 -0
  352. package/dist/esm/TestRunner.js.map +1 -0
  353. package/dist/esm/TreeFingerprint.d.ts +140 -0
  354. package/dist/esm/TreeFingerprint.d.ts.map +1 -0
  355. package/dist/esm/TreeFingerprint.js +170 -0
  356. package/dist/esm/TreeFingerprint.js.map +1 -0
  357. package/dist/esm/UpdatePlan.d.ts +152 -0
  358. package/dist/esm/UpdatePlan.d.ts.map +1 -0
  359. package/dist/esm/UpdatePlan.js +129 -0
  360. package/dist/esm/UpdatePlan.js.map +1 -0
  361. package/dist/esm/WebFetch.d.ts +134 -0
  362. package/dist/esm/WebFetch.d.ts.map +1 -0
  363. package/dist/esm/WebFetch.js +151 -0
  364. package/dist/esm/WebFetch.js.map +1 -0
  365. package/dist/esm/WebSearch.d.ts +181 -0
  366. package/dist/esm/WebSearch.d.ts.map +1 -0
  367. package/dist/esm/WebSearch.js +134 -0
  368. package/dist/esm/WebSearch.js.map +1 -0
  369. package/dist/esm/Write.d.ts +147 -0
  370. package/dist/esm/Write.d.ts.map +1 -0
  371. package/dist/esm/Write.js +144 -0
  372. package/dist/esm/Write.js.map +1 -0
  373. package/dist/esm/index.d.ts +127 -0
  374. package/dist/esm/index.d.ts.map +1 -0
  375. package/dist/esm/index.js +127 -0
  376. package/dist/esm/index.js.map +1 -0
  377. package/dist/esm/internal/ApplyPatch.d.ts +145 -0
  378. package/dist/esm/internal/ApplyPatch.d.ts.map +1 -0
  379. package/dist/esm/internal/ApplyPatch.js +489 -0
  380. package/dist/esm/internal/ApplyPatch.js.map +1 -0
  381. package/dist/esm/internal/CodexText.d.ts +73 -0
  382. package/dist/esm/internal/CodexText.d.ts.map +1 -0
  383. package/dist/esm/internal/CodexText.js +156 -0
  384. package/dist/esm/internal/CodexText.js.map +1 -0
  385. package/dist/esm/internal/Declaration.d.ts +49 -0
  386. package/dist/esm/internal/Declaration.d.ts.map +1 -0
  387. package/dist/esm/internal/Declaration.js +42 -0
  388. package/dist/esm/internal/Declaration.js.map +1 -0
  389. package/dist/esm/internal/Diagnostics.d.ts +77 -0
  390. package/dist/esm/internal/Diagnostics.d.ts.map +1 -0
  391. package/dist/esm/internal/Diagnostics.js +99 -0
  392. package/dist/esm/internal/Diagnostics.js.map +1 -0
  393. package/dist/esm/internal/EnvelopePrecheck.d.ts +67 -0
  394. package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -0
  395. package/dist/esm/internal/EnvelopePrecheck.js +167 -0
  396. package/dist/esm/internal/EnvelopePrecheck.js.map +1 -0
  397. package/dist/esm/internal/Exec.d.ts +139 -0
  398. package/dist/esm/internal/Exec.d.ts.map +1 -0
  399. package/dist/esm/internal/Exec.js +193 -0
  400. package/dist/esm/internal/Exec.js.map +1 -0
  401. package/dist/esm/internal/FileMutation.d.ts +109 -0
  402. package/dist/esm/internal/FileMutation.d.ts.map +1 -0
  403. package/dist/esm/internal/FileMutation.js +123 -0
  404. package/dist/esm/internal/FileMutation.js.map +1 -0
  405. package/dist/esm/internal/FsFailure.d.ts +38 -0
  406. package/dist/esm/internal/FsFailure.d.ts.map +1 -0
  407. package/dist/esm/internal/FsFailure.js +39 -0
  408. package/dist/esm/internal/FsFailure.js.map +1 -0
  409. package/dist/esm/internal/GitWorktree.d.ts +98 -0
  410. package/dist/esm/internal/GitWorktree.d.ts.map +1 -0
  411. package/dist/esm/internal/GitWorktree.js +345 -0
  412. package/dist/esm/internal/GitWorktree.js.map +1 -0
  413. package/dist/esm/internal/Grouping.d.ts +51 -0
  414. package/dist/esm/internal/Grouping.d.ts.map +1 -0
  415. package/dist/esm/internal/Grouping.js +99 -0
  416. package/dist/esm/internal/Grouping.js.map +1 -0
  417. package/dist/esm/internal/Html.d.ts +20 -0
  418. package/dist/esm/internal/Html.d.ts.map +1 -0
  419. package/dist/esm/internal/Html.js +70 -0
  420. package/dist/esm/internal/Html.js.map +1 -0
  421. package/dist/esm/internal/Http.d.ts +95 -0
  422. package/dist/esm/internal/Http.d.ts.map +1 -0
  423. package/dist/esm/internal/Http.js +154 -0
  424. package/dist/esm/internal/Http.js.map +1 -0
  425. package/dist/esm/internal/HttpNetwork.d.ts +27 -0
  426. package/dist/esm/internal/HttpNetwork.d.ts.map +1 -0
  427. package/dist/esm/internal/HttpNetwork.js +114 -0
  428. package/dist/esm/internal/HttpNetwork.js.map +1 -0
  429. package/dist/esm/internal/Ignore.d.ts +37 -0
  430. package/dist/esm/internal/Ignore.d.ts.map +1 -0
  431. package/dist/esm/internal/Ignore.js +128 -0
  432. package/dist/esm/internal/Ignore.js.map +1 -0
  433. package/dist/esm/internal/LinearRegex.d.ts +19 -0
  434. package/dist/esm/internal/LinearRegex.d.ts.map +1 -0
  435. package/dist/esm/internal/LinearRegex.js +176 -0
  436. package/dist/esm/internal/LinearRegex.js.map +1 -0
  437. package/dist/esm/internal/Match.d.ts +85 -0
  438. package/dist/esm/internal/Match.d.ts.map +1 -0
  439. package/dist/esm/internal/Match.js +142 -0
  440. package/dist/esm/internal/Match.js.map +1 -0
  441. package/dist/esm/internal/Paths.d.ts +23 -0
  442. package/dist/esm/internal/Paths.d.ts.map +1 -0
  443. package/dist/esm/internal/Paths.js +40 -0
  444. package/dist/esm/internal/Paths.js.map +1 -0
  445. package/dist/esm/internal/Preserve.d.ts +25 -0
  446. package/dist/esm/internal/Preserve.d.ts.map +1 -0
  447. package/dist/esm/internal/Preserve.js +70 -0
  448. package/dist/esm/internal/Preserve.js.map +1 -0
  449. package/dist/esm/internal/Prune.d.ts +35 -0
  450. package/dist/esm/internal/Prune.d.ts.map +1 -0
  451. package/dist/esm/internal/Prune.js +60 -0
  452. package/dist/esm/internal/Prune.js.map +1 -0
  453. package/dist/esm/internal/SearchContract.d.ts +63 -0
  454. package/dist/esm/internal/SearchContract.d.ts.map +1 -0
  455. package/dist/esm/internal/SearchContract.js +66 -0
  456. package/dist/esm/internal/SearchContract.js.map +1 -0
  457. package/dist/esm/internal/Symbols.d.ts +39 -0
  458. package/dist/esm/internal/Symbols.d.ts.map +1 -0
  459. package/dist/esm/internal/Symbols.js +79 -0
  460. package/dist/esm/internal/Symbols.js.map +1 -0
  461. package/dist/esm/internal/TestReport.d.ts +52 -0
  462. package/dist/esm/internal/TestReport.d.ts.map +1 -0
  463. package/dist/esm/internal/TestReport.js +172 -0
  464. package/dist/esm/internal/TestReport.js.map +1 -0
  465. package/dist/esm/internal/Text.d.ts +114 -0
  466. package/dist/esm/internal/Text.d.ts.map +1 -0
  467. package/dist/esm/internal/Text.js +130 -0
  468. package/dist/esm/internal/Text.js.map +1 -0
  469. package/dist/esm/internal/Url.d.ts +13 -0
  470. package/dist/esm/internal/Url.d.ts.map +1 -0
  471. package/dist/esm/internal/Url.js +27 -0
  472. package/dist/esm/internal/Url.js.map +1 -0
  473. package/dist/esm/internal/Walk.d.ts +72 -0
  474. package/dist/esm/internal/Walk.d.ts.map +1 -0
  475. package/dist/esm/internal/Walk.js +126 -0
  476. package/dist/esm/internal/Walk.js.map +1 -0
  477. package/docs/README.md +117 -0
  478. package/docs/api.md +472 -0
  479. package/docs/concepts/effects-and-capabilities.md +136 -0
  480. package/docs/concepts/flows-and-handlers.md +115 -0
  481. package/docs/concepts/limits-and-disclosure.md +102 -0
  482. package/docs/concepts/search-contract.md +182 -0
  483. package/docs/guides/bind-the-standard-flows.md +114 -0
  484. package/docs/guides/implement-a-search-peer.md +133 -0
  485. package/docs/guides/pin-a-checkpoint.md +141 -0
  486. package/docs/guides/query-a-language-server.md +257 -0
  487. package/docs/guides/reach-the-network.md +141 -0
  488. package/docs/guides/read-and-edit-a-file.md +240 -0
  489. package/docs/guides/run-a-shell-command.md +215 -0
  490. package/docs/guides/run-the-test-suite.md +154 -0
  491. package/docs/guides/search-a-workspace.md +148 -0
  492. package/docs/installation.md +111 -0
  493. package/docs/quickstart.md +125 -0
  494. package/docs/reference/flows.md +556 -0
  495. package/docs/troubleshooting.md +322 -0
  496. package/package.json +439 -3
  497. package/src/ApplyPatch.ts +458 -0
  498. package/src/Bash.ts +549 -0
  499. package/src/Checkpoints.ts +422 -0
  500. package/src/Container.ts +212 -0
  501. package/src/Edit.ts +366 -0
  502. package/src/ExaWebSearch.ts +145 -0
  503. package/src/Explore.ts +139 -0
  504. package/src/Fetch.ts +117 -0
  505. package/src/Glob.ts +200 -0
  506. package/src/Grep.ts +320 -0
  507. package/src/HttpPost.ts +120 -0
  508. package/src/LanguageServer.ts +110 -0
  509. package/src/Ls.ts +228 -0
  510. package/src/Lsp.ts +184 -0
  511. package/src/Manifest.ts +162 -0
  512. package/src/NativeSearch.ts +457 -0
  513. package/src/NodeLanguageServer.ts +1148 -0
  514. package/src/PortableSearch.ts +264 -0
  515. package/src/Probe.ts +284 -0
  516. package/src/Read.ts +359 -0
  517. package/src/Relocate.ts +166 -0
  518. package/src/Search.ts +185 -0
  519. package/src/SearchConformance.ts +288 -0
  520. package/src/SearchContract.ts +489 -0
  521. package/src/ShellCommand.ts +201 -0
  522. package/src/StdError.ts +80 -0
  523. package/src/TestRun.ts +401 -0
  524. package/src/TestRunner.ts +119 -0
  525. package/src/TreeFingerprint.ts +200 -0
  526. package/src/UpdatePlan.ts +171 -0
  527. package/src/WebFetch.ts +194 -0
  528. package/src/WebSearch.ts +165 -0
  529. package/src/Write.ts +195 -0
  530. package/src/index.ts +154 -0
  531. package/src/internal/ApplyPatch.ts +601 -0
  532. package/src/internal/CodexText.ts +182 -0
  533. package/src/internal/Declaration.ts +60 -0
  534. package/src/internal/Diagnostics.ts +134 -0
  535. package/src/internal/EnvelopePrecheck.ts +233 -0
  536. package/src/internal/Exec.ts +314 -0
  537. package/src/internal/FileMutation.ts +231 -0
  538. package/src/internal/FsFailure.ts +51 -0
  539. package/src/internal/GitWorktree.ts +473 -0
  540. package/src/internal/Grouping.ts +106 -0
  541. package/src/internal/Html.ts +87 -0
  542. package/src/internal/Http.ts +209 -0
  543. package/src/internal/HttpNetwork.ts +153 -0
  544. package/src/internal/Ignore.ts +135 -0
  545. package/src/internal/LinearRegex.ts +173 -0
  546. package/src/internal/Match.ts +172 -0
  547. package/src/internal/Paths.ts +42 -0
  548. package/src/internal/Preserve.ts +108 -0
  549. package/src/internal/Prune.ts +62 -0
  550. package/src/internal/SearchContract.ts +77 -0
  551. package/src/internal/Symbols.ts +88 -0
  552. package/src/internal/TestReport.ts +194 -0
  553. package/src/internal/Text.ts +170 -0
  554. package/src/internal/Url.ts +23 -0
  555. package/src/internal/Walk.ts +176 -0
@@ -0,0 +1,473 @@
1
+ /**
2
+ * Detached checkouts shared by checkpoint reads and baseline test runs.
3
+ *
4
+ * ## Host git never reads a file the agent can write that names a program
5
+ *
6
+ * The repository is the workspace's, and an agent can write its `.git`: a
7
+ * containerised agent writes it through the bind mount. Git reads programs out
8
+ * of that directory in more places than any list of `-c` overrides can close.
9
+ * Hooks and `core.fsmonitor` can be overridden, but a filter driver
10
+ * (`filter.<name>.clean`/`.smudge` in `.git/config`, selected by
11
+ * `.git/info/attributes`) cannot: git has no switch that ignores repository
12
+ * config or `$GIT_DIR/info/attributes`, and overriding each driver by name
13
+ * races an agent that keeps rewriting the file.
14
+ *
15
+ * So the git that records and checks out trees runs against a **shadow**
16
+ * `GIT_DIR`: a bare repository this module creates under the host's temporary
17
+ * directory for one operation and deletes afterwards. Its config, hooks and
18
+ * `info/attributes` are the ones `git init --template=` writes, which is none.
19
+ * `GIT_CONFIG_NOSYSTEM` and `GIT_CONFIG_GLOBAL=/dev/null` drop the host's own
20
+ * config files too, so the only settings are the ones on the command line.
21
+ * `GIT_OBJECT_DIRECTORY` points at the workspace's object store, because objects
22
+ * are data: git hashes and inflates them and never runs anything they say.
23
+ *
24
+ * What still touches the workspace repository is plain data:
25
+ *
26
+ * - `rev-parse` in the workspace, which resolves refs and paths and runs no
27
+ * hook, filter, fsmonitor or other configured program;
28
+ * - `git config --file <workspace config>`, which reads or writes that one file
29
+ * and follows no `include`;
30
+ * - a copy of the workspace index into the shadow, so the recorded tree holds
31
+ * what the agent staged without the harness writing the agent's index; and
32
+ * - a handful of `core.*` settings that change how bytes are hashed
33
+ * ({@link dataSettings}), each accepted only as a bare word.
34
+ *
35
+ * A materialized checkout gets its own standalone `.git`, written by this
36
+ * module as files, so a container can still run git in it: `HEAD` names the
37
+ * commit, `objects/info/alternates` points back at the workspace's objects by a
38
+ * relative path, and `index` is the one the checkout was written from. Host git
39
+ * never uses that directory; it is the container's.
40
+ *
41
+ * @since 1.0.0
42
+ */
43
+
44
+ import type { ChildProcessSpawner } from "@smthrs/kernel/ChildProcessSpawner"
45
+ import { Effect } from "effect"
46
+ import * as StdError from "../StdError.ts"
47
+ import * as Exec from "./Exec.ts"
48
+
49
+ const failed = (message: string, code: StdError.Code = "command_failed") => new StdError.StdError({ code, message })
50
+
51
+ /**
52
+ * Settings that stop the workspace repository from naming a program for the
53
+ * `rev-parse` this module runs in it. `rev-parse` runs none of them; these keep
54
+ * that true if a later call is added beside it.
55
+ */
56
+ const hostGitSettings = ["-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false"] as const
57
+
58
+ /** Host config files git would otherwise read, removed from every shadow command. */
59
+ const isolated = { GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: "/dev/null" } as const
60
+
61
+ /**
62
+ * Workspace settings that change how a tree is hashed or compared, carried
63
+ * onto the shadow so a checkpoint records what the agent's own git would.
64
+ * None of them names a program.
65
+ */
66
+ const dataSettings = /^core\.(autocrlf|eol|safecrlf|filemode|symlinks|ignorecase|precomposeunicode)$/
67
+
68
+ /** A setting value this module will repeat to git: a bare word, never a command. */
69
+ const bareWord = /^[A-Za-z0-9_-]+$/
70
+
71
+ const run = (command: string, args: ReadonlyArray<string>, env?: Readonly<Record<string, string>>) =>
72
+ Exec.exec(command, { args, ...(env === undefined ? {} : { env }) }).pipe(
73
+ Effect.mapError((error) => failed(`${command} could not run: ${error.message}`))
74
+ )
75
+
76
+ /**
77
+ * Runs host git in the workspace at `root`, for `rev-parse` only.
78
+ *
79
+ * @category utilities
80
+ * @since 1.0.0
81
+ */
82
+ const git = (root: string, args: ReadonlyArray<string>) => run("git", [...hostGitSettings, "-C", root, ...args])
83
+
84
+ const resolveCommit = (root: string, refs: ReadonlyArray<string>) =>
85
+ Effect.gen(function*() {
86
+ for (const ref of refs) {
87
+ const answer = yield* git(root, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`])
88
+ const commit = answer.stdout.trim()
89
+ if (answer.exitCode === 0 && commit !== "") return { ref, commit }
90
+ }
91
+ return yield* Effect.fail(failed(`No commit resolves from ${refs.join(" or ")} in ${root}.`, "not_found"))
92
+ })
93
+
94
+ /**
95
+ * Where one workspace repository keeps what the shadow needs, as its own git
96
+ * reports it.
97
+ *
98
+ * @category models
99
+ * @since 1.0.0
100
+ */
101
+ export interface Repository {
102
+ /** The root the caller named, without a trailing slash. */
103
+ readonly root: string
104
+ /** The same directory, as git canonicalizes it. */
105
+ readonly toplevel: string
106
+ /** The common git directory, which holds config and objects. */
107
+ readonly common: string
108
+ /** The workspace index. */
109
+ readonly index: string
110
+ readonly objectFormat: string
111
+ /** {@link dataSettings} as `-c` arguments. */
112
+ readonly settings: ReadonlyArray<string>
113
+ }
114
+
115
+ /**
116
+ * Reads or writes the workspace's config file as a file, never as a repository.
117
+ *
118
+ * `--git-dir=/dev/null` stops git discovering any repository around the host's
119
+ * working directory, and `--file` reads the one file without `include`s.
120
+ *
121
+ * @category utilities
122
+ * @since 1.0.0
123
+ */
124
+ const config = (repository: Pick<Repository, "common">, args: ReadonlyArray<string>) =>
125
+ run("git", ["--git-dir=/dev/null", "config", "--file", `${repository.common}/config`, ...args], isolated)
126
+
127
+ const open = (root: string): Effect.Effect<Repository, StdError.StdError, ChildProcessSpawner> =>
128
+ Effect.gen(function*() {
129
+ const stripped = root.replace(/\/+$/, "")
130
+ const answer = yield* git(stripped, [
131
+ "rev-parse",
132
+ "--path-format=absolute",
133
+ "--show-toplevel",
134
+ "--git-common-dir",
135
+ "--git-path",
136
+ "index",
137
+ "--show-object-format"
138
+ ])
139
+ const [toplevel, common, index, objectFormat] = answer.stdout.split("\n").map((line) => line.trim())
140
+ if (
141
+ answer.exitCode !== 0 || toplevel === undefined || toplevel === "" || common === undefined || common === "" ||
142
+ index === undefined || index === "" || objectFormat === undefined || !bareWord.test(objectFormat)
143
+ ) {
144
+ return yield* Effect.fail(failed(`${stripped} is not a git work tree: ${answer.stderr.trim()}`))
145
+ }
146
+ const found = yield* config({ common }, ["--get-regexp", dataSettings.source])
147
+ const settings = found.exitCode === 0
148
+ ? found.stdout.split("\n").flatMap((line) => {
149
+ const [key, value] = line.trim().split(/\s+/)
150
+ return key !== undefined && value !== undefined && dataSettings.test(key) && bareWord.test(value)
151
+ ? ["-c", `${key}=${value}`]
152
+ : []
153
+ })
154
+ : []
155
+ return { root: stripped, toplevel, common, index, objectFormat, settings }
156
+ })
157
+
158
+ const temporaryRoot = (): string => {
159
+ const configured = globalThis.process?.env?.TMPDIR?.replace(/\/+$/, "")
160
+ return configured === undefined || configured === "" ? "/tmp" : configured
161
+ }
162
+
163
+ const remove = (path: string) =>
164
+ run("rm", ["-rf", "--", path]).pipe(
165
+ Effect.flatMap((removed) => removed.exitCode === 0 ? Effect.void : Effect.fail(failed(removed.stderr.trim())))
166
+ )
167
+
168
+ /**
169
+ * A harness-owned `GIT_DIR` over one workspace's objects.
170
+ *
171
+ * @category models
172
+ * @since 1.0.0
173
+ */
174
+ export interface Shadow {
175
+ readonly path: string
176
+ readonly repository: Repository
177
+ /** Runs host git with the shadow as `GIT_DIR`, and `workTree` as its work tree when given. */
178
+ readonly git: (
179
+ args: ReadonlyArray<string>,
180
+ workTree?: string
181
+ ) => Effect.Effect<Exec.ExecResult, StdError.StdError, ChildProcessSpawner>
182
+ /** Copies the workspace index into the shadow, so the shadow never writes the agent's own. */
183
+ readonly adoptIndex: Effect.Effect<void, StdError.StdError, ChildProcessSpawner>
184
+ }
185
+
186
+ const shadowOf = (repository: Repository, path: string): Shadow => ({
187
+ path,
188
+ repository,
189
+ git: (args, workTree) =>
190
+ run(
191
+ "git",
192
+ [
193
+ `--git-dir=${path}`,
194
+ ...(workTree === undefined ? [] : [`--work-tree=${workTree}`]),
195
+ ...hostGitSettings,
196
+ ...repository.settings,
197
+ ...args
198
+ ],
199
+ { ...isolated, GIT_OBJECT_DIRECTORY: `${repository.common}/objects` }
200
+ ),
201
+ adoptIndex: run("sh", [
202
+ "-c",
203
+ "set -C; if [ -e \"$1\" ]; then cat -- \"$1\" > \"$2\"; fi",
204
+ "sh",
205
+ repository.index,
206
+ `${path}/index`
207
+ ]).pipe(
208
+ Effect.flatMap((copied) =>
209
+ copied.exitCode === 0
210
+ ? Effect.void
211
+ : Effect.fail(failed(`Could not read the workspace index: ${copied.stderr.trim()}`))
212
+ )
213
+ )
214
+ })
215
+
216
+ /**
217
+ * Runs `use` with a fresh {@link Shadow} over the repository at `root`, and
218
+ * deletes the shadow however `use` ends.
219
+ *
220
+ * @category utilities
221
+ * @since 1.0.0
222
+ */
223
+ const withShadow = <A, E, R>(
224
+ root: string | Repository,
225
+ use: (shadow: Shadow) => Effect.Effect<A, E, R>
226
+ ): Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner> =>
227
+ Effect.gen(function*() {
228
+ const repository = typeof root === "string" ? yield* open(root) : root
229
+ const path = `${temporaryRoot()}/smithers-git-${globalThis.crypto.randomUUID()}`
230
+ return yield* Effect.acquireUseRelease(
231
+ Effect.succeed(path),
232
+ () =>
233
+ Effect.gen(function*() {
234
+ const created = yield* run(
235
+ "git",
236
+ ["init", "--quiet", "--bare", "--template=", `--object-format=${repository.objectFormat}`, path],
237
+ isolated
238
+ )
239
+ if (created.exitCode !== 0) {
240
+ return yield* Effect.fail(failed(`Could not create a shadow repository: ${created.stderr.trim()}`))
241
+ }
242
+ return yield* use(shadowOf(repository, path))
243
+ }),
244
+ () =>
245
+ remove(path).pipe(
246
+ Effect.catch((error) =>
247
+ Effect.logWarning("could not remove a shadow repository").pipe(
248
+ Effect.annotateLogs({ path, reason: error.message })
249
+ )
250
+ )
251
+ )
252
+ )
253
+ })
254
+
255
+ /** `to` relative to `from`, both absolute POSIX paths. */
256
+ const relative = (from: string, to: string): string => {
257
+ const source = from.split("/").filter((part) => part !== "")
258
+ const target = to.split("/").filter((part) => part !== "")
259
+ let shared = 0
260
+ while (shared < source.length && shared < target.length && source[shared] === target[shared]) shared++
261
+ return [...source.slice(shared).map(() => ".."), ...target.slice(shared)].join("/") || "."
262
+ }
263
+
264
+ /**
265
+ * The config of a checkout's own `.git`, for the container's git.
266
+ *
267
+ * Only {@link dataSettings}, already restricted to bare words, reach it.
268
+ */
269
+ const checkoutConfig = (repository: Repository): string => {
270
+ const sha1 = repository.objectFormat === "sha1"
271
+ const lines = [
272
+ "[core]",
273
+ `\trepositoryformatversion = ${sha1 ? 0 : 1}`,
274
+ "\tbare = false",
275
+ ...repository.settings.filter((_, index) => index % 2 === 1).map((setting) => {
276
+ const [key, value] = setting.split("=")
277
+ return `\t${key?.slice("core.".length)} = ${value}`
278
+ }),
279
+ ...(sha1 ? [] : ["[extensions]", `\tobjectformat = ${repository.objectFormat}`])
280
+ ]
281
+ return `${lines.join("\n")}\n`
282
+ }
283
+
284
+ /** Fails with `message` and the command's stderr unless it exited 0. */
285
+ const succeeded = (result: Exec.ExecResult, message: string) =>
286
+ result.exitCode === 0 ? Effect.void : Effect.fail(failed(`${message}: ${result.stderr.trim()}`))
287
+
288
+ /**
289
+ * Measures which staging directory shares the filesystem of the checkout's
290
+ * parent `$1`: the shadow `$2`, the workspace root's parent `$3`, or the host
291
+ * cache directory `$4`. Prints one line each for the parent, the shadow, the
292
+ * root's parent (`unwritable` when the host user cannot create a stage there)
293
+ * and the cache (empty unless both others missed and it could be created).
294
+ * `stat -c` is GNU and BusyBox, `stat -f` is BSD; an empty line means neither
295
+ * answered.
296
+ */
297
+ const measure = [
298
+ "set -e",
299
+ "mkdir -p -- \"$1\"",
300
+ "dev() { stat -c %d -- \"$1\" 2>/dev/null || stat -f %d -- \"$1\" 2>/dev/null || echo; }",
301
+ "t=$(dev \"$1\")",
302
+ "s=$(dev \"$2\")",
303
+ "if [ -w \"$3\" ]; then b=$(dev \"$3\"); else b=unwritable; fi",
304
+ "c=",
305
+ "if [ -n \"$t\" ] && [ \"$t\" != \"$s\" ] && [ \"$t\" != \"$b\" ] && [ -n \"$4\" ] && mkdir -p -m 700 -- \"$4\" 2>/dev/null; then c=$(dev \"$4\"); fi",
306
+ "printf '%s\\n' \"$t\" \"$s\" \"$b\" \"$c\""
307
+ ].join("; ")
308
+
309
+ /**
310
+ * The host user's cache directory for checkout stages: `$XDG_CACHE_HOME`, or
311
+ * `~/.cache`, under `smithers`. Empty when neither is an absolute path.
312
+ */
313
+ const cacheRoot = (): string => {
314
+ const env = globalThis.process?.env
315
+ const xdg = env?.XDG_CACHE_HOME?.replace(/\/+$/, "")
316
+ if (xdg !== undefined && xdg.startsWith("/")) return `${xdg}/smithers`
317
+ const home = env?.HOME?.replace(/\/+$/, "")
318
+ return home !== undefined && home.startsWith("/") ? `${home}/.cache/smithers` : ""
319
+ }
320
+
321
+ /**
322
+ * Moves the staged checkout `$1` into the directory `$2` under the name `$3`
323
+ * in one `rename`, then proves the directory there is the one that was staged.
324
+ * The staging directory is on the same filesystem, so `mv` renames and never
325
+ * copies.
326
+ *
327
+ * The shell first enters `$2` by its physical path and refuses unless that
328
+ * lies under the real path of the workspace root `$4`. The rename then names
329
+ * the target relative to that directory, so a parent the agent swaps for a
330
+ * symlink, before or after the check, cannot carry the checkout out of the
331
+ * workspace.
332
+ */
333
+ const publish = [
334
+ "set -e",
335
+ "root=$(cd -P -- \"$4\" && pwd -P)",
336
+ "cd -P -- \"$2\"",
337
+ "here=$(pwd -P)",
338
+ "case \"$here\" in \"$root\"|\"$root\"/*) ;; *) echo \"$2 resolves to $here, outside the workspace $root\" >&2; exit 1 ;; esac",
339
+ "if [ -e \"./$3\" ] || [ -L \"./$3\" ]; then echo \"$2/$3 already exists\" >&2; exit 1; fi",
340
+ "staged=$(ls -di -- \"$1\" | awk '{print $1}')",
341
+ "mv -- \"$1\" \"./$3\"",
342
+ "if [ -L \"./$3\" ] || [ ! -d \"./$3\" ]; then echo \"$2/$3 was replaced while it was written\" >&2; exit 1; fi",
343
+ "moved=$(ls -di -- \"./$3\" | awk '{print $1}')",
344
+ "if [ \"$staged\" != \"$moved\" ]; then echo \"$2/$3 was replaced while it was written\" >&2; exit 1; fi"
345
+ ].join("; ")
346
+
347
+ /**
348
+ * Checks `commit`'s tree out at the new directory `host`, with a standalone
349
+ * `.git` the container's git can use.
350
+ *
351
+ * Host git never writes into an agent-writable directory. The tree and its
352
+ * `.git` are written into a staging directory the agent cannot reach: inside
353
+ * the shadow, or, when the host's temporary directory is another filesystem,
354
+ * beside the workspace root or under the host user's cache directory. One
355
+ * `rename` then gives the finished directory its name under the workspace. A
356
+ * path the agent swaps for a symlink cannot redirect a write: a symlink at
357
+ * `host` fails the call before the rename, and a parent that resolves outside
358
+ * the workspace root fails it before the rename too.
359
+ */
360
+ const checkout = (shadow: Shadow, host: string, commit: string) =>
361
+ Effect.gen(function*() {
362
+ const repository = shadow.repository
363
+ const parent = host.slice(0, host.lastIndexOf("/"))
364
+ const name = host.slice(host.lastIndexOf("/") + 1)
365
+ const beside = repository.root.slice(0, repository.root.lastIndexOf("/")) || "/"
366
+ const cache = cacheRoot()
367
+ const stage = `checkout-${globalThis.crypto.randomUUID()}`
368
+ const besideStage = `${beside.replace(/\/+$/, "")}/.smithers-${stage}`
369
+ const cacheStage = `${cache}/${stage}`
370
+ const measured = yield* run("sh", ["-c", measure, "sh", parent, shadow.path, beside, cache])
371
+ yield* succeeded(measured, `Could not check out ${commit}`)
372
+ const [target, inShadow, besideRoot, inCache] = measured.stdout.split("\n").map((line) => line.trim())
373
+ const scratch = target === undefined || target === "" || target === inShadow
374
+ ? undefined
375
+ : target === besideRoot
376
+ ? besideStage
377
+ : target === inCache
378
+ ? cacheStage
379
+ : undefined
380
+ const base = target === undefined || target === ""
381
+ ? undefined
382
+ : target === inShadow
383
+ ? shadow.path
384
+ : scratch
385
+ if (base === undefined) {
386
+ const unwritable = besideRoot === "unwritable" ? " (not writable by this user)" : ""
387
+ return yield* Effect.fail(
388
+ failed(
389
+ `Could not check out ${commit}: neither ${shadow.path} nor ${beside}${unwritable} nor ${
390
+ cache === "" ? "a cache directory" : cache
391
+ } is on the filesystem of ${parent}`
392
+ )
393
+ )
394
+ }
395
+ const staged = `${base}/${name}`
396
+ const objects = relative(
397
+ `${repository.toplevel}${host.slice(repository.root.length)}/.git/objects`,
398
+ `${repository.common}/objects`
399
+ )
400
+ const write = Effect.gen(function*() {
401
+ const prepared = yield* run("sh", [
402
+ "-c",
403
+ [
404
+ "set -eC",
405
+ ...(scratch !== undefined ? ["mkdir -m 700 -- \"$1\""] : []),
406
+ "mkdir -- \"$2\" \"$2/.git\" \"$2/.git/objects\" \"$2/.git/objects/info\" \"$2/.git/refs\"",
407
+ "printf '%s\\n' \"$3\" > \"$2/.git/HEAD\"",
408
+ "printf '%s\\n' \"$4\" > \"$2/.git/objects/info/alternates\"",
409
+ "printf '%s' \"$5\" > \"$2/.git/config\""
410
+ ].join("; "),
411
+ "sh",
412
+ base,
413
+ staged,
414
+ commit,
415
+ objects,
416
+ checkoutConfig(repository)
417
+ ])
418
+ yield* succeeded(prepared, `Could not check out ${commit}`)
419
+ const written = yield* shadow.git(["read-tree", "--reset", "-u", commit], staged)
420
+ yield* succeeded(written, `Could not check out ${commit}`)
421
+ const indexed = yield* run("sh", [
422
+ "-c",
423
+ "set -C; cat -- \"$1\" > \"$2\"",
424
+ "sh",
425
+ `${shadow.path}/index`,
426
+ `${staged}/.git/index`
427
+ ])
428
+ yield* succeeded(indexed, `Could not check out ${commit}`)
429
+ const moved = yield* run("sh", ["-c", publish, "sh", staged, parent, name, repository.root])
430
+ yield* succeeded(moved, `Could not check out ${commit}`)
431
+ })
432
+ return yield* scratch !== undefined
433
+ ? write.pipe(Effect.ensuring(remove(scratch).pipe(Effect.ignore)))
434
+ : write
435
+ })
436
+
437
+ const withDetachedWorktree = <A, E, R>(
438
+ root: string,
439
+ prefix: string,
440
+ commit: string,
441
+ use: (host: string) => Effect.Effect<A, E, R>
442
+ ): Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner> =>
443
+ Effect.gen(function*() {
444
+ // Allocate on execution, including when the same Effect is run twice.
445
+ // Never remove an existing checkout: another call may still be using it.
446
+ const host = `${root.replace(/\/+$/, "")}/${prefix}-${globalThis.crypto.randomUUID()}`
447
+ return yield* Effect.acquireUseRelease(
448
+ Effect.succeed(host),
449
+ () =>
450
+ Effect.gen(function*() {
451
+ yield* withShadow(root, (shadow) => checkout(shadow, host, commit))
452
+ return yield* use(host)
453
+ }),
454
+ // A checkout left behind is a stale copy of the repository inside the
455
+ // workspace. Walks prune it, but the operator must still hear about it.
456
+ () =>
457
+ remove(host).pipe(
458
+ Effect.catch((error) =>
459
+ Effect.logWarning("could not remove a scratch checkout").pipe(
460
+ Effect.annotateLogs({ path: host, reason: error.message })
461
+ )
462
+ )
463
+ )
464
+ )
465
+ })
466
+
467
+ /**
468
+ * Internal Git operations used by both checkpoint and baseline leases.
469
+ *
470
+ * @category utilities
471
+ * @since 1.0.0
472
+ */
473
+ export const GitWorktree = { config, git, open, resolveCommit, withDetachedWorktree, withShadow }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Match-centric grep results: the limit counts matches, and context rides
3
+ * inside the match it belongs to.
4
+ *
5
+ * A flat list of rows made `limit` a row budget, and a row budget can spend
6
+ * itself on context and drop the match. That is not a display detail: on
7
+ * astropy-7166 the clip dropped the match row twice and cost three frames of
8
+ * guard-bailing, because the agent could see the lines around its hit and not
9
+ * the hit. Ripgrep's own JSON groups by match for the same reason.
10
+ *
11
+ * Both peers group here rather than each in its own way, so the native and
12
+ * in-process implementations cannot drift on what a limit means or on which
13
+ * match owns a shared context line.
14
+ *
15
+ * @since 1.0.0
16
+ */
17
+
18
+ import type * as Search from "../Search.ts"
19
+ import * as Symbols from "./Symbols.ts"
20
+ import * as Text from "./Text.ts"
21
+
22
+ /**
23
+ * A file's text as the numbered lines both peers count.
24
+ *
25
+ * This is `Text.sourceLines` under the name the search peers reach for, not a
26
+ * second copy of it. There used to be two byte-identical definitions of the
27
+ * rule, one here and one in `internal/Text.ts`, and a divergence between them
28
+ * is exactly how `read` came to report one more line than `grep` for every
29
+ * file ending in a newline. One definition cannot drift from itself.
30
+ *
31
+ * @category search
32
+ * @since 1.0.0
33
+ */
34
+ export const sourceLines: (content: string) => ReadonlyArray<string> = Text.sourceLines
35
+
36
+ /** Every context line belongs to exactly one match: the nearest, earliest on a tie. */
37
+ const owner = (matches: ReadonlyArray<number>, line: number): number => {
38
+ let best = 0
39
+ let distance = Number.POSITIVE_INFINITY
40
+ for (let index = 0; index < matches.length; index++) {
41
+ const candidate = Math.abs(matches[index]! - line)
42
+ if (candidate < distance) {
43
+ best = index
44
+ distance = candidate
45
+ }
46
+ }
47
+ return best
48
+ }
49
+
50
+ /**
51
+ * Groups a peer's flat rows into matches, each carrying its own context.
52
+ *
53
+ * @category search
54
+ * @since 1.0.0
55
+ */
56
+ export const group = (
57
+ lines: ReadonlyArray<Search.GrepLine>
58
+ ): ReadonlyArray<Search.GrepMatch> => {
59
+ const byFile = new Map<string, Array<Search.GrepLine>>()
60
+ for (const line of lines) {
61
+ const existing = byFile.get(line.file)
62
+ if (existing === undefined) byFile.set(line.file, [line])
63
+ else existing.push(line)
64
+ }
65
+ const grouped: Array<Search.GrepMatch> = []
66
+ for (const [file, rows] of byFile) {
67
+ const matches = rows.filter((row) => row.kind === "match")
68
+ if (matches.length === 0) continue
69
+ const numbers = matches.map((row) => row.line)
70
+ const before = matches.map((): Array<Search.ContextLine> => [])
71
+ const after = matches.map((): Array<Search.ContextLine> => [])
72
+ for (const row of rows) {
73
+ if (row.kind !== "context") continue
74
+ const index = owner(numbers, row.line)
75
+ const bucket = row.line < numbers[index]! ? before[index]! : after[index]!
76
+ bucket.push({ line: row.line, text: row.text })
77
+ }
78
+ for (let index = 0; index < matches.length; index++) {
79
+ const row = matches[index]!
80
+ grouped.push({ file, line: row.line, text: row.text, before: before[index]!, after: after[index]! })
81
+ }
82
+ }
83
+ return grouped
84
+ }
85
+
86
+ /**
87
+ * Attaches each hit's enclosing definition, for the hits actually being
88
+ * returned.
89
+ *
90
+ * `contents` holds a matched file's lines. A peer that does not have them — the
91
+ * `rg` process reports lines, not files — reads only the files whose hits
92
+ * survived the limit, so the cost is bounded by what the caller receives rather
93
+ * than by what the search covered.
94
+ *
95
+ * @category search
96
+ * @since 1.0.0
97
+ */
98
+ export const annotate = (
99
+ matches: ReadonlyArray<Search.GrepMatch>,
100
+ contents: ReadonlyMap<string, ReadonlyArray<string>>
101
+ ): ReadonlyArray<Search.GrepMatch> =>
102
+ matches.map((match) => {
103
+ const source = contents.get(match.file)
104
+ const symbol = source === undefined ? undefined : Symbols.enclosing(source, match.line)
105
+ return symbol === undefined ? match : { ...match, symbol }
106
+ })
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Small, dependency-free HTML renderers for web retrieval.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+
7
+ const comments = /<!--[\s\S]*?-->/g
8
+ const entities: Readonly<Record<string, string>> = { amp: "&", lt: "<", gt: ">", quot: "\"", apos: "'", nbsp: " " }
9
+
10
+ const dropSkipped = (html: string): string => {
11
+ const lower = html.replace(/[A-Z]/g, (letter) => letter.toLowerCase())
12
+ const opening = /<(head|script|style|noscript|iframe|object|embed)\b/gi
13
+ let output = ""
14
+ let cursor = 0
15
+ let match: RegExpExecArray | null
16
+ while ((match = opening.exec(html)) !== null) {
17
+ output += html.slice(cursor, match.index)
18
+ const marker = `</${match[1]!.toLowerCase()}`
19
+ let close = lower.indexOf(marker, opening.lastIndex)
20
+ while (close !== -1) {
21
+ let end = close + marker.length
22
+ while (/\s/.test(lower[end] ?? "")) end++
23
+ if (lower[end] === ">") {
24
+ cursor = end + 1
25
+ opening.lastIndex = cursor
26
+ break
27
+ }
28
+ close = lower.indexOf(marker, close + marker.length)
29
+ }
30
+ if (close === -1) return output
31
+ }
32
+ return output + html.slice(cursor)
33
+ }
34
+
35
+ const decode = (value: string): string =>
36
+ value.replace(/&(#x[\da-f]+|#\d+|[a-z]+);/gi, (match, entity: string) => {
37
+ if (entity[0] === "#") {
38
+ const number = Number.parseInt(
39
+ entity.slice(entity[1]!.toLowerCase() === "x" ? 2 : 1),
40
+ entity[1]!.toLowerCase() === "x" ? 16 : 10
41
+ )
42
+ return number <= 0x10ffff
43
+ && !(number >= 0xd800 && number <= 0xdfff)
44
+ ? String.fromCodePoint(number)
45
+ : match
46
+ }
47
+ const key = entity.toLowerCase()
48
+ return Object.hasOwn(entities, key) ? entities[key]! : match
49
+ })
50
+
51
+ const source = (html: string): string => dropSkipped(html.replace(comments, ""))
52
+
53
+ /**
54
+ * Extracts readable text while dropping executable and presentation-only elements.
55
+ *
56
+ * @category rendering
57
+ * @since 1.0.0
58
+ */
59
+ export const toText = (html: string): string =>
60
+ decode(source(html).replace(/<(br|\/p|\/div|\/li|\/h[1-6]|\/tr)\b[^>]*>/gi, "\n").replace(/<[^>]*>/g, " "))
61
+ .replace(/[ \t]+\n/g, "\n").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/[ \t]{2,}/g, " ").trim()
62
+
63
+ /**
64
+ * Converts a conservative subset of HTML into readable Markdown.
65
+ *
66
+ * @category rendering
67
+ * @since 1.0.0
68
+ */
69
+ export const toMarkdown = (html: string): string => {
70
+ const markdown = source(html)
71
+ .replace(
72
+ /<h([1-6])\b[^>]*>([\s\S]*?)<\/h\1>/gi,
73
+ (_all, level: string, text: string) => `\n\n${"#".repeat(Number(level))} ${toText(text)}\n\n`
74
+ )
75
+ .replace(/<(strong|b)\b[^>]*>([\s\S]*?)<\/\1>/gi, "**$2**")
76
+ .replace(/<(em|i)\b[^>]*>([\s\S]*?)<\/\1>/gi, "*$2*")
77
+ .replace(
78
+ /<a\b[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi,
79
+ (_all, href: string, text: string) => `[${toText(text)}](${href})`
80
+ )
81
+ .replace(/<li\b[^>]*>/gi, "\n- ").replace(
82
+ /<\/?(ul|ol|p|div|section|article|main|blockquote|pre|tr)\b[^>]*>/gi,
83
+ "\n"
84
+ )
85
+ .replace(/<br\b[^>]*>/gi, "\n").replace(/<[^>]*>/g, "")
86
+ return decode(markdown).replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim()
87
+ }