@smthrs/std 0.0.0-stage → 1.0.0-rc.12
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.
- package/CHANGELOG.md +148 -0
- package/LICENSE +21 -0
- package/README.md +156 -2
- package/dist/cjs/ApplyPatch.d.ts +174 -0
- package/dist/cjs/ApplyPatch.d.ts.map +1 -0
- package/dist/cjs/ApplyPatch.js +309 -0
- package/dist/cjs/ApplyPatch.js.map +7 -0
- package/dist/cjs/Bash.d.ts +390 -0
- package/dist/cjs/Bash.d.ts.map +1 -0
- package/dist/cjs/Bash.js +333 -0
- package/dist/cjs/Bash.js.map +7 -0
- package/dist/cjs/Checkpoints.d.ts +322 -0
- package/dist/cjs/Checkpoints.d.ts.map +1 -0
- package/dist/cjs/Checkpoints.js +233 -0
- package/dist/cjs/Checkpoints.js.map +7 -0
- package/dist/cjs/Container.d.ts +132 -0
- package/dist/cjs/Container.d.ts.map +1 -0
- package/dist/cjs/Container.js +113 -0
- package/dist/cjs/Container.js.map +7 -0
- package/dist/cjs/Edit.d.ts +203 -0
- package/dist/cjs/Edit.d.ts.map +1 -0
- package/dist/cjs/Edit.js +258 -0
- package/dist/cjs/Edit.js.map +7 -0
- package/dist/cjs/ExaWebSearch.d.ts +22 -0
- package/dist/cjs/ExaWebSearch.d.ts.map +1 -0
- package/dist/cjs/ExaWebSearch.js +138 -0
- package/dist/cjs/ExaWebSearch.js.map +7 -0
- package/dist/cjs/Explore.d.ts +328 -0
- package/dist/cjs/Explore.d.ts.map +1 -0
- package/dist/cjs/Explore.js +90 -0
- package/dist/cjs/Explore.js.map +7 -0
- package/dist/cjs/Fetch.d.ts +130 -0
- package/dist/cjs/Fetch.d.ts.map +1 -0
- package/dist/cjs/Fetch.js +64 -0
- package/dist/cjs/Fetch.js.map +7 -0
- package/dist/cjs/Glob.d.ts +204 -0
- package/dist/cjs/Glob.d.ts.map +1 -0
- package/dist/cjs/Glob.js +94 -0
- package/dist/cjs/Glob.js.map +7 -0
- package/dist/cjs/Grep.d.ts +347 -0
- package/dist/cjs/Grep.d.ts.map +1 -0
- package/dist/cjs/Grep.js +181 -0
- package/dist/cjs/Grep.js.map +7 -0
- package/dist/cjs/HttpPost.d.ts +130 -0
- package/dist/cjs/HttpPost.d.ts.map +1 -0
- package/dist/cjs/HttpPost.js +72 -0
- package/dist/cjs/HttpPost.js.map +7 -0
- package/dist/cjs/LanguageServer.d.ts +90 -0
- package/dist/cjs/LanguageServer.d.ts.map +1 -0
- package/dist/cjs/LanguageServer.js +60 -0
- package/dist/cjs/LanguageServer.js.map +7 -0
- package/dist/cjs/Ls.d.ts +164 -0
- package/dist/cjs/Ls.d.ts.map +1 -0
- package/dist/cjs/Ls.js +136 -0
- package/dist/cjs/Ls.js.map +7 -0
- package/dist/cjs/Lsp.d.ts +125 -0
- package/dist/cjs/Lsp.d.ts.map +1 -0
- package/dist/cjs/Lsp.js +137 -0
- package/dist/cjs/Lsp.js.map +7 -0
- package/dist/cjs/Manifest.d.ts +918 -0
- package/dist/cjs/Manifest.d.ts.map +1 -0
- package/dist/cjs/Manifest.js +144 -0
- package/dist/cjs/Manifest.js.map +7 -0
- package/dist/cjs/NativeSearch.d.ts +38 -0
- package/dist/cjs/NativeSearch.d.ts.map +1 -0
- package/dist/cjs/NativeSearch.js +326 -0
- package/dist/cjs/NativeSearch.js.map +7 -0
- package/dist/cjs/NodeLanguageServer.d.ts +128 -0
- package/dist/cjs/NodeLanguageServer.d.ts.map +1 -0
- package/dist/cjs/NodeLanguageServer.js +796 -0
- package/dist/cjs/NodeLanguageServer.js.map +7 -0
- package/dist/cjs/PortableSearch.d.ts +36 -0
- package/dist/cjs/PortableSearch.d.ts.map +1 -0
- package/dist/cjs/PortableSearch.js +240 -0
- package/dist/cjs/PortableSearch.js.map +7 -0
- package/dist/cjs/Probe.d.ts +193 -0
- package/dist/cjs/Probe.d.ts.map +1 -0
- package/dist/cjs/Probe.js +134 -0
- package/dist/cjs/Probe.js.map +7 -0
- package/dist/cjs/Read.d.ts +189 -0
- package/dist/cjs/Read.d.ts.map +1 -0
- package/dist/cjs/Read.js +223 -0
- package/dist/cjs/Read.js.map +7 -0
- package/dist/cjs/Relocate.d.ts +73 -0
- package/dist/cjs/Relocate.d.ts.map +1 -0
- package/dist/cjs/Relocate.js +72 -0
- package/dist/cjs/Relocate.js.map +7 -0
- package/dist/cjs/RemoteSearch.d.ts +54 -0
- package/dist/cjs/RemoteSearch.d.ts.map +1 -0
- package/dist/cjs/RemoteSearch.js +134 -0
- package/dist/cjs/RemoteSearch.js.map +7 -0
- package/dist/cjs/Search.d.ts +163 -0
- package/dist/cjs/Search.d.ts.map +1 -0
- package/dist/cjs/Search.js +51 -0
- package/dist/cjs/Search.js.map +7 -0
- package/dist/cjs/SearchConformance.d.ts +115 -0
- package/dist/cjs/SearchConformance.d.ts.map +1 -0
- package/dist/cjs/SearchConformance.js +172 -0
- package/dist/cjs/SearchConformance.js.map +7 -0
- package/dist/cjs/SearchContract.d.ts +114 -0
- package/dist/cjs/SearchContract.d.ts.map +1 -0
- package/dist/cjs/SearchContract.js +339 -0
- package/dist/cjs/SearchContract.js.map +7 -0
- package/dist/cjs/ShellCommand.d.ts +164 -0
- package/dist/cjs/ShellCommand.d.ts.map +1 -0
- package/dist/cjs/ShellCommand.js +102 -0
- package/dist/cjs/ShellCommand.js.map +7 -0
- package/dist/cjs/StdError.d.ts +55 -0
- package/dist/cjs/StdError.d.ts.map +1 -0
- package/dist/cjs/StdError.js +74 -0
- package/dist/cjs/StdError.js.map +7 -0
- package/dist/cjs/TestRun.d.ts +311 -0
- package/dist/cjs/TestRun.d.ts.map +1 -0
- package/dist/cjs/TestRun.js +228 -0
- package/dist/cjs/TestRun.js.map +7 -0
- package/dist/cjs/TestRunner.d.ts +102 -0
- package/dist/cjs/TestRunner.d.ts.map +1 -0
- package/dist/cjs/TestRunner.js +54 -0
- package/dist/cjs/TestRunner.js.map +7 -0
- package/dist/cjs/TreeFingerprint.d.ts +140 -0
- package/dist/cjs/TreeFingerprint.d.ts.map +1 -0
- package/dist/cjs/TreeFingerprint.js +87 -0
- package/dist/cjs/TreeFingerprint.js.map +7 -0
- package/dist/cjs/UpdatePlan.d.ts +152 -0
- package/dist/cjs/UpdatePlan.d.ts.map +1 -0
- package/dist/cjs/UpdatePlan.js +87 -0
- package/dist/cjs/UpdatePlan.js.map +7 -0
- package/dist/cjs/WebFetch.d.ts +134 -0
- package/dist/cjs/WebFetch.d.ts.map +1 -0
- package/dist/cjs/WebFetch.js +140 -0
- package/dist/cjs/WebFetch.js.map +7 -0
- package/dist/cjs/WebSearch.d.ts +181 -0
- package/dist/cjs/WebSearch.d.ts.map +1 -0
- package/dist/cjs/WebSearch.js +86 -0
- package/dist/cjs/WebSearch.js.map +7 -0
- package/dist/cjs/Write.d.ts +147 -0
- package/dist/cjs/Write.d.ts.map +1 -0
- package/dist/cjs/Write.js +122 -0
- package/dist/cjs/Write.js.map +7 -0
- package/dist/cjs/index.d.ts +129 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +101 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/ApplyPatch.d.ts +145 -0
- package/dist/cjs/internal/ApplyPatch.d.ts.map +1 -0
- package/dist/cjs/internal/ApplyPatch.js +462 -0
- package/dist/cjs/internal/ApplyPatch.js.map +7 -0
- package/dist/cjs/internal/CodexText.d.ts +73 -0
- package/dist/cjs/internal/CodexText.d.ts.map +1 -0
- package/dist/cjs/internal/CodexText.js +108 -0
- package/dist/cjs/internal/CodexText.js.map +7 -0
- package/dist/cjs/internal/Declaration.d.ts +49 -0
- package/dist/cjs/internal/Declaration.d.ts.map +1 -0
- package/dist/cjs/internal/Declaration.js +46 -0
- package/dist/cjs/internal/Declaration.js.map +7 -0
- package/dist/cjs/internal/Diagnostics.d.ts +77 -0
- package/dist/cjs/internal/Diagnostics.d.ts.map +1 -0
- package/dist/cjs/internal/Diagnostics.js +89 -0
- package/dist/cjs/internal/Diagnostics.js.map +7 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts +69 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/cjs/internal/EnvelopePrecheck.js +323 -0
- package/dist/cjs/internal/EnvelopePrecheck.js.map +7 -0
- package/dist/cjs/internal/Exec.d.ts +151 -0
- package/dist/cjs/internal/Exec.d.ts.map +1 -0
- package/dist/cjs/internal/Exec.js +207 -0
- package/dist/cjs/internal/Exec.js.map +7 -0
- package/dist/cjs/internal/FileMutation.d.ts +109 -0
- package/dist/cjs/internal/FileMutation.d.ts.map +1 -0
- package/dist/cjs/internal/FileMutation.js +116 -0
- package/dist/cjs/internal/FileMutation.js.map +7 -0
- package/dist/cjs/internal/FsFailure.d.ts +38 -0
- package/dist/cjs/internal/FsFailure.d.ts.map +1 -0
- package/dist/cjs/internal/FsFailure.js +40 -0
- package/dist/cjs/internal/FsFailure.js.map +7 -0
- package/dist/cjs/internal/GitWorktree.d.ts +108 -0
- package/dist/cjs/internal/GitWorktree.d.ts.map +1 -0
- package/dist/cjs/internal/GitWorktree.js +276 -0
- package/dist/cjs/internal/GitWorktree.js.map +7 -0
- package/dist/cjs/internal/Grouping.d.ts +51 -0
- package/dist/cjs/internal/Grouping.d.ts.map +1 -0
- package/dist/cjs/internal/Grouping.js +83 -0
- package/dist/cjs/internal/Grouping.js.map +7 -0
- package/dist/cjs/internal/Html.d.ts +20 -0
- package/dist/cjs/internal/Html.d.ts.map +1 -0
- package/dist/cjs/internal/Html.js +81 -0
- package/dist/cjs/internal/Html.js.map +7 -0
- package/dist/cjs/internal/Http.d.ts +95 -0
- package/dist/cjs/internal/Http.d.ts.map +1 -0
- package/dist/cjs/internal/Http.js +153 -0
- package/dist/cjs/internal/Http.js.map +7 -0
- package/dist/cjs/internal/HttpNetwork.d.ts +27 -0
- package/dist/cjs/internal/HttpNetwork.d.ts.map +1 -0
- package/dist/cjs/internal/HttpNetwork.js +146 -0
- package/dist/cjs/internal/HttpNetwork.js.map +7 -0
- package/dist/cjs/internal/Ignore.d.ts +37 -0
- package/dist/cjs/internal/Ignore.d.ts.map +1 -0
- package/dist/cjs/internal/Ignore.js +100 -0
- package/dist/cjs/internal/Ignore.js.map +7 -0
- package/dist/cjs/internal/LinearRegex.d.ts +19 -0
- package/dist/cjs/internal/LinearRegex.d.ts.map +1 -0
- package/dist/cjs/internal/LinearRegex.js +166 -0
- package/dist/cjs/internal/LinearRegex.js.map +7 -0
- package/dist/cjs/internal/Match.d.ts +85 -0
- package/dist/cjs/internal/Match.d.ts.map +1 -0
- package/dist/cjs/internal/Match.js +99 -0
- package/dist/cjs/internal/Match.js.map +7 -0
- package/dist/cjs/internal/Paths.d.ts +23 -0
- package/dist/cjs/internal/Paths.d.ts.map +1 -0
- package/dist/cjs/internal/Paths.js +52 -0
- package/dist/cjs/internal/Paths.js.map +7 -0
- package/dist/cjs/internal/Preserve.d.ts +25 -0
- package/dist/cjs/internal/Preserve.d.ts.map +1 -0
- package/dist/cjs/internal/Preserve.js +88 -0
- package/dist/cjs/internal/Preserve.js.map +7 -0
- package/dist/cjs/internal/Prune.d.ts +35 -0
- package/dist/cjs/internal/Prune.d.ts.map +1 -0
- package/dist/cjs/internal/Prune.js +54 -0
- package/dist/cjs/internal/Prune.js.map +7 -0
- package/dist/cjs/internal/RemoteTree.d.ts +60 -0
- package/dist/cjs/internal/RemoteTree.d.ts.map +1 -0
- package/dist/cjs/internal/RemoteTree.js +123 -0
- package/dist/cjs/internal/RemoteTree.js.map +7 -0
- package/dist/cjs/internal/SearchContract.d.ts +63 -0
- package/dist/cjs/internal/SearchContract.d.ts.map +1 -0
- package/dist/cjs/internal/SearchContract.js +46 -0
- package/dist/cjs/internal/SearchContract.js.map +7 -0
- package/dist/cjs/internal/Symbols.d.ts +39 -0
- package/dist/cjs/internal/Symbols.d.ts.map +1 -0
- package/dist/cjs/internal/Symbols.js +59 -0
- package/dist/cjs/internal/Symbols.js.map +7 -0
- package/dist/cjs/internal/Tar.d.ts +23 -0
- package/dist/cjs/internal/Tar.d.ts.map +1 -0
- package/dist/cjs/internal/Tar.js +86 -0
- package/dist/cjs/internal/Tar.js.map +7 -0
- package/dist/cjs/internal/TestReport.d.ts +52 -0
- package/dist/cjs/internal/TestReport.d.ts.map +1 -0
- package/dist/cjs/internal/TestReport.js +131 -0
- package/dist/cjs/internal/TestReport.js.map +7 -0
- package/dist/cjs/internal/Text.d.ts +125 -0
- package/dist/cjs/internal/Text.d.ts.map +1 -0
- package/dist/cjs/internal/Text.js +85 -0
- package/dist/cjs/internal/Text.js.map +7 -0
- package/dist/cjs/internal/Url.d.ts +13 -0
- package/dist/cjs/internal/Url.d.ts.map +1 -0
- package/dist/cjs/internal/Url.js +35 -0
- package/dist/cjs/internal/Url.js.map +7 -0
- package/dist/cjs/internal/Walk.d.ts +72 -0
- package/dist/cjs/internal/Walk.d.ts.map +1 -0
- package/dist/cjs/internal/Walk.js +108 -0
- package/dist/cjs/internal/Walk.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/ApplyPatch.d.ts +174 -0
- package/dist/esm/ApplyPatch.d.ts.map +1 -0
- package/dist/esm/ApplyPatch.js +346 -0
- package/dist/esm/ApplyPatch.js.map +1 -0
- package/dist/esm/Bash.d.ts +390 -0
- package/dist/esm/Bash.d.ts.map +1 -0
- package/dist/esm/Bash.js +514 -0
- package/dist/esm/Bash.js.map +1 -0
- package/dist/esm/Checkpoints.d.ts +322 -0
- package/dist/esm/Checkpoints.d.ts.map +1 -0
- package/dist/esm/Checkpoints.js +396 -0
- package/dist/esm/Checkpoints.js.map +1 -0
- package/dist/esm/Container.d.ts +132 -0
- package/dist/esm/Container.d.ts.map +1 -0
- package/dist/esm/Container.js +151 -0
- package/dist/esm/Container.js.map +1 -0
- package/dist/esm/Edit.d.ts +203 -0
- package/dist/esm/Edit.d.ts.map +1 -0
- package/dist/esm/Edit.js +296 -0
- package/dist/esm/Edit.js.map +1 -0
- package/dist/esm/ExaWebSearch.d.ts +22 -0
- package/dist/esm/ExaWebSearch.d.ts.map +1 -0
- package/dist/esm/ExaWebSearch.js +107 -0
- package/dist/esm/ExaWebSearch.js.map +1 -0
- package/dist/esm/Explore.d.ts +328 -0
- package/dist/esm/Explore.d.ts.map +1 -0
- package/dist/esm/Explore.js +106 -0
- package/dist/esm/Explore.js.map +1 -0
- package/dist/esm/Fetch.d.ts +130 -0
- package/dist/esm/Fetch.d.ts.map +1 -0
- package/dist/esm/Fetch.js +91 -0
- package/dist/esm/Fetch.js.map +1 -0
- package/dist/esm/Glob.d.ts +204 -0
- package/dist/esm/Glob.d.ts.map +1 -0
- package/dist/esm/Glob.js +177 -0
- package/dist/esm/Glob.js.map +1 -0
- package/dist/esm/Grep.d.ts +347 -0
- package/dist/esm/Grep.d.ts.map +1 -0
- package/dist/esm/Grep.js +289 -0
- package/dist/esm/Grep.js.map +1 -0
- package/dist/esm/HttpPost.d.ts +130 -0
- package/dist/esm/HttpPost.d.ts.map +1 -0
- package/dist/esm/HttpPost.js +89 -0
- package/dist/esm/HttpPost.js.map +1 -0
- package/dist/esm/LanguageServer.d.ts +90 -0
- package/dist/esm/LanguageServer.d.ts.map +1 -0
- package/dist/esm/LanguageServer.js +57 -0
- package/dist/esm/LanguageServer.js.map +1 -0
- package/dist/esm/Ls.d.ts +164 -0
- package/dist/esm/Ls.d.ts.map +1 -0
- package/dist/esm/Ls.js +178 -0
- package/dist/esm/Ls.js.map +1 -0
- package/dist/esm/Lsp.d.ts +125 -0
- package/dist/esm/Lsp.d.ts.map +1 -0
- package/dist/esm/Lsp.js +165 -0
- package/dist/esm/Lsp.js.map +1 -0
- package/dist/esm/Manifest.d.ts +918 -0
- package/dist/esm/Manifest.d.ts.map +1 -0
- package/dist/esm/Manifest.js +153 -0
- package/dist/esm/Manifest.js.map +1 -0
- package/dist/esm/NativeSearch.d.ts +38 -0
- package/dist/esm/NativeSearch.d.ts.map +1 -0
- package/dist/esm/NativeSearch.js +378 -0
- package/dist/esm/NativeSearch.js.map +1 -0
- package/dist/esm/NodeLanguageServer.d.ts +128 -0
- package/dist/esm/NodeLanguageServer.d.ts.map +1 -0
- package/dist/esm/NodeLanguageServer.js +843 -0
- package/dist/esm/NodeLanguageServer.js.map +1 -0
- package/dist/esm/PortableSearch.d.ts +36 -0
- package/dist/esm/PortableSearch.d.ts.map +1 -0
- package/dist/esm/PortableSearch.js +256 -0
- package/dist/esm/PortableSearch.js.map +1 -0
- package/dist/esm/Probe.d.ts +193 -0
- package/dist/esm/Probe.d.ts.map +1 -0
- package/dist/esm/Probe.js +225 -0
- package/dist/esm/Probe.js.map +1 -0
- package/dist/esm/Read.d.ts +189 -0
- package/dist/esm/Read.d.ts.map +1 -0
- package/dist/esm/Read.js +300 -0
- package/dist/esm/Read.js.map +1 -0
- package/dist/esm/Relocate.d.ts +73 -0
- package/dist/esm/Relocate.d.ts.map +1 -0
- package/dist/esm/Relocate.js +153 -0
- package/dist/esm/Relocate.js.map +1 -0
- package/dist/esm/RemoteSearch.d.ts +54 -0
- package/dist/esm/RemoteSearch.d.ts.map +1 -0
- package/dist/esm/RemoteSearch.js +162 -0
- package/dist/esm/RemoteSearch.js.map +1 -0
- package/dist/esm/Search.d.ts +163 -0
- package/dist/esm/Search.d.ts.map +1 -0
- package/dist/esm/Search.js +47 -0
- package/dist/esm/Search.js.map +1 -0
- package/dist/esm/SearchConformance.d.ts +115 -0
- package/dist/esm/SearchConformance.d.ts.map +1 -0
- package/dist/esm/SearchConformance.js +193 -0
- package/dist/esm/SearchConformance.js.map +1 -0
- package/dist/esm/SearchContract.d.ts +114 -0
- package/dist/esm/SearchContract.d.ts.map +1 -0
- package/dist/esm/SearchContract.js +461 -0
- package/dist/esm/SearchContract.js.map +1 -0
- package/dist/esm/ShellCommand.d.ts +164 -0
- package/dist/esm/ShellCommand.d.ts.map +1 -0
- package/dist/esm/ShellCommand.js +159 -0
- package/dist/esm/ShellCommand.js.map +1 -0
- package/dist/esm/StdError.d.ts +55 -0
- package/dist/esm/StdError.d.ts.map +1 -0
- package/dist/esm/StdError.js +71 -0
- package/dist/esm/StdError.js.map +1 -0
- package/dist/esm/TestRun.d.ts +311 -0
- package/dist/esm/TestRun.d.ts.map +1 -0
- package/dist/esm/TestRun.js +316 -0
- package/dist/esm/TestRun.js.map +1 -0
- package/dist/esm/TestRunner.d.ts +102 -0
- package/dist/esm/TestRunner.d.ts.map +1 -0
- package/dist/esm/TestRunner.js +68 -0
- package/dist/esm/TestRunner.js.map +1 -0
- package/dist/esm/TreeFingerprint.d.ts +140 -0
- package/dist/esm/TreeFingerprint.d.ts.map +1 -0
- package/dist/esm/TreeFingerprint.js +170 -0
- package/dist/esm/TreeFingerprint.js.map +1 -0
- package/dist/esm/UpdatePlan.d.ts +152 -0
- package/dist/esm/UpdatePlan.d.ts.map +1 -0
- package/dist/esm/UpdatePlan.js +129 -0
- package/dist/esm/UpdatePlan.js.map +1 -0
- package/dist/esm/WebFetch.d.ts +134 -0
- package/dist/esm/WebFetch.d.ts.map +1 -0
- package/dist/esm/WebFetch.js +151 -0
- package/dist/esm/WebFetch.js.map +1 -0
- package/dist/esm/WebSearch.d.ts +181 -0
- package/dist/esm/WebSearch.d.ts.map +1 -0
- package/dist/esm/WebSearch.js +134 -0
- package/dist/esm/WebSearch.js.map +1 -0
- package/dist/esm/Write.d.ts +147 -0
- package/dist/esm/Write.d.ts.map +1 -0
- package/dist/esm/Write.js +144 -0
- package/dist/esm/Write.js.map +1 -0
- package/dist/esm/index.d.ts +129 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +129 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/ApplyPatch.d.ts +145 -0
- package/dist/esm/internal/ApplyPatch.d.ts.map +1 -0
- package/dist/esm/internal/ApplyPatch.js +489 -0
- package/dist/esm/internal/ApplyPatch.js.map +1 -0
- package/dist/esm/internal/CodexText.d.ts +73 -0
- package/dist/esm/internal/CodexText.d.ts.map +1 -0
- package/dist/esm/internal/CodexText.js +156 -0
- package/dist/esm/internal/CodexText.js.map +1 -0
- package/dist/esm/internal/Declaration.d.ts +49 -0
- package/dist/esm/internal/Declaration.d.ts.map +1 -0
- package/dist/esm/internal/Declaration.js +42 -0
- package/dist/esm/internal/Declaration.js.map +1 -0
- package/dist/esm/internal/Diagnostics.d.ts +77 -0
- package/dist/esm/internal/Diagnostics.d.ts.map +1 -0
- package/dist/esm/internal/Diagnostics.js +99 -0
- package/dist/esm/internal/Diagnostics.js.map +1 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts +69 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/esm/internal/EnvelopePrecheck.js +426 -0
- package/dist/esm/internal/EnvelopePrecheck.js.map +1 -0
- package/dist/esm/internal/Exec.d.ts +151 -0
- package/dist/esm/internal/Exec.d.ts.map +1 -0
- package/dist/esm/internal/Exec.js +285 -0
- package/dist/esm/internal/Exec.js.map +1 -0
- package/dist/esm/internal/FileMutation.d.ts +109 -0
- package/dist/esm/internal/FileMutation.d.ts.map +1 -0
- package/dist/esm/internal/FileMutation.js +123 -0
- package/dist/esm/internal/FileMutation.js.map +1 -0
- package/dist/esm/internal/FsFailure.d.ts +38 -0
- package/dist/esm/internal/FsFailure.d.ts.map +1 -0
- package/dist/esm/internal/FsFailure.js +39 -0
- package/dist/esm/internal/FsFailure.js.map +1 -0
- package/dist/esm/internal/GitWorktree.d.ts +108 -0
- package/dist/esm/internal/GitWorktree.d.ts.map +1 -0
- package/dist/esm/internal/GitWorktree.js +352 -0
- package/dist/esm/internal/GitWorktree.js.map +1 -0
- package/dist/esm/internal/Grouping.d.ts +51 -0
- package/dist/esm/internal/Grouping.d.ts.map +1 -0
- package/dist/esm/internal/Grouping.js +99 -0
- package/dist/esm/internal/Grouping.js.map +1 -0
- package/dist/esm/internal/Html.d.ts +20 -0
- package/dist/esm/internal/Html.d.ts.map +1 -0
- package/dist/esm/internal/Html.js +70 -0
- package/dist/esm/internal/Html.js.map +1 -0
- package/dist/esm/internal/Http.d.ts +95 -0
- package/dist/esm/internal/Http.d.ts.map +1 -0
- package/dist/esm/internal/Http.js +154 -0
- package/dist/esm/internal/Http.js.map +1 -0
- package/dist/esm/internal/HttpNetwork.d.ts +27 -0
- package/dist/esm/internal/HttpNetwork.d.ts.map +1 -0
- package/dist/esm/internal/HttpNetwork.js +114 -0
- package/dist/esm/internal/HttpNetwork.js.map +1 -0
- package/dist/esm/internal/Ignore.d.ts +37 -0
- package/dist/esm/internal/Ignore.d.ts.map +1 -0
- package/dist/esm/internal/Ignore.js +128 -0
- package/dist/esm/internal/Ignore.js.map +1 -0
- package/dist/esm/internal/LinearRegex.d.ts +19 -0
- package/dist/esm/internal/LinearRegex.d.ts.map +1 -0
- package/dist/esm/internal/LinearRegex.js +176 -0
- package/dist/esm/internal/LinearRegex.js.map +1 -0
- package/dist/esm/internal/Match.d.ts +85 -0
- package/dist/esm/internal/Match.d.ts.map +1 -0
- package/dist/esm/internal/Match.js +142 -0
- package/dist/esm/internal/Match.js.map +1 -0
- package/dist/esm/internal/Paths.d.ts +23 -0
- package/dist/esm/internal/Paths.d.ts.map +1 -0
- package/dist/esm/internal/Paths.js +40 -0
- package/dist/esm/internal/Paths.js.map +1 -0
- package/dist/esm/internal/Preserve.d.ts +25 -0
- package/dist/esm/internal/Preserve.d.ts.map +1 -0
- package/dist/esm/internal/Preserve.js +70 -0
- package/dist/esm/internal/Preserve.js.map +1 -0
- package/dist/esm/internal/Prune.d.ts +35 -0
- package/dist/esm/internal/Prune.d.ts.map +1 -0
- package/dist/esm/internal/Prune.js +60 -0
- package/dist/esm/internal/Prune.js.map +1 -0
- package/dist/esm/internal/RemoteTree.d.ts +60 -0
- package/dist/esm/internal/RemoteTree.d.ts.map +1 -0
- package/dist/esm/internal/RemoteTree.js +132 -0
- package/dist/esm/internal/RemoteTree.js.map +1 -0
- package/dist/esm/internal/SearchContract.d.ts +63 -0
- package/dist/esm/internal/SearchContract.d.ts.map +1 -0
- package/dist/esm/internal/SearchContract.js +66 -0
- package/dist/esm/internal/SearchContract.js.map +1 -0
- package/dist/esm/internal/Symbols.d.ts +39 -0
- package/dist/esm/internal/Symbols.d.ts.map +1 -0
- package/dist/esm/internal/Symbols.js +79 -0
- package/dist/esm/internal/Symbols.js.map +1 -0
- package/dist/esm/internal/Tar.d.ts +23 -0
- package/dist/esm/internal/Tar.d.ts.map +1 -0
- package/dist/esm/internal/Tar.js +97 -0
- package/dist/esm/internal/Tar.js.map +1 -0
- package/dist/esm/internal/TestReport.d.ts +52 -0
- package/dist/esm/internal/TestReport.d.ts.map +1 -0
- package/dist/esm/internal/TestReport.js +172 -0
- package/dist/esm/internal/TestReport.js.map +1 -0
- package/dist/esm/internal/Text.d.ts +125 -0
- package/dist/esm/internal/Text.d.ts.map +1 -0
- package/dist/esm/internal/Text.js +141 -0
- package/dist/esm/internal/Text.js.map +1 -0
- package/dist/esm/internal/Url.d.ts +13 -0
- package/dist/esm/internal/Url.d.ts.map +1 -0
- package/dist/esm/internal/Url.js +27 -0
- package/dist/esm/internal/Url.js.map +1 -0
- package/dist/esm/internal/Walk.d.ts +72 -0
- package/dist/esm/internal/Walk.d.ts.map +1 -0
- package/dist/esm/internal/Walk.js +126 -0
- package/dist/esm/internal/Walk.js.map +1 -0
- package/docs/README.md +119 -0
- package/docs/api.md +499 -0
- package/docs/concepts/effects-and-capabilities.md +138 -0
- package/docs/concepts/flows-and-handlers.md +115 -0
- package/docs/concepts/limits-and-disclosure.md +105 -0
- package/docs/concepts/search-contract.md +182 -0
- package/docs/guides/bind-the-standard-flows.md +116 -0
- package/docs/guides/implement-a-search-peer.md +133 -0
- package/docs/guides/pin-a-checkpoint.md +161 -0
- package/docs/guides/query-a-language-server.md +257 -0
- package/docs/guides/reach-the-network.md +141 -0
- package/docs/guides/read-and-edit-a-file.md +240 -0
- package/docs/guides/run-a-shell-command.md +236 -0
- package/docs/guides/run-the-test-suite.md +154 -0
- package/docs/guides/search-a-workspace.md +148 -0
- package/docs/installation.md +115 -0
- package/docs/quickstart.md +125 -0
- package/docs/reference/flows.md +556 -0
- package/docs/troubleshooting.md +347 -0
- package/package.json +449 -3
- package/src/ApplyPatch.ts +458 -0
- package/src/Bash.ts +619 -0
- package/src/Checkpoints.ts +589 -0
- package/src/Container.ts +212 -0
- package/src/Edit.ts +366 -0
- package/src/ExaWebSearch.ts +145 -0
- package/src/Explore.ts +139 -0
- package/src/Fetch.ts +117 -0
- package/src/Glob.ts +200 -0
- package/src/Grep.ts +320 -0
- package/src/HttpPost.ts +120 -0
- package/src/LanguageServer.ts +110 -0
- package/src/Ls.ts +228 -0
- package/src/Lsp.ts +184 -0
- package/src/Manifest.ts +162 -0
- package/src/NativeSearch.ts +457 -0
- package/src/NodeLanguageServer.ts +1148 -0
- package/src/PortableSearch.ts +284 -0
- package/src/Probe.ts +284 -0
- package/src/Read.ts +359 -0
- package/src/Relocate.ts +166 -0
- package/src/RemoteSearch.ts +199 -0
- package/src/Search.ts +185 -0
- package/src/SearchConformance.ts +288 -0
- package/src/SearchContract.ts +489 -0
- package/src/ShellCommand.ts +201 -0
- package/src/StdError.ts +80 -0
- package/src/TestRun.ts +401 -0
- package/src/TestRunner.ts +119 -0
- package/src/TreeFingerprint.ts +200 -0
- package/src/UpdatePlan.ts +171 -0
- package/src/WebFetch.ts +194 -0
- package/src/WebSearch.ts +165 -0
- package/src/Write.ts +195 -0
- package/src/index.ts +157 -0
- package/src/internal/ApplyPatch.ts +601 -0
- package/src/internal/CodexText.ts +182 -0
- package/src/internal/Declaration.ts +60 -0
- package/src/internal/Diagnostics.ts +134 -0
- package/src/internal/EnvelopePrecheck.ts +489 -0
- package/src/internal/Exec.ts +427 -0
- package/src/internal/FileMutation.ts +231 -0
- package/src/internal/FsFailure.ts +51 -0
- package/src/internal/GitWorktree.ts +491 -0
- package/src/internal/Grouping.ts +106 -0
- package/src/internal/Html.ts +87 -0
- package/src/internal/Http.ts +209 -0
- package/src/internal/HttpNetwork.ts +153 -0
- package/src/internal/Ignore.ts +135 -0
- package/src/internal/LinearRegex.ts +173 -0
- package/src/internal/Match.ts +172 -0
- package/src/internal/Paths.ts +42 -0
- package/src/internal/Preserve.ts +108 -0
- package/src/internal/Prune.ts +62 -0
- package/src/internal/RemoteTree.ts +159 -0
- package/src/internal/SearchContract.ts +77 -0
- package/src/internal/Symbols.ts +88 -0
- package/src/internal/Tar.ts +95 -0
- package/src/internal/TestReport.ts +194 -0
- package/src/internal/Text.ts +185 -0
- package/src/internal/Url.ts +23 -0
- package/src/internal/Walk.ts +176 -0
package/dist/cjs/Read.js
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name2 in all)
|
|
10
|
+
__defProp(target, name2, { get: all[name2], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var Read_exports = {};
|
|
30
|
+
__export(Read_exports, {
|
|
31
|
+
Input: () => Input,
|
|
32
|
+
MAX_READ_FILE_BYTES: () => MAX_READ_FILE_BYTES,
|
|
33
|
+
Output: () => Output,
|
|
34
|
+
Preconditions: () => import_FileMutation.Preconditions,
|
|
35
|
+
ReadSession: () => import_FileMutation.ReadSession,
|
|
36
|
+
activity: () => activity,
|
|
37
|
+
capabilities: () => capabilities,
|
|
38
|
+
description: () => description,
|
|
39
|
+
effects: () => effects,
|
|
40
|
+
effectsFor: () => effectsFor,
|
|
41
|
+
flow: () => flow,
|
|
42
|
+
name: () => name,
|
|
43
|
+
presentation: () => presentation,
|
|
44
|
+
run: () => run
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(Read_exports);
|
|
47
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
48
|
+
var FileSystem = __toESM(require("effect/FileSystem"), 1);
|
|
49
|
+
var Option = __toESM(require("effect/Option"), 1);
|
|
50
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
51
|
+
var import_Declaration = require("./internal/Declaration.js");
|
|
52
|
+
var FileMutation = __toESM(require("./internal/FileMutation.js"), 1);
|
|
53
|
+
var FsFailure = __toESM(require("./internal/FsFailure.js"), 1);
|
|
54
|
+
var import_Text = require("./internal/Text.js");
|
|
55
|
+
var StdError = __toESM(require("./StdError.js"), 1);
|
|
56
|
+
var import_FileMutation = require("./internal/FileMutation.js");
|
|
57
|
+
const name = "read";
|
|
58
|
+
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.";
|
|
59
|
+
const Input = Schema.Struct({
|
|
60
|
+
path: Schema.String.annotate({ description: "Path of the text file to read" }),
|
|
61
|
+
offset: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({
|
|
62
|
+
description: "1-based line offset"
|
|
63
|
+
}),
|
|
64
|
+
limit: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))).annotate({
|
|
65
|
+
description: "Maximum number of lines to return"
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
const Output = Schema.Struct({
|
|
69
|
+
content: Schema.String.annotate({
|
|
70
|
+
description: "Raw page text, preserving CR bytes and omitting the final LF; never line-number prefixed"
|
|
71
|
+
}),
|
|
72
|
+
startLine: Schema.Number.annotate({ description: "First returned 1-based line number" }),
|
|
73
|
+
endLine: Schema.Number.annotate({
|
|
74
|
+
description: "Last returned 1-based line number, or startLine - 1 when no lines are returned"
|
|
75
|
+
}),
|
|
76
|
+
totalLines: Schema.Number.annotate({ description: "Total number of source lines" }),
|
|
77
|
+
truncated: Schema.Boolean.annotate({ description: "Whether displayed output was truncated" }),
|
|
78
|
+
notice: Schema.optional(Schema.String.annotate({ description: "Truncation disclosure" }))
|
|
79
|
+
});
|
|
80
|
+
const effects = (0, import_Declaration.envelope)({
|
|
81
|
+
tier: "sealed",
|
|
82
|
+
mode: "hermetic",
|
|
83
|
+
reads: ["/**"],
|
|
84
|
+
writes: []
|
|
85
|
+
});
|
|
86
|
+
const effectsFor = (input) => (0, import_Declaration.envelope)({
|
|
87
|
+
tier: "sealed",
|
|
88
|
+
mode: "hermetic",
|
|
89
|
+
reads: [input.path],
|
|
90
|
+
writes: []
|
|
91
|
+
});
|
|
92
|
+
const capabilities = [(0, import_Declaration.capability)("fs:read", "/**")];
|
|
93
|
+
const flow = { name, description, input: Input, output: Output, capabilities, effects };
|
|
94
|
+
const activity = "reads";
|
|
95
|
+
const presentation = {
|
|
96
|
+
verb: { pending: "reading", success: "read", failure: "failed to read" },
|
|
97
|
+
subject: "path",
|
|
98
|
+
result: "read"
|
|
99
|
+
};
|
|
100
|
+
const clipLine = (line) => {
|
|
101
|
+
let scalars = 0;
|
|
102
|
+
let end = 0;
|
|
103
|
+
for (const scalar of line) {
|
|
104
|
+
if (scalars === import_Text.MAX_LINE_CHARS) return line.slice(0, end);
|
|
105
|
+
scalars++;
|
|
106
|
+
end += scalar.length;
|
|
107
|
+
}
|
|
108
|
+
return line;
|
|
109
|
+
};
|
|
110
|
+
const MAX_READ_FILE_BYTES = 64 * 1024 * 1024;
|
|
111
|
+
const fileError = (path) => FsFailure.reading(path, `File not found: ${path}`);
|
|
112
|
+
const sharedPrefix = (left, right) => {
|
|
113
|
+
let index = 0;
|
|
114
|
+
while (index < left.length && index < right.length && left[index] === right[index]) index++;
|
|
115
|
+
return index;
|
|
116
|
+
};
|
|
117
|
+
const nearest = (fileSystem, path) => Effect.gen(function* () {
|
|
118
|
+
const segments = path.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
119
|
+
if (path.startsWith("/") || segments.includes("..")) return "";
|
|
120
|
+
for (let depth = segments.length - 1; depth >= 0; depth--) {
|
|
121
|
+
const directory = segments.slice(0, depth).join("/");
|
|
122
|
+
const entries = yield* fileSystem.readDirectory(directory === "" ? "." : directory).pipe(Effect.option);
|
|
123
|
+
if (Option.isNone(entries)) continue;
|
|
124
|
+
const missing = segments[depth].toLowerCase();
|
|
125
|
+
const ranked = entries.value.filter((entry) => !entry.startsWith(".")).map((entry) => ({ entry, score: sharedPrefix(entry.toLowerCase(), missing) })).sort((left, right) => right.score - left.score).map(({ entry }) => entry);
|
|
126
|
+
if (ranked.length === 0) return "";
|
|
127
|
+
const shown = ranked.slice(0, 12).join(", ");
|
|
128
|
+
const more = ranked.length > 12 ? ` and ${ranked.length - 12} more` : "";
|
|
129
|
+
return `. ${directory === "" ? "The working directory" : directory} holds: ${shown}${more}.`;
|
|
130
|
+
}
|
|
131
|
+
return "";
|
|
132
|
+
});
|
|
133
|
+
const missingFile = (fileSystem, path) => Effect.flatMap(nearest(fileSystem, path), (hint) => Effect.fail(
|
|
134
|
+
new StdError.StdError({
|
|
135
|
+
code: "not_found",
|
|
136
|
+
message: `File not found: ${path}${hint}`,
|
|
137
|
+
path
|
|
138
|
+
})
|
|
139
|
+
));
|
|
140
|
+
const run = Effect.fn("Read.run")(function* (input) {
|
|
141
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
142
|
+
const info = yield* fileSystem.stat(input.path).pipe(
|
|
143
|
+
Effect.catchTag(
|
|
144
|
+
"PlatformError",
|
|
145
|
+
(error) => error.reason._tag === "NotFound" ? missingFile(fileSystem, input.path) : Effect.fail(fileError(input.path)(error))
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
if (info.type === "Directory") {
|
|
149
|
+
return yield* Effect.fail(
|
|
150
|
+
new StdError.StdError({
|
|
151
|
+
code: "is_directory",
|
|
152
|
+
message: `Cannot read a directory: ${input.path}`,
|
|
153
|
+
path: input.path
|
|
154
|
+
})
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
if (info.type !== "File") {
|
|
158
|
+
return yield* Effect.fail(
|
|
159
|
+
new StdError.StdError({
|
|
160
|
+
code: "not_found",
|
|
161
|
+
message: `File not found: ${input.path}`,
|
|
162
|
+
path: input.path
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
const size = Number(info.size);
|
|
167
|
+
if (size > MAX_READ_FILE_BYTES) {
|
|
168
|
+
return yield* Effect.fail(
|
|
169
|
+
new StdError.StdError({
|
|
170
|
+
code: "response_too_large",
|
|
171
|
+
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`,
|
|
172
|
+
path: input.path
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
const bytes = yield* fileSystem.readFile(input.path).pipe(Effect.mapError(fileError(input.path)));
|
|
177
|
+
if (bytes.includes(0)) {
|
|
178
|
+
return yield* Effect.fail(
|
|
179
|
+
new StdError.StdError({
|
|
180
|
+
code: "binary_file",
|
|
181
|
+
message: `Cannot read binary file: ${input.path}`,
|
|
182
|
+
path: input.path
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
const text = yield* Effect.try({
|
|
187
|
+
try: () => new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
188
|
+
catch: () => new StdError.StdError({
|
|
189
|
+
code: "binary_file",
|
|
190
|
+
message: `File is not valid UTF-8: ${input.path}`,
|
|
191
|
+
path: input.path
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
const offset = input.offset ?? 1;
|
|
195
|
+
const page = (0, import_Text.slice)(text, { offset, limit: input.limit ?? import_Text.DEFAULT_READ_LIMIT });
|
|
196
|
+
if (offset > Math.max(page.totalLines, 1)) {
|
|
197
|
+
return yield* Effect.fail(
|
|
198
|
+
new StdError.StdError({
|
|
199
|
+
code: "offset_out_of_range",
|
|
200
|
+
message: `Line offset ${offset} is outside ${input.path}`,
|
|
201
|
+
path: input.path
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const lines = page.lines.map(clipLine);
|
|
206
|
+
const longLinesTruncated = lines.some((line, index) => line !== page.lines[index]);
|
|
207
|
+
const rendered = (0, import_Text.truncateBytes)(lines.join("\n"), import_Text.MAX_OUTPUT_BYTES, { keep: "head" });
|
|
208
|
+
const whole = rendered.truncated ? rendered.text.slice(0, Math.max(0, rendered.text.lastIndexOf("\n"))) : rendered.text;
|
|
209
|
+
const shown = rendered.truncated ? whole.split("\n").length : lines.length;
|
|
210
|
+
const endLine = page.startLine + shown - 1;
|
|
211
|
+
const truncated = longLinesTruncated || rendered.truncated || page.endLine < page.totalLines;
|
|
212
|
+
const clipped = longLinesTruncated ? ` Lines longer than ${import_Text.MAX_LINE_CHARS} Unicode scalar values are clipped, so such a line is not an edit anchor.` : "";
|
|
213
|
+
yield* FileMutation.recordRead(fileSystem, input.path, bytes);
|
|
214
|
+
return {
|
|
215
|
+
content: whole,
|
|
216
|
+
startLine: page.startLine,
|
|
217
|
+
endLine,
|
|
218
|
+
totalLines: page.totalLines,
|
|
219
|
+
truncated,
|
|
220
|
+
...truncated ? { notice: `${(0, import_Text.notice)("lines", shown, page.totalLines)}${clipped}` } : {}
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
//# sourceMappingURL=Read.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/Read.ts"],
|
|
4
|
+
"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 \u2014 `startLine` and `endLine` \u2014 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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -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,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var Relocate_exports = {};
|
|
20
|
+
__export(Relocate_exports, {
|
|
21
|
+
relocate: () => relocate
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(Relocate_exports);
|
|
24
|
+
var import_Paths = require("./internal/Paths.js");
|
|
25
|
+
const located = {
|
|
26
|
+
bash: { field: "cwd", kind: "cwd" },
|
|
27
|
+
read: { field: "path", kind: "path" },
|
|
28
|
+
ls: { field: "path", kind: "path" },
|
|
29
|
+
grep: { field: "root", kind: "path" },
|
|
30
|
+
glob: { field: "root", kind: "path" }
|
|
31
|
+
};
|
|
32
|
+
const contained = (path) => {
|
|
33
|
+
const parts = [];
|
|
34
|
+
for (const segment of path.split("/")) {
|
|
35
|
+
if (segment === "" || segment === ".") continue;
|
|
36
|
+
if (segment !== "..") {
|
|
37
|
+
parts.push(segment);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (parts.length === 0) return void 0;
|
|
41
|
+
parts.pop();
|
|
42
|
+
}
|
|
43
|
+
return parts.join("/");
|
|
44
|
+
};
|
|
45
|
+
const within = (root, declared) => {
|
|
46
|
+
if (!declared.startsWith("/")) return contained(declared);
|
|
47
|
+
if ((0, import_Paths.withoutTrailingSlash)(declared) === root) return "";
|
|
48
|
+
return declared.startsWith(`${root}/`) ? contained(declared.slice(root.length + 1)) : void 0;
|
|
49
|
+
};
|
|
50
|
+
const relocate = (flow, input, materialized) => {
|
|
51
|
+
const rule = located[flow];
|
|
52
|
+
if (rule === void 0) return { _tag: "UnsupportedFlow" };
|
|
53
|
+
const record = input !== null && typeof input === "object" && !Array.isArray(input) ? input : {};
|
|
54
|
+
const declared = record[rule.field];
|
|
55
|
+
if (rule.kind === "cwd") {
|
|
56
|
+
const containerised = typeof record["container"] === "string" && record["container"] !== "";
|
|
57
|
+
const base = containerised ? materialized.guest : materialized.host;
|
|
58
|
+
const kept2 = typeof declared === "string" && declared !== "" ? within(containerised ? materialized.guestRoot : materialized.root, declared) : "";
|
|
59
|
+
return {
|
|
60
|
+
_tag: "Relocated",
|
|
61
|
+
input: { ...record, cwd: kept2 === void 0 || kept2 === "" ? base : `${base}/${kept2}` }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const relative = materialized.host.slice((0, import_Paths.withoutTrailingSlash)(materialized.root).length + 1);
|
|
65
|
+
if (declared === void 0) return { _tag: "Relocated", input: { ...record, [rule.field]: relative } };
|
|
66
|
+
if (typeof declared !== "string") return { _tag: "UnsupportedFlow" };
|
|
67
|
+
if (declared.startsWith("/")) return { _tag: "AbsolutePath", path: declared };
|
|
68
|
+
const kept = contained(declared);
|
|
69
|
+
if (kept === void 0) return { _tag: "OutsideTree", path: declared };
|
|
70
|
+
return { _tag: "Relocated", input: { ...record, [rule.field]: kept === "" ? relative : `${relative}/${kept}` } };
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=Relocate.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/Relocate.ts"],
|
|
4
|
+
"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` \u2014 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 \u2014 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 \u2014 an edit, a patch,\n * a web fetch, a memory write \u2014 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 \u2014 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 \u2014 a container call names the\n * mount, a host call names this machine \u2014 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 \u2014 from the *guest* side when it names a\n * container, because that is the path the container will be given \u2014 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 \u2014\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"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BA,mBAAqC;AAiBrC,MAAM,UAA+F;AAAA,EACnG,MAAM,EAAE,OAAO,OAAO,MAAM,MAAM;AAAA,EAClC,MAAM,EAAE,OAAO,QAAQ,MAAM,OAAO;AAAA,EACpC,IAAI,EAAE,OAAO,QAAQ,MAAM,OAAO;AAAA,EAClC,MAAM,EAAE,OAAO,QAAQ,MAAM,OAAO;AAAA,EACpC,MAAM,EAAE,OAAO,QAAQ,MAAM,OAAO;AACtC;AA2BA,MAAM,YAAY,CAAC,SAAqC;AACtD,QAAM,QAAuB,CAAC;AAC9B,aAAW,WAAW,KAAK,MAAM,GAAG,GAAG;AACrC,QAAI,YAAY,MAAM,YAAY,IAAK;AACvC,QAAI,YAAY,MAAM;AACpB,YAAM,KAAK,OAAO;AAClB;AAAA,IACF;AACA,QAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,UAAM,IAAI;AAAA,EACZ;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAWA,MAAM,SAAS,CAAC,MAAc,aAAyC;AACrE,MAAI,CAAC,SAAS,WAAW,GAAG,EAAG,QAAO,UAAU,QAAQ;AACxD,UAAI,mCAAqB,QAAQ,MAAM,KAAM,QAAO;AACpD,SAAO,SAAS,WAAW,GAAG,IAAI,GAAG,IAAI,UAAU,SAAS,MAAM,KAAK,SAAS,CAAC,CAAC,IAAI;AACxF;AA2BO,MAAM,WAAW,CACtB,MACA,OACA,iBACe;AACf,QAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,SAAS,OAAW,QAAO,EAAE,MAAM,kBAAkB;AACzD,QAAM,SAAS,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC9E,QACA,CAAC;AACL,QAAM,WAAW,OAAO,KAAK,KAAK;AAClC,MAAI,KAAK,SAAS,OAAO;AAIvB,UAAM,gBAAgB,OAAO,OAAO,WAAW,MAAM,YAAY,OAAO,WAAW,MAAM;AACzF,UAAM,OAAO,gBAAgB,aAAa,QAAQ,aAAa;AAC/D,UAAMA,QAAO,OAAO,aAAa,YAAY,aAAa,KACtD,OAAO,gBAAgB,aAAa,YAAY,aAAa,MAAM,QAAQ,IAC3E;AACJ,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,GAAG,QAAQ,KAAKA,UAAS,UAAaA,UAAS,KAAK,OAAO,GAAG,IAAI,IAAIA,KAAI,GAAG;AAAA,IACxF;AAAA,EACF;AACA,QAAM,WAAW,aAAa,KAAK,UAAM,mCAAqB,aAAa,IAAI,EAAE,SAAS,CAAC;AAC3F,MAAI,aAAa,OAAW,QAAO,EAAE,MAAM,aAAa,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,KAAK,GAAG,SAAS,EAAE;AACrG,MAAI,OAAO,aAAa,SAAU,QAAO,EAAE,MAAM,kBAAkB;AACnE,MAAI,SAAS,WAAW,GAAG,EAAG,QAAO,EAAE,MAAM,gBAAgB,MAAM,SAAS;AAC5E,QAAM,OAAO,UAAU,QAAQ;AAC/B,MAAI,SAAS,OAAW,QAAO,EAAE,MAAM,eAAe,MAAM,SAAS;AACrE,SAAO,EAAE,MAAM,aAAa,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,KAAK,GAAG,SAAS,KAAK,WAAW,GAAG,QAAQ,IAAI,IAAI,GAAG,EAAE;AACjH;",
|
|
6
|
+
"names": ["kept"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The search contract for a tree on another machine, in two round trips.
|
|
3
|
+
*
|
|
4
|
+
* `PortableSearch` asks `FileSystem` one question per directory, per entry
|
|
5
|
+
* and per file. On a machine reached through a transport, such as a
|
|
6
|
+
* benchmark's task container behind `docker exec`, every question is a
|
|
7
|
+
* process start, so one `grep` over a 6,000-file repository is some 20,000 of
|
|
8
|
+
* them. This peer asks the machine's own shell twice instead. `find` lists
|
|
9
|
+
* the tree under the root, leaving out the directories every walk skips, and
|
|
10
|
+
* `tar` returns its `.gitignore` files with the listing. The in-process peer
|
|
11
|
+
* then decides which files the search reads, a second `tar` returns exactly
|
|
12
|
+
* those, and `PortableSearch` answers over that copy. Every result, notice,
|
|
13
|
+
* and refusal is therefore the in-process peer's own: this module decides
|
|
14
|
+
* only where the bytes come from.
|
|
15
|
+
*
|
|
16
|
+
* It runs through the machine's own `ChildProcessSpawner`, the one
|
|
17
|
+
* `Sandbox.hostContext` serves beside the machine's `FileSystem`. The machine
|
|
18
|
+
* needs `sh`, `find`, `xargs`, `tar`, `head`, and `base64`; GNU, BusyBox, and
|
|
19
|
+
* BSD userlands all have them. Output crosses as base64, so a transport whose
|
|
20
|
+
* channel carries only text returns it intact. A search reads at most
|
|
21
|
+
* {@link maxBytes} of file content and refuses beyond that, naming the root
|
|
22
|
+
* to narrow.
|
|
23
|
+
*
|
|
24
|
+
* @since 1.0.0-rc.8
|
|
25
|
+
*/
|
|
26
|
+
import type * as ChildProcessSpawner from "@smthrs/kernel/ChildProcessSpawner";
|
|
27
|
+
import * as Path from "@smthrs/kernel/Path";
|
|
28
|
+
import { Context } from "effect";
|
|
29
|
+
import * as Search from "./Search.ts";
|
|
30
|
+
/**
|
|
31
|
+
* The most file content one search brings back from the machine.
|
|
32
|
+
*
|
|
33
|
+
* The copy is held in memory while the in-process peer reads it, so the
|
|
34
|
+
* bound is on this process's memory rather than on the search: a root that
|
|
35
|
+
* holds more is refused with `response_too_large` and a narrower root or
|
|
36
|
+
* globs answer it.
|
|
37
|
+
*
|
|
38
|
+
* @category constants
|
|
39
|
+
* @since 1.0.0-rc.8
|
|
40
|
+
*/
|
|
41
|
+
export declare const maxBytes: number;
|
|
42
|
+
/**
|
|
43
|
+
* Builds the peer over a machine's spawner and its `Path`, which resolves a
|
|
44
|
+
* relative root where the machine's file operations do. `maxBytes` lowers
|
|
45
|
+
* the bound on the file content one search brings back; the default is
|
|
46
|
+
* {@link maxBytes}.
|
|
47
|
+
*
|
|
48
|
+
* @category constructors
|
|
49
|
+
* @since 1.0.0-rc.8
|
|
50
|
+
*/
|
|
51
|
+
export declare const make: (services: Context.Context<ChildProcessSpawner.ChildProcessSpawner | Path.Path>, options?: {
|
|
52
|
+
readonly maxBytes?: number | undefined;
|
|
53
|
+
}) => Search.Search;
|
|
54
|
+
//# sourceMappingURL=RemoteSearch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RemoteSearch.d.ts","sourceRoot":"","sources":["../../src/RemoteSearch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,KAAK,mBAAmB,MAAM,oCAAoC,CAAA;AAC9E,OAAO,KAAK,IAAI,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAU,MAAM,QAAQ,CAAA;AASxC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAGrC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,QAAoB,CAAA;AA+FzC;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GACf,UAAU,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,EAC9E,UAAU;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,KACnD,MAAM,CAAC,MAwCT,CAAA"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var RemoteSearch_exports = {};
|
|
30
|
+
__export(RemoteSearch_exports, {
|
|
31
|
+
make: () => make,
|
|
32
|
+
maxBytes: () => maxBytes
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(RemoteSearch_exports);
|
|
35
|
+
var Path = __toESM(require("@smthrs/kernel/Path"), 1);
|
|
36
|
+
var import_effect = require("effect");
|
|
37
|
+
var Base64 = __toESM(require("effect/encoding/Base64"), 1);
|
|
38
|
+
var FileSystem = __toESM(require("effect/FileSystem"), 1);
|
|
39
|
+
var Result = __toESM(require("effect/Result"), 1);
|
|
40
|
+
var Exec = __toESM(require("./internal/Exec.js"), 1);
|
|
41
|
+
var Prune = __toESM(require("./internal/Prune.js"), 1);
|
|
42
|
+
var RemoteTree = __toESM(require("./internal/RemoteTree.js"), 1);
|
|
43
|
+
var Tar = __toESM(require("./internal/Tar.js"), 1);
|
|
44
|
+
var PortableSearch = __toESM(require("./PortableSearch.js"), 1);
|
|
45
|
+
var Search = __toESM(require("./Search.js"), 1);
|
|
46
|
+
var StdError = __toESM(require("./StdError.js"), 1);
|
|
47
|
+
const maxBytes = 256 * 1024 * 1024;
|
|
48
|
+
const maxListingBytes = 64 * 1024 * 1024;
|
|
49
|
+
const quoted = (value) => `'${value.replaceAll("'", `'\\''`)}'`;
|
|
50
|
+
const pruned = `\\( ${Prune.repositoryDirectories.map((name) => `-name ${quoted(name)}`).join(" -o ")} \\) -prune`;
|
|
51
|
+
const missing = (tool) => `searching this machine needs ${tool}, which it does not have`;
|
|
52
|
+
const requireTools = `for t in find xargs tar head; do command -v "$t" >/dev/null || { echo "${missing("$t")}" >&2; exit 3; }; done`;
|
|
53
|
+
const listing = [
|
|
54
|
+
"set -f",
|
|
55
|
+
requireTools,
|
|
56
|
+
"r=$1",
|
|
57
|
+
"{",
|
|
58
|
+
` if [ -d "$r" ]; then if [ -r "$r" ] && [ -x "$r" ]; then printf 'd%s\\0' "$r"; else printf 'u%s\\0' "$r"; fi`,
|
|
59
|
+
` elif [ -f "$r" ]; then printf 'f%s\\0' "$r"`,
|
|
60
|
+
` elif [ -e "$r" ]; then printf 'o%s\\0' "$r"`,
|
|
61
|
+
" fi",
|
|
62
|
+
// No `-exec … {} +` inside parentheses: BusyBox `find` never runs one there.
|
|
63
|
+
` find -H "$r" -mindepth 1 ${pruned} -o -type d -exec printf 'd%s\\0' {} + -o -type f -exec printf 'f%s\\0' {} + -o -type l -exec sh -c 'for p do if [ -d "$p" ]; then k=D; elif [ -f "$p" ]; then k=F; else k=L; fi; printf "%s%s\\0" "$k" "$p"; done' sh {} + -o -exec printf 'o%s\\0' {} + 2>/dev/null`,
|
|
64
|
+
" printf 'E\\0'",
|
|
65
|
+
` if [ "$3" = 1 ]; then find -H "$r" -mindepth 1 ${pruned} -o -type f -name .gitignore -print0 2>/dev/null | (cd / && COPYFILE_DISABLE=1 xargs -0 -r tar -cf - -- 2>/dev/null); fi`,
|
|
66
|
+
'} | head -c "$2" | base64'
|
|
67
|
+
].join("\n");
|
|
68
|
+
const fetching = [
|
|
69
|
+
requireTools,
|
|
70
|
+
'cd / && COPYFILE_DISABLE=1 xargs -0 -r tar -chf - -- 2>/dev/null | head -c "$1" | base64'
|
|
71
|
+
].join("\n");
|
|
72
|
+
const failed = (root, reason) => new StdError.StdError({
|
|
73
|
+
code: "command_failed",
|
|
74
|
+
message: `Could not search ${root} on this machine: ${reason}`,
|
|
75
|
+
path: root
|
|
76
|
+
});
|
|
77
|
+
const tooLarge = (root, bound) => new StdError.StdError({
|
|
78
|
+
code: "response_too_large",
|
|
79
|
+
message: `The files under ${root} come to more than ${bound} bytes; narrow the root or the globs`,
|
|
80
|
+
path: root
|
|
81
|
+
});
|
|
82
|
+
const bootstrap = `command -v base64 >/dev/null || { echo "${missing("base64")}" >&2; exit 3; }; IFS= read -r p && p=$(printf %s "$p" | base64 -d) && exec sh -c "$p" sh "$@"`;
|
|
83
|
+
const run = (root, script, args, bound, stdin = "") => import_effect.Effect.gen(function* () {
|
|
84
|
+
const result = yield* Exec.exec("sh", {
|
|
85
|
+
args: ["-c", bootstrap, "sh", ...args],
|
|
86
|
+
stdin: `${Base64.encode(new TextEncoder().encode(script))}
|
|
87
|
+
${stdin}`
|
|
88
|
+
}).pipe(import_effect.Effect.mapError((error) => failed(root, error.message)));
|
|
89
|
+
if (result.exitCode !== 0) {
|
|
90
|
+
return yield* import_effect.Effect.fail(failed(root, result.stderr.trim() || `exit ${result.exitCode}`));
|
|
91
|
+
}
|
|
92
|
+
const decoded = Base64.decode(result.stdout.replaceAll(/\s/g, ""));
|
|
93
|
+
if (Result.isFailure(decoded)) return yield* import_effect.Effect.fail(failed(root, "the machine answered with invalid base64"));
|
|
94
|
+
if (decoded.success.length >= bound) return yield* import_effect.Effect.fail(tooLarge(root, bound - 1));
|
|
95
|
+
return decoded.success;
|
|
96
|
+
});
|
|
97
|
+
const make = (services, options) => {
|
|
98
|
+
const path = import_effect.Context.get(services, Path.Path);
|
|
99
|
+
const contentBound = (options?.maxBytes ?? maxBytes) + 1;
|
|
100
|
+
const copy = (tree) => import_effect.Context.make(FileSystem.FileSystem, RemoteTree.fileSystem(tree, path)).pipe(import_effect.Context.add(Path.Path, path));
|
|
101
|
+
const listed = (root, noIgnore) => {
|
|
102
|
+
const resolved = path.resolve(root);
|
|
103
|
+
const bound = maxListingBytes + 1;
|
|
104
|
+
return import_effect.Effect.flatMap(
|
|
105
|
+
run(root, listing, [resolved, String(bound), noIgnore === true ? "0" : "1"], bound),
|
|
106
|
+
(bytes) => {
|
|
107
|
+
const tree = RemoteTree.parse(bytes, resolved, path);
|
|
108
|
+
return tree === void 0 ? import_effect.Effect.fail(failed(root, "the listing came back malformed")) : import_effect.Effect.succeed(tree);
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
return Search.make({
|
|
113
|
+
grep: (input) => import_effect.Effect.gen(function* () {
|
|
114
|
+
const tree = yield* listed(input.root, input.noIgnore);
|
|
115
|
+
const read = yield* PortableSearch.searched(input).pipe(import_effect.Effect.provide(copy(tree)));
|
|
116
|
+
const files = [...new Set(read.map((file) => path.resolve(file)))];
|
|
117
|
+
const bytes = files.length === 0 ? new Uint8Array() : yield* run(
|
|
118
|
+
input.root,
|
|
119
|
+
fetching,
|
|
120
|
+
[String(contentBound)],
|
|
121
|
+
contentBound,
|
|
122
|
+
files.map((file) => `${file}\0`).join("")
|
|
123
|
+
);
|
|
124
|
+
const members = files.length === 0 || bytes.length > 0 ? Tar.files(bytes) : void 0;
|
|
125
|
+
if (members === void 0) return yield* import_effect.Effect.fail(failed(input.root, "the files came back malformed"));
|
|
126
|
+
const contents = new Map([...tree.contents, ...RemoteTree.absolute(members)]);
|
|
127
|
+
return yield* PortableSearch.make(copy({ ...tree, contents })).grep(input);
|
|
128
|
+
}).pipe(import_effect.Effect.provide(services)),
|
|
129
|
+
glob: (input) => import_effect.Effect.flatMap(listed(input.root, input.noIgnore), (tree) => PortableSearch.make(copy(tree)).glob(input)).pipe(
|
|
130
|
+
import_effect.Effect.provide(services)
|
|
131
|
+
)
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=RemoteSearch.js.map
|