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

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 +380 -0
  9. package/dist/cjs/Bash.d.ts.map +1 -0
  10. package/dist/cjs/Bash.js +332 -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 +108 -0
  173. package/dist/cjs/internal/GitWorktree.d.ts.map +1 -0
  174. package/dist/cjs/internal/GitWorktree.js +276 -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 +380 -0
  246. package/dist/esm/Bash.d.ts.map +1 -0
  247. package/dist/esm/Bash.js +505 -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 +108 -0
  410. package/dist/esm/internal/GitWorktree.d.ts.map +1 -0
  411. package/dist/esm/internal/GitWorktree.js +352 -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 +607 -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 +491 -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,182 @@
1
+ /**
2
+ * Faithful port of Codex CLI output truncation.
3
+ *
4
+ * Mirrors `codex-rs/utils/string/src/truncate.rs` and
5
+ * `codex-rs/utils/output-truncation/src/lib.rs`: middle truncation on UTF-8
6
+ * boundaries with a `…{n} tokens truncated…` marker and a 4-bytes-per-token
7
+ * estimate, so ChatGPT-family models see the exact shapes they were
8
+ * posttrained on.
9
+ *
10
+ * @since 1.0.0
11
+ */
12
+
13
+ const APPROX_BYTES_PER_TOKEN = 4
14
+
15
+ const encoder = new TextEncoder()
16
+ const decoder = new TextDecoder()
17
+
18
+ /**
19
+ * UTF-8 byte length of a string.
20
+ *
21
+ * @since 1.0.0
22
+ * @private
23
+ */
24
+ export const byteLength = (text: string): number => encoder.encode(text).byteLength
25
+
26
+ /**
27
+ * Approximate token count: ceil(utf8Bytes / 4).
28
+ *
29
+ * @since 1.0.0
30
+ * @private
31
+ */
32
+ export const approxTokenCount = (text: string): number =>
33
+ Math.floor((byteLength(text) + APPROX_BYTES_PER_TOKEN - 1) / APPROX_BYTES_PER_TOKEN)
34
+
35
+ /**
36
+ * Approximate byte budget for a token budget.
37
+ *
38
+ * @since 1.0.0
39
+ * @private
40
+ */
41
+ export const approxBytesForTokens = (tokens: number): number => tokens * APPROX_BYTES_PER_TOKEN
42
+
43
+ /**
44
+ * Approximate tokens represented by a byte count: ceil(bytes / 4).
45
+ *
46
+ * @since 1.0.0
47
+ * @private
48
+ */
49
+ export const approxTokensFromByteCount = (bytes: number): number =>
50
+ Math.floor((bytes + APPROX_BYTES_PER_TOKEN - 1) / APPROX_BYTES_PER_TOKEN)
51
+
52
+ const formatTruncationMarker = (useTokens: boolean, removedCount: number): string =>
53
+ useTokens ? `…${removedCount} tokens truncated…` : `…${removedCount} chars truncated…`
54
+
55
+ interface Split {
56
+ readonly removedChars: number
57
+ readonly before: string
58
+ readonly after: string
59
+ }
60
+
61
+ /** A UTF-8 continuation byte is `10xxxxxx`; every other byte starts a character. */
62
+ const isContinuation = (byte: number): boolean => (byte & 0b1100_0000) === 0b1000_0000
63
+
64
+ /** The last character boundary at or before `offset`. */
65
+ const boundaryAtOrBefore = (bytes: Uint8Array, offset: number): number => {
66
+ let at = Math.min(offset, bytes.byteLength)
67
+ while (at > 0 && at < bytes.byteLength && isContinuation(bytes[at]!)) at--
68
+ return at
69
+ }
70
+
71
+ /** The first character boundary at or after `offset`. */
72
+ const boundaryAtOrAfter = (bytes: Uint8Array, offset: number): number => {
73
+ let at = Math.max(offset, 0)
74
+ while (at < bytes.byteLength && isContinuation(bytes[at]!)) at++
75
+ return at
76
+ }
77
+
78
+ /**
79
+ * Splits `s` into the head that fits `beginningBytes` and the tail that fits
80
+ * `endBytes`, both cut on UTF-8 character boundaries, and counts the characters
81
+ * dropped between them.
82
+ *
83
+ * The boundaries are read off the encoded bytes rather than by re-encoding one
84
+ * character at a time: a per-character `TextEncoder.encode` costs about two
85
+ * microseconds, which is nineteen seconds for the eight megabytes a bounded
86
+ * capture can hand this function.
87
+ */
88
+ const splitString = (s: string, beginningBytes: number, endBytes: number): Split => {
89
+ const bytes = encoder.encode(s)
90
+ const tailStartTarget = Math.max(bytes.byteLength - endBytes, 0)
91
+ const prefixEnd = boundaryAtOrBefore(bytes, beginningBytes)
92
+ const suffixStart = boundaryAtOrAfter(bytes, Math.max(tailStartTarget, prefixEnd))
93
+ let removedChars = 0
94
+ for (let at = prefixEnd; at < suffixStart; at++) if (!isContinuation(bytes[at]!)) removedChars++
95
+ return {
96
+ removedChars,
97
+ before: decoder.decode(bytes.subarray(0, prefixEnd)),
98
+ after: decoder.decode(bytes.subarray(suffixStart))
99
+ }
100
+ }
101
+
102
+ const truncateWithByteEstimate = (s: string, maxBytes: number, useTokens: boolean): string => {
103
+ if (s === "") return ""
104
+ const totalBytes = byteLength(s)
105
+ if (maxBytes === 0) {
106
+ return formatTruncationMarker(useTokens, useTokens ? approxTokensFromByteCount(totalBytes) : [...s].length)
107
+ }
108
+ if (totalBytes <= maxBytes) return s
109
+ const leftBudget = Math.floor(maxBytes / 2)
110
+ const rightBudget = maxBytes - leftBudget
111
+ const { after, before, removedChars } = splitString(s, leftBudget, rightBudget)
112
+ const marker = formatTruncationMarker(
113
+ useTokens,
114
+ useTokens ? approxTokensFromByteCount(Math.max(totalBytes - maxBytes, 0)) : removedChars
115
+ )
116
+ return `${before}${marker}${after}`
117
+ }
118
+
119
+ /**
120
+ * Middle-truncate to a byte budget with a char-count marker.
121
+ *
122
+ * @since 1.0.0
123
+ * @private
124
+ */
125
+ export const truncateMiddleChars = (s: string, maxBytes: number): string => truncateWithByteEstimate(s, maxBytes, false)
126
+
127
+ /**
128
+ * Middle-truncate to an approximate token budget, preserving the beginning
129
+ * and end. Returns the possibly truncated string and the original token
130
+ * count when truncation occurred.
131
+ *
132
+ * @since 1.0.0
133
+ * @private
134
+ */
135
+ export const truncateMiddleWithTokenBudget = (
136
+ s: string,
137
+ maxTokens: number
138
+ ): { readonly text: string; readonly originalTokenCount: number | undefined } => {
139
+ if (s === "") return { text: "", originalTokenCount: undefined }
140
+ if (maxTokens > 0 && byteLength(s) <= approxBytesForTokens(maxTokens)) {
141
+ return { text: s, originalTokenCount: undefined }
142
+ }
143
+ const truncated = truncateWithByteEstimate(s, approxBytesForTokens(maxTokens), true)
144
+ if (truncated === s) return { text: s, originalTokenCount: undefined }
145
+ return { text: truncated, originalTokenCount: approxTokenCount(s) }
146
+ }
147
+
148
+ const countLines = (content: string): number => {
149
+ if (content === "") return 0
150
+ const parts = content.split("\n")
151
+ return parts[parts.length - 1] === "" ? parts.length - 1 : parts.length
152
+ }
153
+
154
+ /**
155
+ * Codex `format_exec_output_for_model`: exit code, wall time, optional line
156
+ * count disclosure, then the (possibly middle-truncated) output.
157
+ *
158
+ * @since 1.0.0
159
+ * @private
160
+ */
161
+ export const formatExecOutputForModel = (options: {
162
+ readonly output: string
163
+ readonly exitCode: number
164
+ readonly durationSeconds: number
165
+ readonly maxOutputTokens: number
166
+ readonly timedOutAfterMs?: number | undefined
167
+ }): string => {
168
+ const content = options.timedOutAfterMs === undefined
169
+ ? options.output
170
+ : `command timed out after ${options.timedOutAfterMs} milliseconds\n${options.output}`
171
+ const durationSeconds = Math.round(options.durationSeconds * 10) / 10
172
+ const totalLines = countLines(content)
173
+ const formatted = truncateMiddleWithTokenBudget(content, options.maxOutputTokens).text
174
+ const sections = [
175
+ `Exit code: ${options.exitCode}`,
176
+ `Wall time: ${durationSeconds} seconds`
177
+ ]
178
+ if (totalLines !== countLines(formatted)) sections.push(`Total output lines: ${totalLines}`)
179
+ sections.push("Output:")
180
+ sections.push(formatted)
181
+ return sections.join("\n")
182
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Shared declaration helpers for the standard flows.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+
7
+ import type * as Capability from "@smthrs/capability/Capability"
8
+ import * as Effects from "@smthrs/core/Effects"
9
+
10
+ /**
11
+ * Options accepted by {@link envelope}.
12
+ *
13
+ * @category models
14
+ * @since 1.0.0
15
+ */
16
+ export interface EnvelopeOptions {
17
+ readonly tier: "sealed" | "compensable" | "irreversible"
18
+ readonly mode: "hermetic" | "expected"
19
+ readonly reads: Iterable<string>
20
+ readonly writes: Iterable<string>
21
+ }
22
+
23
+ /**
24
+ * Builds a deterministic effect declaration for a standard flow.
25
+ *
26
+ * Every standard flow serializes on conflict: the library owns no lane
27
+ * partitioning of its own, so the conservative choice is the safe one.
28
+ *
29
+ * @category constructors
30
+ * @since 1.0.0
31
+ */
32
+ export const envelope = (options: EnvelopeOptions): Effects.Declaration =>
33
+ Effects.make({
34
+ reads: options.reads,
35
+ writes: options.writes,
36
+ mode: options.mode,
37
+ onConflict: "serialize",
38
+ tier: options.tier
39
+ })
40
+
41
+ /**
42
+ * Formats a capability request as the `action:resource` string carried on a
43
+ * flow declaration.
44
+ *
45
+ * @category constructors
46
+ * @since 1.0.0
47
+ */
48
+ export const capability = (action: Capability.Action, resource: string): string => `${action}:${resource}`
49
+
50
+ /**
51
+ * The read glob covering everything under one search root.
52
+ *
53
+ * `glob` and `grep` narrow their conservative `/**` declaration to the root the
54
+ * call actually names, and a declaration that disagreed between the two would
55
+ * make the same search reserve different paths depending on which flow ran it.
56
+ *
57
+ * @category constructors
58
+ * @since 1.0.0
59
+ */
60
+ export const rootSubtree = (root: string): string => root === "/" ? "/**" : `${root.replace(/\/+$/, "")}/**`
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Keeps a bound language server in step with the files the mutation flows
3
+ * write, and reads back the errors an edit leaves.
4
+ *
5
+ * The server is optional: a host that binds no `LanguageServer` edits files
6
+ * exactly as before, and a server that fails or times out never fails the
7
+ * write that already happened.
8
+ *
9
+ * @since 1.0.0
10
+ */
11
+
12
+ import * as Effect from "effect/Effect"
13
+ import * as Option from "effect/Option"
14
+ import * as Schema from "effect/Schema"
15
+ import * as LanguageServer from "../LanguageServer.ts"
16
+
17
+ /**
18
+ * Most errors attached to one result.
19
+ *
20
+ * @category internal
21
+ * @since 1.0.0
22
+ */
23
+ export const MAX_ERRORS = 20
24
+
25
+ /**
26
+ * One error-severity diagnostic, at its 1-based position.
27
+ *
28
+ * @category internal
29
+ * @since 1.0.0
30
+ */
31
+ export const Problem = Schema.Struct({
32
+ line: Schema.Number.annotate({ description: "1-based line" }),
33
+ character: Schema.Number.annotate({ description: "1-based character" }),
34
+ message: Schema.String
35
+ })
36
+
37
+ /**
38
+ * A decoded {@link Problem}.
39
+ *
40
+ * @category internal
41
+ * @since 1.0.0
42
+ */
43
+ export type Problem = typeof Problem.Type
44
+
45
+ const record = (value: unknown): Readonly<Record<string, unknown>> | undefined =>
46
+ typeof value === "object" && value !== null && !Array.isArray(value)
47
+ ? value as Readonly<Record<string, unknown>>
48
+ : undefined
49
+
50
+ /**
51
+ * The error-severity items of a document diagnostic report, 1-based.
52
+ *
53
+ * @category internal
54
+ * @since 1.0.0
55
+ */
56
+ export const errors = (report: unknown): ReadonlyArray<Problem> => {
57
+ const items = record(report)?.items
58
+ if (!Array.isArray(items)) return []
59
+ const found: Array<Problem> = []
60
+ for (const item of items) {
61
+ const diagnostic = record(item)
62
+ const start = record(record(diagnostic?.range)?.start)
63
+ if (
64
+ diagnostic?.severity !== 1 || typeof diagnostic.message !== "string" ||
65
+ typeof start?.line !== "number" || typeof start.character !== "number"
66
+ ) continue
67
+ found.push({ line: start.line + 1, character: start.character + 1, message: diagnostic.message })
68
+ if (found.length === MAX_ERRORS) break
69
+ }
70
+ return found
71
+ }
72
+
73
+ /**
74
+ * Sends a written file's new text to the bound server, if any. Succeeds with
75
+ * the server that took it.
76
+ *
77
+ * @category internal
78
+ * @since 1.0.0
79
+ */
80
+ export const sync = (path: string, text: string): Effect.Effect<LanguageServer.LanguageServer | undefined> =>
81
+ Effect.serviceOption(LanguageServer.LanguageServer).pipe(
82
+ Effect.flatMap(Option.match({
83
+ onNone: () => Effect.succeed(undefined),
84
+ onSome: (server) =>
85
+ server.sync(path, text).pipe(
86
+ Effect.as(server),
87
+ Effect.orElseSucceed(() => undefined)
88
+ )
89
+ }))
90
+ )
91
+
92
+ /**
93
+ * Tells the bound server, if any, that a file is gone.
94
+ *
95
+ * @category internal
96
+ * @since 1.0.0
97
+ */
98
+ export const close = (path: string): Effect.Effect<void> =>
99
+ Effect.serviceOption(LanguageServer.LanguageServer).pipe(
100
+ Effect.flatMap(Option.match({
101
+ onNone: () => Effect.void,
102
+ onSome: (server) => server.close(path).pipe(Effect.ignore)
103
+ }))
104
+ )
105
+
106
+ /**
107
+ * Tells the bound server, if any, to re-read every file it has open, after
108
+ * something other than the mutation flows may have changed them.
109
+ *
110
+ * @category internal
111
+ * @since 1.0.0
112
+ */
113
+ export const refresh: Effect.Effect<void> = Effect.serviceOption(LanguageServer.LanguageServer).pipe(
114
+ Effect.flatMap(Option.match({
115
+ onNone: () => Effect.void,
116
+ onSome: (server) => server.refresh.pipe(Effect.ignore)
117
+ }))
118
+ )
119
+
120
+ /**
121
+ * The errors `server` reports for `path`, or `undefined` when it could not
122
+ * answer.
123
+ *
124
+ * @category internal
125
+ * @since 1.0.0
126
+ */
127
+ export const errorsOf = (
128
+ server: LanguageServer.LanguageServer,
129
+ path: string
130
+ ): Effect.Effect<ReadonlyArray<Problem> | undefined> =>
131
+ server.diagnostics(path).pipe(
132
+ Effect.map(errors),
133
+ Effect.orElseSucceed(() => undefined)
134
+ )
@@ -0,0 +1,233 @@
1
+ /**
2
+ * The hermetic pre-check: a lexical scan of shell text for the paths it names,
3
+ * and the refusal when one of them falls outside the declared envelope.
4
+ *
5
+ * The scan is fail-closed over explicit path tokens and nothing more. It
6
+ * cannot prove confinement — a shell can name a path no lexer sees, through a
7
+ * variable, a substitution, or a program that opens a file of its own — so a
8
+ * kernel or host sandbox must eventually enforce and report the complete read
9
+ * and write sets.
10
+ *
11
+ * It lives beside the flow rather than inside it because it is its own
12
+ * concept, with its own vocabulary (Access, PathReference) and its own
13
+ * security history: three independent bypasses, each sufficient on its own to
14
+ * defeat it, are closed here.
15
+ *
16
+ * @since 1.0.0
17
+ */
18
+
19
+ import type * as Path from "@smthrs/kernel/Path"
20
+ import * as StdError from "../StdError.ts"
21
+ import { withinEnvelope } from "./Paths.ts"
22
+
23
+ /**
24
+ * The filesystem envelope one invocation declared.
25
+ *
26
+ * Structural rather than the hermetic `Bash.Input` itself: the scan needs the
27
+ * three fields and none of the rest, and depending on the flow module would
28
+ * make the flow and its pre-check import each other.
29
+ *
30
+ * @category models
31
+ * @since 1.0.0
32
+ */
33
+ export interface Envelope {
34
+ readonly cwd?: string | undefined
35
+ readonly reads: ReadonlyArray<string>
36
+ readonly writes: ReadonlyArray<string>
37
+ }
38
+
39
+ /**
40
+ * How a command touches a path it names.
41
+ *
42
+ * @category models
43
+ * @since 1.0.0
44
+ */
45
+ export type Access = "read" | "write"
46
+
47
+ /**
48
+ * One path a command names, and how it touches it.
49
+ *
50
+ * @category models
51
+ * @since 1.0.0
52
+ */
53
+ export interface PathReference {
54
+ readonly access: Access
55
+ readonly value: string
56
+ }
57
+
58
+ const commandSeparators = new Set(["&&", "||", ";", "|", "&", "\n"])
59
+ const redirections = new Set([">", ">>", "<", "<<"])
60
+ const writeCommands = new Set(["chmod", "chown", "mkdir", "rm", "rmdir", "tee", "touch", "truncate", "unlink"])
61
+ const destinationCommands = new Set(["cp", "install", "mv"])
62
+ const prefixWrappers = new Set(["env", "nice", "time", "sudo", "nohup", "xargs", "command", "exec"])
63
+
64
+ // Shell spaces may disappear, but a physical line ends one command. Retaining
65
+ // LF prevents a command on line one from classifying every later line's paths.
66
+ //
67
+ // A word is one or more runs of bare characters and quoted sections, not a
68
+ // bare run alone: `FOO="a b" rm /work/target` used to tokenize as `FOO="a`,
69
+ // `b"`, `rm`, `/work/target`, and since only the first token carried an `=`
70
+ // the command was read as `b"` rather than `rm` — so the delete was
71
+ // classified as a read and a hermetic call with `writes: []` spawned. The
72
+ // quoted alternatives come first inside the group so a quoted span is taken
73
+ // whole; the bare class excludes quotes so the branches cannot overlap.
74
+ const tokenize = (command: string): ReadonlyArray<string> =>
75
+ command.match(/\n|>>|<<|&&|\|\||[<>;|&]|(?:"(?:\\.|[^"\\])*"|'[^']*'|[^\s<>;|&"']+)+/g) ?? []
76
+
77
+ const unquote = (token: string): string => {
78
+ const first = token[0]
79
+ const last = token[token.length - 1]
80
+ return token.length >= 2 && (first === "'" || first === "\"") && last === first
81
+ ? token.slice(1, -1)
82
+ : token
83
+ }
84
+
85
+ const pathValue = (token: string): string =>
86
+ unquote(token)
87
+ .replace(/^\$\(+/, "")
88
+ .replace(/[),]+$/, "")
89
+
90
+ const isPathToken = (path: Path.Path, token: string): boolean =>
91
+ token === "." ||
92
+ token === ".." ||
93
+ token.startsWith("./") ||
94
+ token.startsWith("../") ||
95
+ path.isAbsolute(token) ||
96
+ /^[A-Za-z]:[\\/]/.test(token) ||
97
+ token.includes("/")
98
+
99
+ const segmentReferences = (path: Path.Path, tokens: ReadonlyArray<string>): ReadonlyArray<PathReference> => {
100
+ const commentIndex = tokens.findIndex((token) => token.startsWith("#"))
101
+ const active = commentIndex === -1 ? tokens : tokens.slice(0, commentIndex)
102
+ const hasWrapper = active.some((token) => prefixWrappers.has(path.basename(pathValue(token))))
103
+ let commandIndex = active.findIndex((token) =>
104
+ !redirections.has(token) &&
105
+ !token.includes("=") &&
106
+ !prefixWrappers.has(path.basename(pathValue(token))) &&
107
+ !token.startsWith("-") &&
108
+ token !== ""
109
+ )
110
+ if (hasWrapper) {
111
+ // Wrapper options can carry their own values. Prefer a later known
112
+ // mutating command so an option value cannot lend it a read classification.
113
+ const mutatingIndex = active.findIndex((token) => {
114
+ const command = path.basename(pathValue(token))
115
+ return writeCommands.has(command) || destinationCommands.has(command)
116
+ })
117
+ if (mutatingIndex !== -1) commandIndex = mutatingIndex
118
+ }
119
+ if (commandIndex === -1) return []
120
+
121
+ const command = path.basename(pathValue(active[commandIndex]!))
122
+ const candidates: Array<{ readonly index: number; readonly value: string }> = []
123
+ for (let index = 0; index < active.length; index++) {
124
+ const token = active[index]!
125
+ if (index === commandIndex || redirections.has(token) || token.startsWith("-")) continue
126
+ const value = pathValue(token)
127
+ if (value !== "" && isPathToken(path, value)) candidates.push({ index, value })
128
+ }
129
+
130
+ const destinationIndex = destinationCommands.has(command)
131
+ ? candidates[candidates.length - 1]?.index
132
+ : undefined
133
+
134
+ return candidates.map(({ index, value }) => {
135
+ const previous = active[index - 1]
136
+ const access: Access = previous === ">" || previous === ">>" ||
137
+ writeCommands.has(command) || destinationIndex === index
138
+ ? "write"
139
+ : "read"
140
+ return { access, value }
141
+ })
142
+ }
143
+
144
+ /**
145
+ * Every path token the shell text names, one segment at a time.
146
+ *
147
+ * @category pre-check
148
+ * @since 1.0.0
149
+ */
150
+ export const commandReferences = (path: Path.Path, command: string): ReadonlyArray<PathReference> => {
151
+ const references: Array<PathReference> = []
152
+ let segment: Array<string> = []
153
+ for (const token of tokenize(command)) {
154
+ if (commandSeparators.has(token)) {
155
+ references.push(...segmentReferences(path, segment))
156
+ segment = []
157
+ } else {
158
+ segment.push(token)
159
+ }
160
+ }
161
+ references.push(...segmentReferences(path, segment))
162
+ return references
163
+ }
164
+
165
+ const resolvePath = (
166
+ path: Path.Path,
167
+ cwd: string,
168
+ value: string
169
+ ): string => path.isAbsolute(value) ? path.normalize(value) : path.resolve(cwd, value)
170
+
171
+ const isDeclared = (
172
+ path: Path.Path,
173
+ cwd: string,
174
+ declared: ReadonlyArray<string>,
175
+ source: string
176
+ ): boolean =>
177
+ withinEnvelope(
178
+ declared.map((entry) => resolvePath(path, cwd, entry)),
179
+ resolvePath(path, cwd, source)
180
+ )
181
+
182
+ /**
183
+ * The refusal shell text earns by naming a path outside its declared
184
+ * envelope, or `undefined` when every path it names is declared.
185
+ *
186
+ * @category pre-check
187
+ * @since 1.0.0
188
+ */
189
+ export const outsideEnvelope = (
190
+ input: Envelope,
191
+ text: string,
192
+ path: Path.Path
193
+ ): StdError.StdError | undefined => {
194
+ const base = path.resolve(".")
195
+ const cwd = path.resolve(input.cwd ?? ".")
196
+ // Passing the default explicitly is not a declaration the caller owes. A
197
+ // working directory is where the command runs, not a file it reads, and
198
+ // `cwd: "."` names exactly what omitting `cwd` names — so refusing it asked
199
+ // the caller to list the workspace root among its reads to say nothing at
200
+ // all. Agents hit this constantly: one SWE-bench run spent ten of its
201
+ // forty-eight tool calls re-issuing the same command after
202
+ // "Working directory is outside declared reads: <the workspace root>". A
203
+ // cwd that points somewhere else is still declared or refused.
204
+ if (input.cwd !== undefined && cwd !== base && !isDeclared(path, cwd, input.reads, cwd)) {
205
+ return new StdError.StdError({
206
+ code: "outside_declared_reads",
207
+ message: `Working directory is outside declared reads: ${cwd}`,
208
+ path: cwd
209
+ })
210
+ }
211
+
212
+ // The Shell contract currently has no sandbox or access-reporting surface.
213
+ // This lexical scan is intentionally only a fail-closed pre-check for
214
+ // explicit path tokens. It cannot prove confinement; a kernel/host sandbox
215
+ // must eventually enforce and report the complete read and write sets.
216
+ for (const reference of commandReferences(path, text)) {
217
+ const resolved = resolvePath(path, cwd, reference.value)
218
+ // /dev/* is the process plumbing every shell one-liner leans on:
219
+ // `2>/dev/null`, `cat /dev/stdin`. Normalize first so a dot-dot segment
220
+ // cannot disguise an ordinary filesystem path as process plumbing.
221
+ if (resolved.startsWith("/dev/")) continue
222
+ const declared = reference.access === "write" ? input.writes : input.reads
223
+ if (!isDeclared(path, cwd, declared, resolved)) {
224
+ const code = reference.access === "write" ? "outside_declared_writes" : "outside_declared_reads"
225
+ return new StdError.StdError({
226
+ code,
227
+ message: `Command path is outside declared ${reference.access}s: ${resolved}`,
228
+ path: resolved
229
+ })
230
+ }
231
+ }
232
+ return undefined
233
+ }