@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,300 @@
1
+ /**
2
+ * Read flow declaration and portable handler.
3
+ *
4
+ * `content` is raw file text. It used to be rendered as `NNN\t<line>`, and that
5
+ * rendering was the single most expensive tool defect measured on the 45-instance
6
+ * SWE-bench trace program: an anchor copied out of a read carried the gutter, so
7
+ * every `edit` built from a read missed, and every cell that wanted a literal
8
+ * line had to strip the prefix in JavaScript first. Two instances (django-13346,
9
+ * django-14351) spent whole frames writing string surgery against text the file
10
+ * does not contain. Line numbers are facts about the page, so they are page
11
+ * fields — `startLine` and `endLine` — and never bytes inside the text.
12
+ *
13
+ * Every line in `content` is a whole line: a page cut short by the byte budget
14
+ * drops its trailing partial line rather than handing back a fragment that looks
15
+ * like an anchor and is not one. CRLF lines retain their trailing CR; only
16
+ * the page's final LF is omitted.
17
+ *
18
+ * @since 1.0.0
19
+ */
20
+ import * as Effect from "effect/Effect";
21
+ import * as FileSystem from "effect/FileSystem";
22
+ import * as Option from "effect/Option";
23
+ import * as Schema from "effect/Schema";
24
+ import { capability, envelope } from "./internal/Declaration.js";
25
+ import * as FileMutation from "./internal/FileMutation.js";
26
+ import * as FsFailure from "./internal/FsFailure.js";
27
+ import { DEFAULT_READ_LIMIT, MAX_LINE_CHARS, MAX_OUTPUT_BYTES, notice, slice, truncateBytes } from "./internal/Text.js";
28
+ import * as StdError from "./StdError.js";
29
+ export { Preconditions, ReadSession } from "./internal/FileMutation.js";
30
+ /**
31
+ * Registry name for the read flow.
32
+ *
33
+ * @category identifiers
34
+ * @since 1.0.0
35
+ */
36
+ export const name = "read";
37
+ /**
38
+ * Model-facing description of the read flow.
39
+ *
40
+ * @category descriptions
41
+ * @since 1.0.0
42
+ */
43
+ export const description = "Read a text file by 1-based offset and limit. content is RAW file text with no line-number prefixes, so any line of it is an edit anchor as it stands; the numbers are startLine/endLine.";
44
+ /**
45
+ * Input schema for the read flow.
46
+ *
47
+ * @category schemas
48
+ * @since 1.0.0
49
+ */
50
+ export const Input = Schema.Struct({
51
+ path: Schema.String.annotate({ description: "Path of the text file to read" }),
52
+ offset: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({
53
+ description: "1-based line offset"
54
+ }),
55
+ limit: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({
56
+ description: "Maximum number of lines to return"
57
+ })
58
+ });
59
+ /**
60
+ * Output schema for the read flow.
61
+ *
62
+ * @category schemas
63
+ * @since 1.0.0
64
+ */
65
+ export const Output = Schema.Struct({
66
+ content: Schema.String.annotate({
67
+ description: "Raw page text, preserving CR bytes and omitting the final LF; never line-number prefixed"
68
+ }),
69
+ startLine: Schema.Number.annotate({ description: "First returned 1-based line number" }),
70
+ endLine: Schema.Number.annotate({
71
+ description: "Last returned 1-based line number, or startLine - 1 when no lines are returned"
72
+ }),
73
+ totalLines: Schema.Number.annotate({ description: "Total number of source lines" }),
74
+ truncated: Schema.Boolean.annotate({ description: "Whether displayed output was truncated" }),
75
+ notice: Schema.optional(Schema.String.annotate({ description: "Truncation disclosure" }))
76
+ });
77
+ /**
78
+ * Static conservative effect envelope for the read flow.
79
+ *
80
+ * @category effects
81
+ * @since 1.0.0
82
+ */
83
+ export const effects = envelope({
84
+ tier: "sealed",
85
+ mode: "hermetic",
86
+ reads: ["/**"],
87
+ writes: []
88
+ });
89
+ /**
90
+ * Narrows the read effect envelope to one input path.
91
+ *
92
+ * @category effects
93
+ * @since 1.0.0
94
+ */
95
+ export const effectsFor = (input) => envelope({
96
+ tier: "sealed",
97
+ mode: "hermetic",
98
+ reads: [input.path],
99
+ writes: []
100
+ });
101
+ /**
102
+ * Capabilities required by the read flow.
103
+ *
104
+ * @category capabilities
105
+ * @since 1.0.0
106
+ */
107
+ export const capabilities = [capability("fs:read", "/**")];
108
+ /**
109
+ * Declaration-only read flow.
110
+ *
111
+ * @category flows
112
+ * @since 1.0.0
113
+ */
114
+ export const flow = { name, description, input: Input, output: Output, capabilities, effects };
115
+ /**
116
+ * What a call to this flow does, for a reader of a run.
117
+ *
118
+ * Display metadata only. `@smthrs/registry` `Descriptor.FlowActivity` is the
119
+ * governing vocabulary and `StandardFlows` binds this value onto the flow's
120
+ * descriptor, where the binding site checks it. `declarationDigest` excludes
121
+ * it, so declaring it cannot invalidate a call identity or a cached prompt.
122
+ *
123
+ * @category presentation
124
+ * @since 1.0.0-rc.0
125
+ */
126
+ export const activity = "reads";
127
+ /**
128
+ * How one recorded call to this flow reads: the verb for each settlement, the
129
+ * input field that is its subject, and the measured output fields a one-line
130
+ * summary may count.
131
+ *
132
+ * Display metadata only, governed by `@smthrs/registry`
133
+ * `Descriptor.CallPresentation` and checked where `StandardFlows` binds it.
134
+ *
135
+ * @category presentation
136
+ * @since 1.0.0-rc.0
137
+ */
138
+ export const presentation = {
139
+ verb: { pending: "reading", success: "read", failure: "failed to read" },
140
+ subject: "path",
141
+ result: "read"
142
+ };
143
+ const clipLine = (line) => {
144
+ let scalars = 0;
145
+ let end = 0;
146
+ for (const scalar of line) {
147
+ if (scalars === MAX_LINE_CHARS)
148
+ return line.slice(0, end);
149
+ scalars++;
150
+ end += scalar.length;
151
+ }
152
+ return line;
153
+ };
154
+ /**
155
+ * The largest file `read` loads.
156
+ *
157
+ * `read` decodes the whole file to count its lines, so the file is held in
158
+ * memory twice over: its bytes and a UTF-16 string. Past this bound a page
159
+ * read would cost the host gigabytes for a window of a few thousand lines,
160
+ * and past 2 GiB Node cannot load the file at all.
161
+ *
162
+ * @category constants
163
+ * @since 1.0.0
164
+ */
165
+ export const MAX_READ_FILE_BYTES = 64 * 1024 * 1024;
166
+ const fileError = (path) => FsFailure.reading(path, `File not found: ${path}`);
167
+ const sharedPrefix = (left, right) => {
168
+ let index = 0;
169
+ while (index < left.length && index < right.length && left[index] === right[index])
170
+ index++;
171
+ return index;
172
+ };
173
+ /**
174
+ * Where a guessed relative path stops existing, and what is there instead.
175
+ *
176
+ * A worker that guesses `packages/smithers/flow/src/Flow.ts` learns nothing
177
+ * from "not found" and guesses again. Naming the nearest directory that exists
178
+ * and its entries, closest name first, turns the next call into a choice.
179
+ * Absolute paths and paths that climb out with `..` get no listing: the call
180
+ * declared one file, and the working tree is the only place a listing is
181
+ * already the caller's to read.
182
+ */
183
+ const nearest = (fileSystem, path) => Effect.gen(function* () {
184
+ const segments = path.split("/").filter((segment) => segment !== "" && segment !== ".");
185
+ if (path.startsWith("/") || segments.includes(".."))
186
+ return "";
187
+ for (let depth = segments.length - 1; depth >= 0; depth--) {
188
+ const directory = segments.slice(0, depth).join("/");
189
+ const entries = yield* fileSystem.readDirectory(directory === "" ? "." : directory).pipe(Effect.option);
190
+ if (Option.isNone(entries))
191
+ continue;
192
+ const missing = segments[depth].toLowerCase();
193
+ const ranked = entries.value
194
+ .filter((entry) => !entry.startsWith("."))
195
+ .map((entry) => ({ entry, score: sharedPrefix(entry.toLowerCase(), missing) }))
196
+ .sort((left, right) => right.score - left.score)
197
+ .map(({ entry }) => entry);
198
+ if (ranked.length === 0)
199
+ return "";
200
+ const shown = ranked.slice(0, 12).join(", ");
201
+ const more = ranked.length > 12 ? ` and ${ranked.length - 12} more` : "";
202
+ return `. ${directory === "" ? "The working directory" : directory} holds: ${shown}${more}.`;
203
+ }
204
+ return "";
205
+ });
206
+ const missingFile = (fileSystem, path) => Effect.flatMap(nearest(fileSystem, path), (hint) => Effect.fail(new StdError.StdError({
207
+ code: "not_found",
208
+ message: `File not found: ${path}${hint}`,
209
+ path
210
+ })));
211
+ /**
212
+ * Reads, validates, and renders one page of a UTF-8 text file.
213
+ *
214
+ * The kernel filesystem exposes bytes rather than a guaranteed UTF-8 string,
215
+ * so decoding is deliberately fatal to keep binary input in the typed channel.
216
+ *
217
+ * @category handlers
218
+ * @since 1.0.0
219
+ */
220
+ export const run = Effect.fn("Read.run")(function* (input) {
221
+ const fileSystem = yield* FileSystem.FileSystem;
222
+ const info = yield* fileSystem.stat(input.path).pipe(Effect.catchTag("PlatformError", (error) => error.reason._tag === "NotFound"
223
+ ? missingFile(fileSystem, input.path)
224
+ : Effect.fail(fileError(input.path)(error))));
225
+ if (info.type === "Directory") {
226
+ return yield* Effect.fail(new StdError.StdError({
227
+ code: "is_directory",
228
+ message: `Cannot read a directory: ${input.path}`,
229
+ path: input.path
230
+ }));
231
+ }
232
+ if (info.type !== "File") {
233
+ return yield* Effect.fail(new StdError.StdError({
234
+ code: "not_found",
235
+ message: `File not found: ${input.path}`,
236
+ path: input.path
237
+ }));
238
+ }
239
+ const size = Number(info.size);
240
+ if (size > MAX_READ_FILE_BYTES) {
241
+ return yield* Effect.fail(new StdError.StdError({
242
+ code: "response_too_large",
243
+ message: `${input.path} is ${size} bytes, over the ${MAX_READ_FILE_BYTES}-byte read limit; search it with grep or print a line range with bash`,
244
+ path: input.path
245
+ }));
246
+ }
247
+ const bytes = yield* fileSystem.readFile(input.path).pipe(Effect.mapError(fileError(input.path)));
248
+ if (bytes.includes(0)) {
249
+ return yield* Effect.fail(new StdError.StdError({
250
+ code: "binary_file",
251
+ message: `Cannot read binary file: ${input.path}`,
252
+ path: input.path
253
+ }));
254
+ }
255
+ const text = yield* Effect.try({
256
+ try: () => new TextDecoder("utf-8", { fatal: true }).decode(bytes),
257
+ catch: () => new StdError.StdError({
258
+ code: "binary_file",
259
+ message: `File is not valid UTF-8: ${input.path}`,
260
+ path: input.path
261
+ })
262
+ });
263
+ const offset = input.offset ?? 1;
264
+ const page = slice(text, { offset, limit: input.limit ?? DEFAULT_READ_LIMIT });
265
+ // An empty file has no lines, and reading one is not an out-of-range read:
266
+ // the caller asked for the first page and there is nothing on it. Only an
267
+ // offset past the first line of a file that has none is out of range.
268
+ if (offset > Math.max(page.totalLines, 1)) {
269
+ return yield* Effect.fail(new StdError.StdError({
270
+ code: "offset_out_of_range",
271
+ message: `Line offset ${offset} is outside ${input.path}`,
272
+ path: input.path
273
+ }));
274
+ }
275
+ const lines = page.lines.map(clipLine);
276
+ const longLinesTruncated = lines.some((line, index) => line !== page.lines[index]);
277
+ const rendered = truncateBytes(lines.join("\n"), MAX_OUTPUT_BYTES, { keep: "head" });
278
+ // A byte budget cuts mid-line. A partial line reads like an anchor and is not
279
+ // one, so the page ends at the last whole line it could afford.
280
+ const whole = rendered.truncated
281
+ ? rendered.text.slice(0, Math.max(0, rendered.text.lastIndexOf("\n")))
282
+ : rendered.text;
283
+ // Each clipped line fits the byte budget, so a truncated page retains at least one whole line.
284
+ const shown = rendered.truncated ? whole.split("\n").length : lines.length;
285
+ const endLine = page.startLine + shown - 1;
286
+ const truncated = longLinesTruncated || rendered.truncated || page.endLine < page.totalLines;
287
+ const clipped = longLinesTruncated
288
+ ? ` Lines longer than ${MAX_LINE_CHARS} Unicode scalar values are clipped, so such a line is not an edit anchor.`
289
+ : "";
290
+ yield* FileMutation.recordRead(fileSystem, input.path, bytes);
291
+ return {
292
+ content: whole,
293
+ startLine: page.startLine,
294
+ endLine,
295
+ totalLines: page.totalLines,
296
+ truncated,
297
+ ...(truncated ? { notice: `${notice("lines", shown, page.totalLines)}${clipped}` } : {})
298
+ };
299
+ });
300
+ //# sourceMappingURL=Read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Read.js","sourceRoot":"","sources":["../../src/Read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAA;AAC1D,OAAO,KAAK,SAAS,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC,OAAO,EAAE,aAAa,EAAE,WAAW,EAA4B,MAAM,4BAA4B,CAAA;AAEjG;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAA;AAE1B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GACtB,2LAA2L,CAAA;AAE7L;;;;;GAKG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,+BAA+B,EAAE,CAAC;IAC9E,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACnF,WAAW,EAAE,qBAAqB;KACnC,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAClF,WAAW,EAAE,mCAAmC;KACjD,CAAC;CACH,CAAC,CAAA;AAUF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC9B,WAAW,EAAE,0FAA0F;KACxG,CAAC;IACF,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;IACxF,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC9B,WAAW,EAAE,gFAAgF;KAC9F,CAAC;IACF,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;IACnF,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC;IAC7F,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC;CAC1F,CAAC,CAAA;AAUF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC;IAC9B,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,CAAC,KAAK,CAAC;IACd,MAAM,EAAE,EAAE;CACX,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAwB,EAAE,EAAE,CACrD,QAAQ,CAAC;IACP,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;IACnB,MAAM,EAAE,EAAE;CACX,CAAC,CAAA;AAEJ;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAW,CAAA;AAEvG;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAgB,CAAA;AAExC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE;IACxE,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;CACN,CAAA;AAEV,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAU,EAAE;IACxC,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,IAAI,OAAO,KAAK,cAAc;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACzD,OAAO,EAAE,CAAA;QACT,GAAG,IAAI,MAAM,CAAC,MAAM,CAAA;IACtB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;AAEnD,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAA;AAEtF,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE;IAC3D,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,OAAO,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,CAAA;IAC3F,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,GAAG,CACd,UAAiC,EACjC,IAAY,EACW,EAAE,CACzB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG,CAAC,CAAA;IACvF,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAA;IAC9D,KAAK,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAC1D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACpD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QACvG,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC;YAAE,SAAQ;QACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAE,CAAC,WAAW,EAAE,CAAA;QAC9C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK;aACzB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;aACzC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;aAC9E,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;aAC/C,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAA;QAClC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;QACxE,OAAO,KAAK,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,SAAS,WAAW,KAAK,GAAG,IAAI,GAAG,CAAA;IAC9F,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAC,CAAA;AAEJ,MAAM,WAAW,GAAG,CAAC,UAAiC,EAAE,IAAY,EAAE,EAAE,CACtE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACjD,MAAM,CAAC,IAAI,CACT,IAAI,QAAQ,CAAC,QAAQ,CAAC;IACpB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,mBAAmB,IAAI,GAAG,IAAI,EAAE;IACzC,IAAI;CACL,CAAC,CACH,CAAC,CAAA;AAEN;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAChD,KAAwB;IAExB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAA;IAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAClD,MAAM,CAAC,QAAQ,CACb,eAAe,EACf,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU;QAC9B,CAAC,CAAC,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC;QACrC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAChD,CACF,CAAA;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,4BAA4B,KAAK,CAAC,IAAI,EAAE;YACjD,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,mBAAmB,KAAK,CAAC,IAAI,EAAE;YACxC,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,IAAI,GAAG,mBAAmB,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EACL,GAAG,KAAK,CAAC,IAAI,OAAO,IAAI,oBAAoB,mBAAmB,uEAAuE;YACxI,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjG,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,4BAA4B,KAAK,CAAC,IAAI,EAAE;YACjD,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QAC7B,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QAClE,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,4BAA4B,KAAK,CAAC,IAAI,EAAE;YACjD,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC;KACL,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAA;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,kBAAkB,EAAE,CAAC,CAAA;IAC9E,2EAA2E;IAC3E,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACvB,IAAI,QAAQ,CAAC,QAAQ,CAAC;YACpB,IAAI,EAAE,qBAAqB;YAC3B,OAAO,EAAE,eAAe,MAAM,eAAe,KAAK,CAAC,IAAI,EAAE;YACzD,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CACH,CAAA;IACH,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACtC,MAAM,kBAAkB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;IAClF,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACpF,8EAA8E;IAC9E,gEAAgE;IAChE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS;QAC9B,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAA;IACjB,+FAA+F;IAC/F,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,GAAG,KAAK,GAAG,CAAC,CAAA;IAC1C,MAAM,SAAS,GAAG,kBAAkB,IAAI,QAAQ,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAA;IAC5F,MAAM,OAAO,GAAG,kBAAkB;QAChC,CAAC,CAAC,sBAAsB,cAAc,2EAA2E;QACjH,CAAC,CAAC,EAAE,CAAA;IACN,KAAK,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC7D,OAAO;QACL,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO;QACP,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,SAAS;QACT,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzF,CAAA;AACH,CAAC,CAAC,CAAA","sourcesContent":["/**\n * Read flow declaration and portable handler.\n *\n * `content` is raw file text. It used to be rendered as `NNN\\t<line>`, and that\n * rendering was the single most expensive tool defect measured on the 45-instance\n * SWE-bench trace program: an anchor copied out of a read carried the gutter, so\n * every `edit` built from a read missed, and every cell that wanted a literal\n * line had to strip the prefix in JavaScript first. Two instances (django-13346,\n * django-14351) spent whole frames writing string surgery against text the file\n * does not contain. Line numbers are facts about the page, so they are page\n * fields — `startLine` and `endLine` — and never bytes inside the text.\n *\n * Every line in `content` is a whole line: a page cut short by the byte budget\n * drops its trailing partial line rather than handing back a fragment that looks\n * like an anchor and is not one. CRLF lines retain their trailing CR; only\n * the page's final LF is omitted.\n *\n * @since 1.0.0\n */\n\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport * as Option from \"effect/Option\"\nimport * as Schema from \"effect/Schema\"\nimport { capability, envelope } from \"./internal/Declaration.ts\"\nimport * as FileMutation from \"./internal/FileMutation.ts\"\nimport * as FsFailure from \"./internal/FsFailure.ts\"\nimport { DEFAULT_READ_LIMIT, MAX_LINE_CHARS, MAX_OUTPUT_BYTES, notice, slice, truncateBytes } from \"./internal/Text.ts\"\nimport * as StdError from \"./StdError.ts\"\n\nexport { Preconditions, ReadSession, type VersionedFileSystem } from \"./internal/FileMutation.ts\"\n\n/**\n * Registry name for the read flow.\n *\n * @category identifiers\n * @since 1.0.0\n */\nexport const name = \"read\"\n\n/**\n * Model-facing description of the read flow.\n *\n * @category descriptions\n * @since 1.0.0\n */\nexport const description =\n \"Read a text file by 1-based offset and limit. content is RAW file text with no line-number prefixes, so any line of it is an edit anchor as it stands; the numbers are startLine/endLine.\"\n\n/**\n * Input schema for the read flow.\n *\n * @category schemas\n * @since 1.0.0\n */\nexport const Input = Schema.Struct({\n path: Schema.String.annotate({ description: \"Path of the text file to read\" }),\n offset: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({\n description: \"1-based line offset\"\n }),\n limit: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({\n description: \"Maximum number of lines to return\"\n })\n})\n\n/**\n * Decoded input accepted by the `read` flow.\n *\n * @category models\n * @since 1.0.0\n */\nexport type Input = typeof Input.Type\n\n/**\n * Output schema for the read flow.\n *\n * @category schemas\n * @since 1.0.0\n */\nexport const Output = Schema.Struct({\n content: Schema.String.annotate({\n description: \"Raw page text, preserving CR bytes and omitting the final LF; never line-number prefixed\"\n }),\n startLine: Schema.Number.annotate({ description: \"First returned 1-based line number\" }),\n endLine: Schema.Number.annotate({\n description: \"Last returned 1-based line number, or startLine - 1 when no lines are returned\"\n }),\n totalLines: Schema.Number.annotate({ description: \"Total number of source lines\" }),\n truncated: Schema.Boolean.annotate({ description: \"Whether displayed output was truncated\" }),\n notice: Schema.optional(Schema.String.annotate({ description: \"Truncation disclosure\" }))\n})\n\n/**\n * Decoded output returned by the `read` flow.\n *\n * @category models\n * @since 1.0.0\n */\nexport type Output = typeof Output.Type\n\n/**\n * Static conservative effect envelope for the read flow.\n *\n * @category effects\n * @since 1.0.0\n */\nexport const effects = envelope({\n tier: \"sealed\",\n mode: \"hermetic\",\n reads: [\"/**\"],\n writes: []\n})\n\n/**\n * Narrows the read effect envelope to one input path.\n *\n * @category effects\n * @since 1.0.0\n */\nexport const effectsFor = (input: typeof Input.Type) =>\n envelope({\n tier: \"sealed\",\n mode: \"hermetic\",\n reads: [input.path],\n writes: []\n })\n\n/**\n * Capabilities required by the read flow.\n *\n * @category capabilities\n * @since 1.0.0\n */\nexport const capabilities = [capability(\"fs:read\", \"/**\")]\n\n/**\n * Declaration-only read flow.\n *\n * @category flows\n * @since 1.0.0\n */\nexport const flow = { name, description, input: Input, output: Output, capabilities, effects } as const\n\n/**\n * What a call to this flow does, for a reader of a run.\n *\n * Display metadata only. `@smthrs/registry` `Descriptor.FlowActivity` is the\n * governing vocabulary and `StandardFlows` binds this value onto the flow's\n * descriptor, where the binding site checks it. `declarationDigest` excludes\n * it, so declaring it cannot invalidate a call identity or a cached prompt.\n *\n * @category presentation\n * @since 1.0.0-rc.0\n */\nexport const activity = \"reads\" as const\n\n/**\n * How one recorded call to this flow reads: the verb for each settlement, the\n * input field that is its subject, and the measured output fields a one-line\n * summary may count.\n *\n * Display metadata only, governed by `@smthrs/registry`\n * `Descriptor.CallPresentation` and checked where `StandardFlows` binds it.\n *\n * @category presentation\n * @since 1.0.0-rc.0\n */\nexport const presentation = {\n verb: { pending: \"reading\", success: \"read\", failure: \"failed to read\" },\n subject: \"path\",\n result: \"read\"\n} as const\n\nconst clipLine = (line: string): string => {\n let scalars = 0\n let end = 0\n for (const scalar of line) {\n if (scalars === MAX_LINE_CHARS) return line.slice(0, end)\n scalars++\n end += scalar.length\n }\n return line\n}\n\n/**\n * The largest file `read` loads.\n *\n * `read` decodes the whole file to count its lines, so the file is held in\n * memory twice over: its bytes and a UTF-16 string. Past this bound a page\n * read would cost the host gigabytes for a window of a few thousand lines,\n * and past 2 GiB Node cannot load the file at all.\n *\n * @category constants\n * @since 1.0.0\n */\nexport const MAX_READ_FILE_BYTES = 64 * 1024 * 1024\n\nconst fileError = (path: string) => FsFailure.reading(path, `File not found: ${path}`)\n\nconst sharedPrefix = (left: string, right: string): number => {\n let index = 0\n while (index < left.length && index < right.length && left[index] === right[index]) index++\n return index\n}\n\n/**\n * Where a guessed relative path stops existing, and what is there instead.\n *\n * A worker that guesses `packages/smithers/flow/src/Flow.ts` learns nothing\n * from \"not found\" and guesses again. Naming the nearest directory that exists\n * and its entries, closest name first, turns the next call into a choice.\n * Absolute paths and paths that climb out with `..` get no listing: the call\n * declared one file, and the working tree is the only place a listing is\n * already the caller's to read.\n */\nconst nearest = (\n fileSystem: FileSystem.FileSystem,\n path: string\n): Effect.Effect<string> =>\n Effect.gen(function*() {\n const segments = path.split(\"/\").filter((segment) => segment !== \"\" && segment !== \".\")\n if (path.startsWith(\"/\") || segments.includes(\"..\")) return \"\"\n for (let depth = segments.length - 1; depth >= 0; depth--) {\n const directory = segments.slice(0, depth).join(\"/\")\n const entries = yield* fileSystem.readDirectory(directory === \"\" ? \".\" : directory).pipe(Effect.option)\n if (Option.isNone(entries)) continue\n const missing = segments[depth]!.toLowerCase()\n const ranked = entries.value\n .filter((entry) => !entry.startsWith(\".\"))\n .map((entry) => ({ entry, score: sharedPrefix(entry.toLowerCase(), missing) }))\n .sort((left, right) => right.score - left.score)\n .map(({ entry }) => entry)\n if (ranked.length === 0) return \"\"\n const shown = ranked.slice(0, 12).join(\", \")\n const more = ranked.length > 12 ? ` and ${ranked.length - 12} more` : \"\"\n return `. ${directory === \"\" ? \"The working directory\" : directory} holds: ${shown}${more}.`\n }\n return \"\"\n })\n\nconst missingFile = (fileSystem: FileSystem.FileSystem, path: string) =>\n Effect.flatMap(nearest(fileSystem, path), (hint) =>\n Effect.fail(\n new StdError.StdError({\n code: \"not_found\",\n message: `File not found: ${path}${hint}`,\n path\n })\n ))\n\n/**\n * Reads, validates, and renders one page of a UTF-8 text file.\n *\n * The kernel filesystem exposes bytes rather than a guaranteed UTF-8 string,\n * so decoding is deliberately fatal to keep binary input in the typed channel.\n *\n * @category handlers\n * @since 1.0.0\n */\nexport const run = Effect.fn(\"Read.run\")(function*(\n input: typeof Input.Type\n): Effect.fn.Return<typeof Output.Type, StdError.StdError, FileSystem.FileSystem> {\n const fileSystem = yield* FileSystem.FileSystem\n const info = yield* fileSystem.stat(input.path).pipe(\n Effect.catchTag(\n \"PlatformError\",\n (error) =>\n error.reason._tag === \"NotFound\"\n ? missingFile(fileSystem, input.path)\n : Effect.fail(fileError(input.path)(error))\n )\n )\n if (info.type === \"Directory\") {\n return yield* Effect.fail(\n new StdError.StdError({\n code: \"is_directory\",\n message: `Cannot read a directory: ${input.path}`,\n path: input.path\n })\n )\n }\n if (info.type !== \"File\") {\n return yield* Effect.fail(\n new StdError.StdError({\n code: \"not_found\",\n message: `File not found: ${input.path}`,\n path: input.path\n })\n )\n }\n const size = Number(info.size)\n if (size > MAX_READ_FILE_BYTES) {\n return yield* Effect.fail(\n new StdError.StdError({\n code: \"response_too_large\",\n message:\n `${input.path} is ${size} bytes, over the ${MAX_READ_FILE_BYTES}-byte read limit; search it with grep or print a line range with bash`,\n path: input.path\n })\n )\n }\n const bytes = yield* fileSystem.readFile(input.path).pipe(Effect.mapError(fileError(input.path)))\n if (bytes.includes(0)) {\n return yield* Effect.fail(\n new StdError.StdError({\n code: \"binary_file\",\n message: `Cannot read binary file: ${input.path}`,\n path: input.path\n })\n )\n }\n const text = yield* Effect.try({\n try: () => new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes),\n catch: () =>\n new StdError.StdError({\n code: \"binary_file\",\n message: `File is not valid UTF-8: ${input.path}`,\n path: input.path\n })\n })\n const offset = input.offset ?? 1\n const page = slice(text, { offset, limit: input.limit ?? DEFAULT_READ_LIMIT })\n // An empty file has no lines, and reading one is not an out-of-range read:\n // the caller asked for the first page and there is nothing on it. Only an\n // offset past the first line of a file that has none is out of range.\n if (offset > Math.max(page.totalLines, 1)) {\n return yield* Effect.fail(\n new StdError.StdError({\n code: \"offset_out_of_range\",\n message: `Line offset ${offset} is outside ${input.path}`,\n path: input.path\n })\n )\n }\n const lines = page.lines.map(clipLine)\n const longLinesTruncated = lines.some((line, index) => line !== page.lines[index])\n const rendered = truncateBytes(lines.join(\"\\n\"), MAX_OUTPUT_BYTES, { keep: \"head\" })\n // A byte budget cuts mid-line. A partial line reads like an anchor and is not\n // one, so the page ends at the last whole line it could afford.\n const whole = rendered.truncated\n ? rendered.text.slice(0, Math.max(0, rendered.text.lastIndexOf(\"\\n\")))\n : rendered.text\n // Each clipped line fits the byte budget, so a truncated page retains at least one whole line.\n const shown = rendered.truncated ? whole.split(\"\\n\").length : lines.length\n const endLine = page.startLine + shown - 1\n const truncated = longLinesTruncated || rendered.truncated || page.endLine < page.totalLines\n const clipped = longLinesTruncated\n ? ` Lines longer than ${MAX_LINE_CHARS} Unicode scalar values are clipped, so such a line is not an edit anchor.`\n : \"\"\n yield* FileMutation.recordRead(fileSystem, input.path, bytes)\n return {\n content: whole,\n startLine: page.startLine,\n endLine,\n totalLines: page.totalLines,\n truncated,\n ...(truncated ? { notice: `${notice(\"lines\", shown, page.totalLines)}${clipped}` } : {})\n }\n})\n"]}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * What can be pointed at a checkpoint, and what cannot.
3
+ *
4
+ * {@link relocate} is the closed answer, and it is the half of the checkpoint
5
+ * feature that tracks the flows rather than git: it knows that `bash` carries
6
+ * its working directory in `cwd` and that `read`, `ls`, `grep` and `glob` carry
7
+ * their subject in `path`, `path`, `root` and `root`. `Checkpoints` changes when
8
+ * git does; this changes when one of those five input shapes does, which is why
9
+ * it is a module of its own. `Relocate.test.ts` decodes every rewritten input
10
+ * with the flow's own `Input` schema, so a renamed field fails there rather than
11
+ * silently relocating nothing.
12
+ *
13
+ * `bash` names *where it runs*, so it is relocated by its `cwd` — into the
14
+ * checkpoint, and into the same subdirectory of it the call asked for, because a
15
+ * check declared in `tests/` that silently ran at the top would come back
16
+ * failing for a reason nobody chose. `read`, `ls`, `grep` and `glob` name *what
17
+ * they touch* relative to the workspace root, so they are relocated by prefixing
18
+ * that root — and only when the path they name stays inside the tree, because an
19
+ * absolute path in these runs is a container path the host cannot rebase and a
20
+ * `..` path is the live tree under another name. Every other flow answers
21
+ * `checkpoint_unsupported` through the harness, including `test`, which already
22
+ * has `against: "base"` for exactly this question and would otherwise have two
23
+ * mechanisms that can disagree.
24
+ *
25
+ * @since 1.0.0
26
+ */
27
+ import type { Schema } from "effect";
28
+ import type { Materialized } from "./Checkpoints.ts";
29
+ /**
30
+ * Why one input could not be pointed at a checkpoint.
31
+ *
32
+ * @category models
33
+ * @since 1.0.0
34
+ */
35
+ export type Relocation = {
36
+ readonly _tag: "Relocated";
37
+ readonly input: Schema.Json;
38
+ } | {
39
+ readonly _tag: "UnsupportedFlow";
40
+ } | {
41
+ readonly _tag: "AbsolutePath";
42
+ readonly path: string;
43
+ } | {
44
+ readonly _tag: "OutsideTree";
45
+ readonly path: string;
46
+ };
47
+ /**
48
+ * Rewrites one call's input so the call runs against a materialized checkpoint.
49
+ *
50
+ * Returns the rewritten input, or the reason there is none. A `bash` call runs
51
+ * in the checkpoint's directory — from the *guest* side when it names a
52
+ * container, because that is the path the container will be given — and keeps
53
+ * whatever subdirectory it asked for: a check declared in `tests/` runs in the
54
+ * checkpoint's `tests/`. A working directory the checkpoint holds no copy of,
55
+ * such as somewhere else on the machine, becomes the checkpoint's own top,
56
+ * because a tree is all this can offer and there is no subpath in it to keep.
57
+ *
58
+ * A reader takes the checkpoint's workspace-relative directory as the prefix of
59
+ * what it names, because these flows resolve their subject against the
60
+ * workspace root and the checkpoint is a directory under it.
61
+ *
62
+ * Two paths are refused rather than rewritten, and both for the same reason —
63
+ * the host would otherwise hand back a reading of a tree the cell did not name.
64
+ * An absolute path in these runs is a container path, and the host cannot know
65
+ * which prefix of it names the tree. A relative path that climbs past the
66
+ * checkpoint with `..` names the live tree, exactly the tree the reading was
67
+ * taken to avoid.
68
+ *
69
+ * @category conversions
70
+ * @since 1.0.0
71
+ */
72
+ export declare const relocate: (flow: string, input: Schema.Json, materialized: Materialized) => Relocation;
73
+ //# sourceMappingURL=Relocate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Relocate.d.ts","sourceRoot":"","sources":["../../src/Relocate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AA0BpD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GACpC;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AA4C3D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EACZ,OAAO,MAAM,CAAC,IAAI,EAClB,cAAc,YAAY,KACzB,UA4BF,CAAA"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * What can be pointed at a checkpoint, and what cannot.
3
+ *
4
+ * {@link relocate} is the closed answer, and it is the half of the checkpoint
5
+ * feature that tracks the flows rather than git: it knows that `bash` carries
6
+ * its working directory in `cwd` and that `read`, `ls`, `grep` and `glob` carry
7
+ * their subject in `path`, `path`, `root` and `root`. `Checkpoints` changes when
8
+ * git does; this changes when one of those five input shapes does, which is why
9
+ * it is a module of its own. `Relocate.test.ts` decodes every rewritten input
10
+ * with the flow's own `Input` schema, so a renamed field fails there rather than
11
+ * silently relocating nothing.
12
+ *
13
+ * `bash` names *where it runs*, so it is relocated by its `cwd` — into the
14
+ * checkpoint, and into the same subdirectory of it the call asked for, because a
15
+ * check declared in `tests/` that silently ran at the top would come back
16
+ * failing for a reason nobody chose. `read`, `ls`, `grep` and `glob` name *what
17
+ * they touch* relative to the workspace root, so they are relocated by prefixing
18
+ * that root — and only when the path they name stays inside the tree, because an
19
+ * absolute path in these runs is a container path the host cannot rebase and a
20
+ * `..` path is the live tree under another name. Every other flow answers
21
+ * `checkpoint_unsupported` through the harness, including `test`, which already
22
+ * has `against: "base"` for exactly this question and would otherwise have two
23
+ * mechanisms that can disagree.
24
+ *
25
+ * @since 1.0.0
26
+ */
27
+ import { withoutTrailingSlash } from "./internal/Paths.js";
28
+ /**
29
+ * The flows whose input names where they run or what they read, and the field
30
+ * that says so.
31
+ *
32
+ * A closed table rather than a per-flow hook, because the set is small and the
33
+ * rule for admitting one is exact: the field has to name a location the whole
34
+ * call is relative to. `bash` runs in a directory; the four readers resolve
35
+ * their subject against the workspace root. Everything else — an edit, a patch,
36
+ * a web fetch, a memory write — either names no location or writes, and both
37
+ * are refused above this module.
38
+ *
39
+ * `test` is deliberately absent. It answers this exact question already, with
40
+ * `against: "base"`, and a second mechanism pointed at the same tree is a way
41
+ * for two answers to disagree.
42
+ */
43
+ const located = {
44
+ bash: { field: "cwd", kind: "cwd" },
45
+ read: { field: "path", kind: "path" },
46
+ ls: { field: "path", kind: "path" },
47
+ grep: { field: "root", kind: "path" },
48
+ glob: { field: "root", kind: "path" }
49
+ };
50
+ /**
51
+ * Resolves `.` and `..` inside a relative path, or answers `undefined` when the
52
+ * path climbs out of whatever it would be joined under.
53
+ *
54
+ * This is the whole of the isolation the reader rule can enforce, and it is not
55
+ * optional. Prefixing blindly turns `../../mod.py` into
56
+ * `.flows-checkpoints/cp-1-0/../../mod.py`, which is a path back into the live
57
+ * tree — so the cell would read the work it is trying to take a baseline
58
+ * against, the journal would record that reading under the checkpoint it named,
59
+ * and the call key folds the checkpoint in, so the live reading would replay as
60
+ * a pinned one forever. A proof built on it is a proof of nothing, which is the
61
+ * exact failure this module exists to abolish.
62
+ */
63
+ const contained = (path) => {
64
+ const parts = [];
65
+ for (const segment of path.split("/")) {
66
+ if (segment === "" || segment === ".")
67
+ continue;
68
+ if (segment !== "..") {
69
+ parts.push(segment);
70
+ continue;
71
+ }
72
+ if (parts.length === 0)
73
+ return undefined;
74
+ parts.pop();
75
+ }
76
+ return parts.join("/");
77
+ };
78
+ /**
79
+ * The part of `declared` that names a place inside `root`, or `undefined` when
80
+ * it names somewhere the checkpoint does not hold a copy of.
81
+ *
82
+ * A relative path is already workspace-relative. An absolute one is compared
83
+ * against the root on the side that issued it — a container call names the
84
+ * mount, a host call names this machine — because that is the only prefix the
85
+ * store can strip without guessing.
86
+ */
87
+ const within = (root, declared) => {
88
+ if (!declared.startsWith("/"))
89
+ return contained(declared);
90
+ if (withoutTrailingSlash(declared) === root)
91
+ return "";
92
+ return declared.startsWith(`${root}/`) ? contained(declared.slice(root.length + 1)) : undefined;
93
+ };
94
+ /**
95
+ * Rewrites one call's input so the call runs against a materialized checkpoint.
96
+ *
97
+ * Returns the rewritten input, or the reason there is none. A `bash` call runs
98
+ * in the checkpoint's directory — from the *guest* side when it names a
99
+ * container, because that is the path the container will be given — and keeps
100
+ * whatever subdirectory it asked for: a check declared in `tests/` runs in the
101
+ * checkpoint's `tests/`. A working directory the checkpoint holds no copy of,
102
+ * such as somewhere else on the machine, becomes the checkpoint's own top,
103
+ * because a tree is all this can offer and there is no subpath in it to keep.
104
+ *
105
+ * A reader takes the checkpoint's workspace-relative directory as the prefix of
106
+ * what it names, because these flows resolve their subject against the
107
+ * workspace root and the checkpoint is a directory under it.
108
+ *
109
+ * Two paths are refused rather than rewritten, and both for the same reason —
110
+ * the host would otherwise hand back a reading of a tree the cell did not name.
111
+ * An absolute path in these runs is a container path, and the host cannot know
112
+ * which prefix of it names the tree. A relative path that climbs past the
113
+ * checkpoint with `..` names the live tree, exactly the tree the reading was
114
+ * taken to avoid.
115
+ *
116
+ * @category conversions
117
+ * @since 1.0.0
118
+ */
119
+ export const relocate = (flow, input, materialized) => {
120
+ const rule = located[flow];
121
+ if (rule === undefined)
122
+ return { _tag: "UnsupportedFlow" };
123
+ const record = input !== null && typeof input === "object" && !Array.isArray(input)
124
+ ? input
125
+ : {};
126
+ const declared = record[rule.field];
127
+ if (rule.kind === "cwd") {
128
+ // A container call is given the path the container will resolve; a host
129
+ // call is given the host's. `bash` chooses which by naming a container, so
130
+ // this reads the same field it does.
131
+ const containerised = typeof record["container"] === "string" && record["container"] !== "";
132
+ const base = containerised ? materialized.guest : materialized.host;
133
+ const kept = typeof declared === "string" && declared !== ""
134
+ ? within(containerised ? materialized.guestRoot : materialized.root, declared)
135
+ : "";
136
+ return {
137
+ _tag: "Relocated",
138
+ input: { ...record, cwd: kept === undefined || kept === "" ? base : `${base}/${kept}` }
139
+ };
140
+ }
141
+ const relative = materialized.host.slice(withoutTrailingSlash(materialized.root).length + 1);
142
+ if (declared === undefined)
143
+ return { _tag: "Relocated", input: { ...record, [rule.field]: relative } };
144
+ if (typeof declared !== "string")
145
+ return { _tag: "UnsupportedFlow" };
146
+ if (declared.startsWith("/"))
147
+ return { _tag: "AbsolutePath", path: declared };
148
+ const kept = contained(declared);
149
+ if (kept === undefined)
150
+ return { _tag: "OutsideTree", path: declared };
151
+ return { _tag: "Relocated", input: { ...record, [rule.field]: kept === "" ? relative : `${relative}/${kept}` } };
152
+ };
153
+ //# sourceMappingURL=Relocate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Relocate.js","sourceRoot":"","sources":["../../src/Relocate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What can be pointed at a checkpoint, and what cannot.\n *\n * {@link relocate} is the closed answer, and it is the half of the checkpoint\n * feature that tracks the flows rather than git: it knows that `bash` carries\n * its working directory in `cwd` and that `read`, `ls`, `grep` and `glob` carry\n * their subject in `path`, `path`, `root` and `root`. `Checkpoints` changes when\n * git does; this changes when one of those five input shapes does, which is why\n * it is a module of its own. `Relocate.test.ts` decodes every rewritten input\n * with the flow's own `Input` schema, so a renamed field fails there rather than\n * silently relocating nothing.\n *\n * `bash` names *where it runs*, so it is relocated by its `cwd` — into the\n * checkpoint, and into the same subdirectory of it the call asked for, because a\n * check declared in `tests/` that silently ran at the top would come back\n * failing for a reason nobody chose. `read`, `ls`, `grep` and `glob` name *what\n * they touch* relative to the workspace root, so they are relocated by prefixing\n * that root — and only when the path they name stays inside the tree, because an\n * absolute path in these runs is a container path the host cannot rebase and a\n * `..` path is the live tree under another name. Every other flow answers\n * `checkpoint_unsupported` through the harness, including `test`, which already\n * has `against: \"base\"` for exactly this question and would otherwise have two\n * mechanisms that can disagree.\n *\n * @since 1.0.0\n */\n\nimport type { Schema } from \"effect\"\nimport type { Materialized } from \"./Checkpoints.ts\"\nimport { withoutTrailingSlash } from \"./internal/Paths.ts\"\n\n/**\n * The flows whose input names where they run or what they read, and the field\n * that says so.\n *\n * A closed table rather than a per-flow hook, because the set is small and the\n * rule for admitting one is exact: the field has to name a location the whole\n * call is relative to. `bash` runs in a directory; the four readers resolve\n * their subject against the workspace root. Everything else — an edit, a patch,\n * a web fetch, a memory write — either names no location or writes, and both\n * are refused above this module.\n *\n * `test` is deliberately absent. It answers this exact question already, with\n * `against: \"base\"`, and a second mechanism pointed at the same tree is a way\n * for two answers to disagree.\n */\nconst located: Readonly<Record<string, { readonly field: string; readonly kind: \"cwd\" | \"path\" }>> = {\n bash: { field: \"cwd\", kind: \"cwd\" },\n read: { field: \"path\", kind: \"path\" },\n ls: { field: \"path\", kind: \"path\" },\n grep: { field: \"root\", kind: \"path\" },\n glob: { field: \"root\", kind: \"path\" }\n}\n\n/**\n * Why one input could not be pointed at a checkpoint.\n *\n * @category models\n * @since 1.0.0\n */\nexport type Relocation =\n | { readonly _tag: \"Relocated\"; readonly input: Schema.Json }\n | { readonly _tag: \"UnsupportedFlow\" }\n | { readonly _tag: \"AbsolutePath\"; readonly path: string }\n | { readonly _tag: \"OutsideTree\"; readonly path: string }\n\n/**\n * Resolves `.` and `..` inside a relative path, or answers `undefined` when the\n * path climbs out of whatever it would be joined under.\n *\n * This is the whole of the isolation the reader rule can enforce, and it is not\n * optional. Prefixing blindly turns `../../mod.py` into\n * `.flows-checkpoints/cp-1-0/../../mod.py`, which is a path back into the live\n * tree — so the cell would read the work it is trying to take a baseline\n * against, the journal would record that reading under the checkpoint it named,\n * and the call key folds the checkpoint in, so the live reading would replay as\n * a pinned one forever. A proof built on it is a proof of nothing, which is the\n * exact failure this module exists to abolish.\n */\nconst contained = (path: string): string | undefined => {\n const parts: Array<string> = []\n for (const segment of path.split(\"/\")) {\n if (segment === \"\" || segment === \".\") continue\n if (segment !== \"..\") {\n parts.push(segment)\n continue\n }\n if (parts.length === 0) return undefined\n parts.pop()\n }\n return parts.join(\"/\")\n}\n\n/**\n * The part of `declared` that names a place inside `root`, or `undefined` when\n * it names somewhere the checkpoint does not hold a copy of.\n *\n * A relative path is already workspace-relative. An absolute one is compared\n * against the root on the side that issued it — a container call names the\n * mount, a host call names this machine — because that is the only prefix the\n * store can strip without guessing.\n */\nconst within = (root: string, declared: string): string | undefined => {\n if (!declared.startsWith(\"/\")) return contained(declared)\n if (withoutTrailingSlash(declared) === root) return \"\"\n return declared.startsWith(`${root}/`) ? contained(declared.slice(root.length + 1)) : undefined\n}\n\n/**\n * Rewrites one call's input so the call runs against a materialized checkpoint.\n *\n * Returns the rewritten input, or the reason there is none. A `bash` call runs\n * in the checkpoint's directory — from the *guest* side when it names a\n * container, because that is the path the container will be given — and keeps\n * whatever subdirectory it asked for: a check declared in `tests/` runs in the\n * checkpoint's `tests/`. A working directory the checkpoint holds no copy of,\n * such as somewhere else on the machine, becomes the checkpoint's own top,\n * because a tree is all this can offer and there is no subpath in it to keep.\n *\n * A reader takes the checkpoint's workspace-relative directory as the prefix of\n * what it names, because these flows resolve their subject against the\n * workspace root and the checkpoint is a directory under it.\n *\n * Two paths are refused rather than rewritten, and both for the same reason —\n * the host would otherwise hand back a reading of a tree the cell did not name.\n * An absolute path in these runs is a container path, and the host cannot know\n * which prefix of it names the tree. A relative path that climbs past the\n * checkpoint with `..` names the live tree, exactly the tree the reading was\n * taken to avoid.\n *\n * @category conversions\n * @since 1.0.0\n */\nexport const relocate = (\n flow: string,\n input: Schema.Json,\n materialized: Materialized\n): Relocation => {\n const rule = located[flow]\n if (rule === undefined) return { _tag: \"UnsupportedFlow\" }\n const record = input !== null && typeof input === \"object\" && !Array.isArray(input)\n ? input as Record<string, Schema.Json>\n : {}\n const declared = record[rule.field]\n if (rule.kind === \"cwd\") {\n // A container call is given the path the container will resolve; a host\n // call is given the host's. `bash` chooses which by naming a container, so\n // this reads the same field it does.\n const containerised = typeof record[\"container\"] === \"string\" && record[\"container\"] !== \"\"\n const base = containerised ? materialized.guest : materialized.host\n const kept = typeof declared === \"string\" && declared !== \"\"\n ? within(containerised ? materialized.guestRoot : materialized.root, declared)\n : \"\"\n return {\n _tag: \"Relocated\",\n input: { ...record, cwd: kept === undefined || kept === \"\" ? base : `${base}/${kept}` }\n }\n }\n const relative = materialized.host.slice(withoutTrailingSlash(materialized.root).length + 1)\n if (declared === undefined) return { _tag: \"Relocated\", input: { ...record, [rule.field]: relative } }\n if (typeof declared !== \"string\") return { _tag: \"UnsupportedFlow\" }\n if (declared.startsWith(\"/\")) return { _tag: \"AbsolutePath\", path: declared }\n const kept = contained(declared)\n if (kept === undefined) return { _tag: \"OutsideTree\", path: declared }\n return { _tag: \"Relocated\", input: { ...record, [rule.field]: kept === \"\" ? relative : `${relative}/${kept}` } }\n}\n"]}