@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsFailure.d.ts","sourceRoot":"","sources":["../../../src/internal/FsFailure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,QAAQ,CAAC,QAC0C,CAAA;AAEnG;;;;;;GAMG;AACH,eAAO,MAAM,MAAM,GACjB,MAAM,MAAM,EACZ,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,KAAK,QAAQ,CAAC,QAAQ,MAErE,OAAO,aAAa,CAAC,aAAa,KAAG,QAAQ,CAAC,QACuC,CAAA;AAEtF;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,EAAE,iBAAiB,MAAM,aAXrD,aAAa,CAAC,aAAa,KAAG,QAAQ,CAAC,QAesE,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a filesystem failure to the standard-flow code that names its reason.
|
|
3
|
+
*
|
|
4
|
+
* A permission denial is not a missing file. Telling the model a denied path
|
|
5
|
+
* does not exist sends it searching for a file that is right there, and hides
|
|
6
|
+
* the denial from whoever reads the run. Every standard flow that touches the
|
|
7
|
+
* filesystem routes its failures through here so `PermissionDenied` always
|
|
8
|
+
* reaches the model as `permission_denied`.
|
|
9
|
+
*
|
|
10
|
+
* @since 1.0.0
|
|
11
|
+
*/
|
|
12
|
+
import * as StdError from "../StdError.js";
|
|
13
|
+
/**
|
|
14
|
+
* The failure for a path the host or the kernel guard refused.
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
* @since 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
export const permissionDenied = (path) => new StdError.StdError({ code: "permission_denied", message: `Permission denied: ${path}`, path });
|
|
20
|
+
/**
|
|
21
|
+
* Maps `PermissionDenied` to `permission_denied` and any other reason through
|
|
22
|
+
* `otherwise`.
|
|
23
|
+
*
|
|
24
|
+
* @private
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
*/
|
|
27
|
+
export const denied = (path, otherwise) => (error) => error.reason._tag === "PermissionDenied" ? permissionDenied(path) : otherwise(error);
|
|
28
|
+
/**
|
|
29
|
+
* Maps a read-side failure: `NotFound` to `not_found` with `notFoundMessage`,
|
|
30
|
+
* `PermissionDenied` to `permission_denied`, and anything else to
|
|
31
|
+
* `command_failed` carrying the host's reason.
|
|
32
|
+
*
|
|
33
|
+
* @private
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
*/
|
|
36
|
+
export const reading = (path, notFoundMessage) => denied(path, (error) => error.reason._tag === "NotFound"
|
|
37
|
+
? new StdError.StdError({ code: "not_found", message: notFoundMessage, path })
|
|
38
|
+
: new StdError.StdError({ code: "command_failed", message: `Could not read ${path}: ${error.message}`, path }));
|
|
39
|
+
//# sourceMappingURL=FsFailure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FsFailure.js","sourceRoot":"","sources":["../../../src/internal/FsFailure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAqB,EAAE,CAClE,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,sBAAsB,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;AAEnG;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CACpB,IAAY,EACZ,SAAoE,EACpE,EAAE,CACJ,CAAC,KAAkC,EAAqB,EAAE,CACxD,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;AAEtF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,eAAuB,EAAE,EAAE,CAC/D,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CACrB,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU;IAC9B,CAAC,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA","sourcesContent":["/**\n * Maps a filesystem failure to the standard-flow code that names its reason.\n *\n * A permission denial is not a missing file. Telling the model a denied path\n * does not exist sends it searching for a file that is right there, and hides\n * the denial from whoever reads the run. Every standard flow that touches the\n * filesystem routes its failures through here so `PermissionDenied` always\n * reaches the model as `permission_denied`.\n *\n * @since 1.0.0\n */\n\nimport type * as PlatformError from \"effect/PlatformError\"\nimport * as StdError from \"../StdError.ts\"\n\n/**\n * The failure for a path the host or the kernel guard refused.\n *\n * @private\n * @since 1.0.0\n */\nexport const permissionDenied = (path: string): StdError.StdError =>\n new StdError.StdError({ code: \"permission_denied\", message: `Permission denied: ${path}`, path })\n\n/**\n * Maps `PermissionDenied` to `permission_denied` and any other reason through\n * `otherwise`.\n *\n * @private\n * @since 1.0.0\n */\nexport const denied = (\n path: string,\n otherwise: (error: PlatformError.PlatformError) => StdError.StdError\n) =>\n(error: PlatformError.PlatformError): StdError.StdError =>\n error.reason._tag === \"PermissionDenied\" ? permissionDenied(path) : otherwise(error)\n\n/**\n * Maps a read-side failure: `NotFound` to `not_found` with `notFoundMessage`,\n * `PermissionDenied` to `permission_denied`, and anything else to\n * `command_failed` carrying the host's reason.\n *\n * @private\n * @since 1.0.0\n */\nexport const reading = (path: string, notFoundMessage: string) =>\n denied(path, (error) =>\n error.reason._tag === \"NotFound\"\n ? new StdError.StdError({ code: \"not_found\", message: notFoundMessage, path })\n : new StdError.StdError({ code: \"command_failed\", message: `Could not read ${path}: ${error.message}`, path }))\n"]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detached checkouts shared by checkpoint reads and baseline test runs.
|
|
3
|
+
*
|
|
4
|
+
* ## Host git never reads a file the agent can write that names a program
|
|
5
|
+
*
|
|
6
|
+
* The repository is the workspace's, and an agent can write its `.git`: a
|
|
7
|
+
* containerised agent writes it through the bind mount. Git reads programs out
|
|
8
|
+
* of that directory in more places than any list of `-c` overrides can close.
|
|
9
|
+
* Hooks and `core.fsmonitor` can be overridden, but a filter driver
|
|
10
|
+
* (`filter.<name>.clean`/`.smudge` in `.git/config`, selected by
|
|
11
|
+
* `.git/info/attributes`) cannot: git has no switch that ignores repository
|
|
12
|
+
* config or `$GIT_DIR/info/attributes`, and overriding each driver by name
|
|
13
|
+
* races an agent that keeps rewriting the file.
|
|
14
|
+
*
|
|
15
|
+
* So the git that records and checks out trees runs against a **shadow**
|
|
16
|
+
* `GIT_DIR`: a bare repository this module creates under the host's temporary
|
|
17
|
+
* directory for one operation and deletes afterwards. Its config, hooks and
|
|
18
|
+
* `info/attributes` are the ones `git init --template=` writes, which is none.
|
|
19
|
+
* `GIT_CONFIG_NOSYSTEM` and `GIT_CONFIG_GLOBAL=/dev/null` drop the host's own
|
|
20
|
+
* config files too, so the only settings are the ones on the command line.
|
|
21
|
+
* `GIT_OBJECT_DIRECTORY` points at the workspace's object store, because objects
|
|
22
|
+
* are data: git hashes and inflates them and never runs anything they say.
|
|
23
|
+
*
|
|
24
|
+
* What still touches the workspace repository is plain data:
|
|
25
|
+
*
|
|
26
|
+
* - `rev-parse` in the workspace, which resolves refs and paths and runs no
|
|
27
|
+
* hook, filter, fsmonitor or other configured program;
|
|
28
|
+
* - `git config --file <workspace config>`, which reads or writes that one file
|
|
29
|
+
* and follows no `include`;
|
|
30
|
+
* - a copy of the workspace index into the shadow, so the recorded tree holds
|
|
31
|
+
* what the agent staged without the harness writing the agent's index; and
|
|
32
|
+
* - a handful of `core.*` settings that change how bytes are hashed
|
|
33
|
+
* ({@link dataSettings}), each accepted only as a bare word.
|
|
34
|
+
*
|
|
35
|
+
* A materialized checkout gets its own standalone `.git`, written by this
|
|
36
|
+
* module as files, so a container can still run git in it: `HEAD` names the
|
|
37
|
+
* commit, `objects/info/alternates` points back at the workspace's objects by a
|
|
38
|
+
* relative path, and `index` is the one the checkout was written from. Host git
|
|
39
|
+
* never uses that directory; it is the container's.
|
|
40
|
+
*
|
|
41
|
+
* @since 1.0.0
|
|
42
|
+
*/
|
|
43
|
+
import type { ChildProcessSpawner } from "@smthrs/kernel/ChildProcessSpawner";
|
|
44
|
+
import { Effect } from "effect";
|
|
45
|
+
import * as StdError from "../StdError.ts";
|
|
46
|
+
import * as Exec from "./Exec.ts";
|
|
47
|
+
/**
|
|
48
|
+
* Where one workspace repository keeps what the shadow needs, as its own git
|
|
49
|
+
* reports it.
|
|
50
|
+
*
|
|
51
|
+
* @category models
|
|
52
|
+
* @since 1.0.0
|
|
53
|
+
*/
|
|
54
|
+
export interface Repository {
|
|
55
|
+
/** The root the caller named, without a trailing slash. */
|
|
56
|
+
readonly root: string;
|
|
57
|
+
/** The same directory, as git canonicalizes it. */
|
|
58
|
+
readonly toplevel: string;
|
|
59
|
+
/** The common git directory, which holds config and objects. */
|
|
60
|
+
readonly common: string;
|
|
61
|
+
/** The workspace index. */
|
|
62
|
+
readonly index: string;
|
|
63
|
+
readonly objectFormat: string;
|
|
64
|
+
/** {@link dataSettings} as `-c` arguments. */
|
|
65
|
+
readonly settings: ReadonlyArray<string>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A harness-owned `GIT_DIR` over one workspace's objects.
|
|
69
|
+
*
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 1.0.0
|
|
72
|
+
*/
|
|
73
|
+
export interface Shadow {
|
|
74
|
+
readonly path: string;
|
|
75
|
+
readonly repository: Repository;
|
|
76
|
+
/** Runs host git with the shadow as `GIT_DIR`, and `workTree` as its work tree when given. */
|
|
77
|
+
readonly git: (args: ReadonlyArray<string>, workTree?: string) => Effect.Effect<Exec.ExecResult, StdError.StdError, ChildProcessSpawner>;
|
|
78
|
+
/**
|
|
79
|
+
* Copies the workspace index into the shadow, with its modification time, so
|
|
80
|
+
* the shadow never writes the agent's own.
|
|
81
|
+
*
|
|
82
|
+
* The time is part of what git reads. It trusts an entry's recorded stat
|
|
83
|
+
* unless the entry is at least as new as the index file, in whole seconds;
|
|
84
|
+
* a copy stamped at the moment of copying made every entry look older, and a
|
|
85
|
+
* same-size edit from the second the index was written was recorded as the
|
|
86
|
+
* committed bytes (#3431). The time is taken before the bytes are read, so
|
|
87
|
+
* an index rewritten meanwhile leaves the copy looking older, never newer.
|
|
88
|
+
*/
|
|
89
|
+
readonly adoptIndex: Effect.Effect<void, StdError.StdError, ChildProcessSpawner>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Internal Git operations used by both checkpoint and baseline leases.
|
|
93
|
+
*
|
|
94
|
+
* @category utilities
|
|
95
|
+
* @since 1.0.0
|
|
96
|
+
*/
|
|
97
|
+
export declare const GitWorktree: {
|
|
98
|
+
config: (repository: Pick<Repository, "common">, args: ReadonlyArray<string>) => Effect.Effect<Exec.ExecResult, StdError.StdError, ChildProcessSpawner>;
|
|
99
|
+
git: (root: string, args: ReadonlyArray<string>) => Effect.Effect<Exec.ExecResult, StdError.StdError, ChildProcessSpawner>;
|
|
100
|
+
open: (root: string) => Effect.Effect<Repository, StdError.StdError, ChildProcessSpawner>;
|
|
101
|
+
resolveCommit: (root: string, refs: ReadonlyArray<string>) => Effect.Effect<{
|
|
102
|
+
ref: string;
|
|
103
|
+
commit: string;
|
|
104
|
+
}, StdError.StdError, ChildProcessSpawner>;
|
|
105
|
+
withDetachedWorktree: <A, E, R>(repository: Repository, prefix: string, commit: string, use: (host: string) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner>;
|
|
106
|
+
withShadow: <A, E, R>(root: string | Repository, use: (shadow: Shadow) => Effect.Effect<A, E, R>) => Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner>;
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=GitWorktree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitWorktree.d.ts","sourceRoot":"","sources":["../../../src/internal/GitWorktree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AA+CjC;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACzC;AAuDD;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAA;IAC/B,8FAA8F;IAC9F,QAAQ,CAAC,GAAG,EAAE,CACZ,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;IAC3E;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;CACjF;AAmSD;;;;;GAKG;AACH,eAAO,MAAM,WAAW;yBA/WI,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,aAAa,CAAC,MAAM,CAAC;gBA1ChE,MAAM,QAAQ,aAAa,CAAC,MAAM,CAAC;iBA6ClC,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;0BA3CjE,MAAM,QAAQ,aAAa,CAAC,MAAM,CAAC;;;;2BAmXlC,CAAC,EAAE,CAAC,EAAE,CAAC,cACvB,UAAU,UACd,MAAM,UACN,MAAM,OACT,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,mBAAmB,CAAC;iBA3N/C,CAAC,EAAE,CAAC,EAAE,CAAC,QACnB,MAAM,GAAG,UAAU,OACpB,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,mBAAmB,CAAC;CAuP8B,CAAA"}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detached checkouts shared by checkpoint reads and baseline test runs.
|
|
3
|
+
*
|
|
4
|
+
* ## Host git never reads a file the agent can write that names a program
|
|
5
|
+
*
|
|
6
|
+
* The repository is the workspace's, and an agent can write its `.git`: a
|
|
7
|
+
* containerised agent writes it through the bind mount. Git reads programs out
|
|
8
|
+
* of that directory in more places than any list of `-c` overrides can close.
|
|
9
|
+
* Hooks and `core.fsmonitor` can be overridden, but a filter driver
|
|
10
|
+
* (`filter.<name>.clean`/`.smudge` in `.git/config`, selected by
|
|
11
|
+
* `.git/info/attributes`) cannot: git has no switch that ignores repository
|
|
12
|
+
* config or `$GIT_DIR/info/attributes`, and overriding each driver by name
|
|
13
|
+
* races an agent that keeps rewriting the file.
|
|
14
|
+
*
|
|
15
|
+
* So the git that records and checks out trees runs against a **shadow**
|
|
16
|
+
* `GIT_DIR`: a bare repository this module creates under the host's temporary
|
|
17
|
+
* directory for one operation and deletes afterwards. Its config, hooks and
|
|
18
|
+
* `info/attributes` are the ones `git init --template=` writes, which is none.
|
|
19
|
+
* `GIT_CONFIG_NOSYSTEM` and `GIT_CONFIG_GLOBAL=/dev/null` drop the host's own
|
|
20
|
+
* config files too, so the only settings are the ones on the command line.
|
|
21
|
+
* `GIT_OBJECT_DIRECTORY` points at the workspace's object store, because objects
|
|
22
|
+
* are data: git hashes and inflates them and never runs anything they say.
|
|
23
|
+
*
|
|
24
|
+
* What still touches the workspace repository is plain data:
|
|
25
|
+
*
|
|
26
|
+
* - `rev-parse` in the workspace, which resolves refs and paths and runs no
|
|
27
|
+
* hook, filter, fsmonitor or other configured program;
|
|
28
|
+
* - `git config --file <workspace config>`, which reads or writes that one file
|
|
29
|
+
* and follows no `include`;
|
|
30
|
+
* - a copy of the workspace index into the shadow, so the recorded tree holds
|
|
31
|
+
* what the agent staged without the harness writing the agent's index; and
|
|
32
|
+
* - a handful of `core.*` settings that change how bytes are hashed
|
|
33
|
+
* ({@link dataSettings}), each accepted only as a bare word.
|
|
34
|
+
*
|
|
35
|
+
* A materialized checkout gets its own standalone `.git`, written by this
|
|
36
|
+
* module as files, so a container can still run git in it: `HEAD` names the
|
|
37
|
+
* commit, `objects/info/alternates` points back at the workspace's objects by a
|
|
38
|
+
* relative path, and `index` is the one the checkout was written from. Host git
|
|
39
|
+
* never uses that directory; it is the container's.
|
|
40
|
+
*
|
|
41
|
+
* @since 1.0.0
|
|
42
|
+
*/
|
|
43
|
+
import { Effect } from "effect";
|
|
44
|
+
import * as StdError from "../StdError.js";
|
|
45
|
+
import * as Exec from "./Exec.js";
|
|
46
|
+
const failed = (message, code = "command_failed") => new StdError.StdError({ code, message });
|
|
47
|
+
/**
|
|
48
|
+
* Settings that stop the workspace repository from naming a program for the
|
|
49
|
+
* `rev-parse` this module runs in it. `rev-parse` runs none of them; these keep
|
|
50
|
+
* that true if a later call is added beside it.
|
|
51
|
+
*/
|
|
52
|
+
const hostGitSettings = ["-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false"];
|
|
53
|
+
/** Host config files git would otherwise read, removed from every shadow command. */
|
|
54
|
+
const isolated = { GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: "/dev/null" };
|
|
55
|
+
/**
|
|
56
|
+
* Workspace settings that change how a tree is hashed or compared, carried
|
|
57
|
+
* onto the shadow so a checkpoint records what the agent's own git would.
|
|
58
|
+
* None of them names a program.
|
|
59
|
+
*/
|
|
60
|
+
const dataSettings = /^core\.(autocrlf|eol|safecrlf|filemode|symlinks|ignorecase|precomposeunicode)$/;
|
|
61
|
+
/** A setting value this module will repeat to git: a bare word, never a command. */
|
|
62
|
+
const bareWord = /^[A-Za-z0-9_-]+$/;
|
|
63
|
+
const run = (command, args, env) => Exec.exec(command, { args, ...(env === undefined ? {} : { env }) }).pipe(Effect.mapError((error) => failed(`${command} could not run: ${error.message}`)));
|
|
64
|
+
/**
|
|
65
|
+
* Runs host git in the workspace at `root`, for `rev-parse` only.
|
|
66
|
+
*
|
|
67
|
+
* @category utilities
|
|
68
|
+
* @since 1.0.0
|
|
69
|
+
*/
|
|
70
|
+
const git = (root, args) => run("git", [...hostGitSettings, "-C", root, ...args]);
|
|
71
|
+
const resolveCommit = (root, refs) => Effect.gen(function* () {
|
|
72
|
+
for (const ref of refs) {
|
|
73
|
+
const answer = yield* git(root, ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`]);
|
|
74
|
+
const commit = answer.stdout.trim();
|
|
75
|
+
if (answer.exitCode === 0 && commit !== "")
|
|
76
|
+
return { ref, commit };
|
|
77
|
+
}
|
|
78
|
+
return yield* Effect.fail(failed(`No commit resolves from ${refs.join(" or ")} in ${root}.`, "not_found"));
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Reads or writes the workspace's config file as a file, never as a repository.
|
|
82
|
+
*
|
|
83
|
+
* `--git-dir=/dev/null` stops git discovering any repository around the host's
|
|
84
|
+
* working directory, and `--file` reads the one file without `include`s.
|
|
85
|
+
*
|
|
86
|
+
* @category utilities
|
|
87
|
+
* @since 1.0.0
|
|
88
|
+
*/
|
|
89
|
+
const config = (repository, args) => run("git", ["--git-dir=/dev/null", "config", "--file", `${repository.common}/config`, ...args], isolated);
|
|
90
|
+
const open = (root) => Effect.gen(function* () {
|
|
91
|
+
const stripped = root.replace(/\/+$/, "");
|
|
92
|
+
const answer = yield* git(stripped, [
|
|
93
|
+
"rev-parse",
|
|
94
|
+
"--path-format=absolute",
|
|
95
|
+
"--show-toplevel",
|
|
96
|
+
"--git-common-dir",
|
|
97
|
+
"--git-path",
|
|
98
|
+
"index",
|
|
99
|
+
"--show-object-format"
|
|
100
|
+
]);
|
|
101
|
+
const [toplevel, common, index, objectFormat] = answer.stdout.split("\n").map((line) => line.trim());
|
|
102
|
+
if (answer.exitCode !== 0 || toplevel === undefined || toplevel === "" || common === undefined || common === "" ||
|
|
103
|
+
index === undefined || index === "" || objectFormat === undefined || !bareWord.test(objectFormat)) {
|
|
104
|
+
return yield* Effect.fail(failed(`${stripped} is not a git work tree: ${answer.stderr.trim()}`));
|
|
105
|
+
}
|
|
106
|
+
const found = yield* config({ common }, ["--get-regexp", dataSettings.source]);
|
|
107
|
+
const settings = found.exitCode === 0
|
|
108
|
+
? found.stdout.split("\n").flatMap((line) => {
|
|
109
|
+
const [key, value] = line.trim().split(/\s+/);
|
|
110
|
+
return key !== undefined && value !== undefined && dataSettings.test(key) && bareWord.test(value)
|
|
111
|
+
? ["-c", `${key}=${value}`]
|
|
112
|
+
: [];
|
|
113
|
+
})
|
|
114
|
+
: [];
|
|
115
|
+
return { root: stripped, toplevel, common, index, objectFormat, settings };
|
|
116
|
+
});
|
|
117
|
+
const temporaryRoot = () => {
|
|
118
|
+
const configured = globalThis.process?.env?.TMPDIR?.replace(/\/+$/, "");
|
|
119
|
+
return configured === undefined || configured === "" ? "/tmp" : configured;
|
|
120
|
+
};
|
|
121
|
+
const remove = (path) => run("rm", ["-rf", "--", path]).pipe(Effect.flatMap((removed) => removed.exitCode === 0 ? Effect.void : Effect.fail(failed(removed.stderr.trim()))));
|
|
122
|
+
/** The `adoptIndex` script: `$1` is the workspace index, `$2` the shadow's. */
|
|
123
|
+
const adoptIndexScript = [
|
|
124
|
+
"set -C",
|
|
125
|
+
"if [ -e \"$1\" ]",
|
|
126
|
+
"then : > \"$2.at\" && touch -r \"$1\" -- \"$2.at\" && cat -- \"$1\" > \"$2\" && touch -r \"$2.at\" -- \"$2\" && rm -f -- \"$2.at\"",
|
|
127
|
+
"fi"
|
|
128
|
+
].join("; ");
|
|
129
|
+
const shadowOf = (repository, path) => ({
|
|
130
|
+
path,
|
|
131
|
+
repository,
|
|
132
|
+
git: (args, workTree) => run("git", [
|
|
133
|
+
`--git-dir=${path}`,
|
|
134
|
+
...(workTree === undefined ? [] : [`--work-tree=${workTree}`]),
|
|
135
|
+
...hostGitSettings,
|
|
136
|
+
...repository.settings,
|
|
137
|
+
...args
|
|
138
|
+
], { ...isolated, GIT_OBJECT_DIRECTORY: `${repository.common}/objects` }),
|
|
139
|
+
adoptIndex: run("sh", [
|
|
140
|
+
"-c",
|
|
141
|
+
adoptIndexScript,
|
|
142
|
+
"sh",
|
|
143
|
+
repository.index,
|
|
144
|
+
`${path}/index`
|
|
145
|
+
]).pipe(Effect.flatMap((copied) => copied.exitCode === 0
|
|
146
|
+
? Effect.void
|
|
147
|
+
: Effect.fail(failed(`Could not read the workspace index: ${copied.stderr.trim()}`))))
|
|
148
|
+
});
|
|
149
|
+
/**
|
|
150
|
+
* Runs `use` with a fresh {@link Shadow} over the repository at `root`, and
|
|
151
|
+
* deletes the shadow however `use` ends.
|
|
152
|
+
*
|
|
153
|
+
* @category utilities
|
|
154
|
+
* @since 1.0.0
|
|
155
|
+
*/
|
|
156
|
+
const withShadow = (root, use) => Effect.gen(function* () {
|
|
157
|
+
const repository = typeof root === "string" ? yield* open(root) : root;
|
|
158
|
+
const path = `${temporaryRoot()}/smithers-git-${globalThis.crypto.randomUUID()}`;
|
|
159
|
+
return yield* Effect.acquireUseRelease(Effect.succeed(path), () => Effect.gen(function* () {
|
|
160
|
+
const created = yield* run("git", ["init", "--quiet", "--bare", "--template=", `--object-format=${repository.objectFormat}`, path], isolated);
|
|
161
|
+
if (created.exitCode !== 0) {
|
|
162
|
+
return yield* Effect.fail(failed(`Could not create a shadow repository: ${created.stderr.trim()}`));
|
|
163
|
+
}
|
|
164
|
+
return yield* use(shadowOf(repository, path));
|
|
165
|
+
}), () => remove(path).pipe(Effect.catch((error) => Effect.logWarning("could not remove a shadow repository").pipe(Effect.annotateLogs({ path, reason: error.message })))));
|
|
166
|
+
});
|
|
167
|
+
/** `to` relative to `from`, both absolute POSIX paths. */
|
|
168
|
+
const relative = (from, to) => {
|
|
169
|
+
const source = from.split("/").filter((part) => part !== "");
|
|
170
|
+
const target = to.split("/").filter((part) => part !== "");
|
|
171
|
+
let shared = 0;
|
|
172
|
+
while (shared < source.length && shared < target.length && source[shared] === target[shared])
|
|
173
|
+
shared++;
|
|
174
|
+
return [...source.slice(shared).map(() => ".."), ...target.slice(shared)].join("/") || ".";
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* The config of a checkout's own `.git`, for the container's git.
|
|
178
|
+
*
|
|
179
|
+
* Only {@link dataSettings}, already restricted to bare words, reach it.
|
|
180
|
+
*/
|
|
181
|
+
const checkoutConfig = (repository) => {
|
|
182
|
+
const sha1 = repository.objectFormat === "sha1";
|
|
183
|
+
const lines = [
|
|
184
|
+
"[core]",
|
|
185
|
+
`\trepositoryformatversion = ${sha1 ? 0 : 1}`,
|
|
186
|
+
"\tbare = false",
|
|
187
|
+
...repository.settings.filter((_, index) => index % 2 === 1).map((setting) => {
|
|
188
|
+
const [key, value] = setting.split("=");
|
|
189
|
+
return `\t${key?.slice("core.".length)} = ${value}`;
|
|
190
|
+
}),
|
|
191
|
+
...(sha1 ? [] : ["[extensions]", `\tobjectformat = ${repository.objectFormat}`])
|
|
192
|
+
];
|
|
193
|
+
return `${lines.join("\n")}\n`;
|
|
194
|
+
};
|
|
195
|
+
/** Fails with `message` and the command's stderr unless it exited 0. */
|
|
196
|
+
const succeeded = (result, message) => result.exitCode === 0 ? Effect.void : Effect.fail(failed(`${message}: ${result.stderr.trim()}`));
|
|
197
|
+
/**
|
|
198
|
+
* Measures which staging directory shares the filesystem of the checkout's
|
|
199
|
+
* parent `$1`: the shadow `$2`, the workspace root's parent `$3`, or the host
|
|
200
|
+
* cache directory `$4`. Prints one line each for the parent, the shadow, the
|
|
201
|
+
* root's parent (`unwritable` when the host user cannot create a stage there)
|
|
202
|
+
* and the cache (empty unless both others missed and it could be created).
|
|
203
|
+
* `stat -c` is GNU and BusyBox, `stat -f` is BSD; an empty line means neither
|
|
204
|
+
* answered.
|
|
205
|
+
*/
|
|
206
|
+
const measure = [
|
|
207
|
+
"set -e",
|
|
208
|
+
"mkdir -p -- \"$1\"",
|
|
209
|
+
"dev() { stat -c %d -- \"$1\" 2>/dev/null || stat -f %d -- \"$1\" 2>/dev/null || echo; }",
|
|
210
|
+
"t=$(dev \"$1\")",
|
|
211
|
+
"s=$(dev \"$2\")",
|
|
212
|
+
"if [ -w \"$3\" ]; then b=$(dev \"$3\"); else b=unwritable; fi",
|
|
213
|
+
"c=",
|
|
214
|
+
"if [ -n \"$t\" ] && [ \"$t\" != \"$s\" ] && [ \"$t\" != \"$b\" ] && [ -n \"$4\" ] && mkdir -p -m 700 -- \"$4\" 2>/dev/null; then c=$(dev \"$4\"); fi",
|
|
215
|
+
"printf '%s\\n' \"$t\" \"$s\" \"$b\" \"$c\""
|
|
216
|
+
].join("; ");
|
|
217
|
+
/**
|
|
218
|
+
* The host user's cache directory for checkout stages: `$XDG_CACHE_HOME`, or
|
|
219
|
+
* `~/.cache`, under `smithers`. Empty when neither is an absolute path.
|
|
220
|
+
*/
|
|
221
|
+
const cacheRoot = () => {
|
|
222
|
+
const env = globalThis.process?.env;
|
|
223
|
+
const xdg = env?.XDG_CACHE_HOME?.replace(/\/+$/, "");
|
|
224
|
+
if (xdg !== undefined && xdg.startsWith("/"))
|
|
225
|
+
return `${xdg}/smithers`;
|
|
226
|
+
const home = env?.HOME?.replace(/\/+$/, "");
|
|
227
|
+
return home !== undefined && home.startsWith("/") ? `${home}/.cache/smithers` : "";
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Moves the staged checkout `$1` into the directory `$2` under the name `$3`
|
|
231
|
+
* in one `rename`, then proves the directory there is the one that was staged.
|
|
232
|
+
* The staging directory is on the same filesystem, so `mv` renames and never
|
|
233
|
+
* copies.
|
|
234
|
+
*
|
|
235
|
+
* The shell first enters `$2` by its physical path and refuses unless that
|
|
236
|
+
* lies under the real path of the workspace root `$4`. The rename then names
|
|
237
|
+
* the target relative to that directory, so a parent the agent swaps for a
|
|
238
|
+
* symlink, before or after the check, cannot carry the checkout out of the
|
|
239
|
+
* workspace.
|
|
240
|
+
*/
|
|
241
|
+
const publish = [
|
|
242
|
+
"set -e",
|
|
243
|
+
"root=$(cd -P -- \"$4\" && pwd -P)",
|
|
244
|
+
"cd -P -- \"$2\"",
|
|
245
|
+
"here=$(pwd -P)",
|
|
246
|
+
"case \"$here\" in \"$root\"|\"$root\"/*) ;; *) echo \"$2 resolves to $here, outside the workspace $root\" >&2; exit 1 ;; esac",
|
|
247
|
+
"if [ -e \"./$3\" ] || [ -L \"./$3\" ]; then echo \"$2/$3 already exists\" >&2; exit 1; fi",
|
|
248
|
+
"staged=$(ls -di -- \"$1\" | awk '{print $1}')",
|
|
249
|
+
"mv -- \"$1\" \"./$3\"",
|
|
250
|
+
"if [ -L \"./$3\" ] || [ ! -d \"./$3\" ]; then echo \"$2/$3 was replaced while it was written\" >&2; exit 1; fi",
|
|
251
|
+
"moved=$(ls -di -- \"./$3\" | awk '{print $1}')",
|
|
252
|
+
"if [ \"$staged\" != \"$moved\" ]; then echo \"$2/$3 was replaced while it was written\" >&2; exit 1; fi"
|
|
253
|
+
].join("; ");
|
|
254
|
+
/**
|
|
255
|
+
* Checks `commit`'s tree out at the new directory `host`, with a standalone
|
|
256
|
+
* `.git` the container's git can use.
|
|
257
|
+
*
|
|
258
|
+
* Host git never writes into an agent-writable directory. The tree and its
|
|
259
|
+
* `.git` are written into a staging directory the agent cannot reach: inside
|
|
260
|
+
* the shadow, or, when the host's temporary directory is another filesystem,
|
|
261
|
+
* beside the workspace root or under the host user's cache directory. One
|
|
262
|
+
* `rename` then gives the finished directory its name under the workspace. A
|
|
263
|
+
* path the agent swaps for a symlink cannot redirect a write: a symlink at
|
|
264
|
+
* `host` fails the call before the rename, and a parent that resolves outside
|
|
265
|
+
* the workspace root fails it before the rename too.
|
|
266
|
+
*/
|
|
267
|
+
const checkout = (shadow, host, commit) => Effect.gen(function* () {
|
|
268
|
+
const repository = shadow.repository;
|
|
269
|
+
const parent = host.slice(0, host.lastIndexOf("/"));
|
|
270
|
+
const name = host.slice(host.lastIndexOf("/") + 1);
|
|
271
|
+
const beside = repository.root.slice(0, repository.root.lastIndexOf("/")) || "/";
|
|
272
|
+
const cache = cacheRoot();
|
|
273
|
+
const stage = `checkout-${globalThis.crypto.randomUUID()}`;
|
|
274
|
+
const besideStage = `${beside.replace(/\/+$/, "")}/.smithers-${stage}`;
|
|
275
|
+
const cacheStage = `${cache}/${stage}`;
|
|
276
|
+
const measured = yield* run("sh", ["-c", measure, "sh", parent, shadow.path, beside, cache]);
|
|
277
|
+
yield* succeeded(measured, `Could not check out ${commit}`);
|
|
278
|
+
const [target, inShadow, besideRoot, inCache] = measured.stdout.split("\n").map((line) => line.trim());
|
|
279
|
+
const scratch = target === undefined || target === "" || target === inShadow
|
|
280
|
+
? undefined
|
|
281
|
+
: target === besideRoot
|
|
282
|
+
? besideStage
|
|
283
|
+
: target === inCache
|
|
284
|
+
? cacheStage
|
|
285
|
+
: undefined;
|
|
286
|
+
const base = target === undefined || target === ""
|
|
287
|
+
? undefined
|
|
288
|
+
: target === inShadow
|
|
289
|
+
? shadow.path
|
|
290
|
+
: scratch;
|
|
291
|
+
if (base === undefined) {
|
|
292
|
+
const unwritable = besideRoot === "unwritable" ? " (not writable by this user)" : "";
|
|
293
|
+
return yield* Effect.fail(failed(`Could not check out ${commit}: neither ${shadow.path} nor ${beside}${unwritable} nor ${cache === "" ? "a cache directory" : cache} is on the filesystem of ${parent}`));
|
|
294
|
+
}
|
|
295
|
+
const staged = `${base}/${name}`;
|
|
296
|
+
const objects = relative(`${repository.toplevel}${host.slice(repository.root.length)}/.git/objects`, `${repository.common}/objects`);
|
|
297
|
+
const write = Effect.gen(function* () {
|
|
298
|
+
const prepared = yield* run("sh", [
|
|
299
|
+
"-c",
|
|
300
|
+
[
|
|
301
|
+
"set -eC",
|
|
302
|
+
...(scratch !== undefined ? ["mkdir -m 700 -- \"$1\""] : []),
|
|
303
|
+
"mkdir -- \"$2\" \"$2/.git\" \"$2/.git/objects\" \"$2/.git/objects/info\" \"$2/.git/refs\"",
|
|
304
|
+
"printf '%s\\n' \"$3\" > \"$2/.git/HEAD\"",
|
|
305
|
+
"printf '%s\\n' \"$4\" > \"$2/.git/objects/info/alternates\"",
|
|
306
|
+
"printf '%s' \"$5\" > \"$2/.git/config\""
|
|
307
|
+
].join("; "),
|
|
308
|
+
"sh",
|
|
309
|
+
base,
|
|
310
|
+
staged,
|
|
311
|
+
commit,
|
|
312
|
+
objects,
|
|
313
|
+
checkoutConfig(repository)
|
|
314
|
+
]);
|
|
315
|
+
yield* succeeded(prepared, `Could not check out ${commit}`);
|
|
316
|
+
const written = yield* shadow.git(["read-tree", "--reset", "-u", commit], staged);
|
|
317
|
+
yield* succeeded(written, `Could not check out ${commit}`);
|
|
318
|
+
const indexed = yield* run("sh", [
|
|
319
|
+
"-c",
|
|
320
|
+
"set -C; cat -- \"$1\" > \"$2\"",
|
|
321
|
+
"sh",
|
|
322
|
+
`${shadow.path}/index`,
|
|
323
|
+
`${staged}/.git/index`
|
|
324
|
+
]);
|
|
325
|
+
yield* succeeded(indexed, `Could not check out ${commit}`);
|
|
326
|
+
const moved = yield* run("sh", ["-c", publish, "sh", staged, parent, name, repository.root]);
|
|
327
|
+
yield* succeeded(moved, `Could not check out ${commit}`);
|
|
328
|
+
});
|
|
329
|
+
return yield* scratch !== undefined
|
|
330
|
+
? write.pipe(Effect.ensuring(remove(scratch).pipe(Effect.ignore)))
|
|
331
|
+
: write;
|
|
332
|
+
});
|
|
333
|
+
const withDetachedWorktree = (repository, prefix, commit, use) => Effect.gen(function* () {
|
|
334
|
+
// Allocate on execution, including when the same Effect is run twice.
|
|
335
|
+
// Never remove an existing checkout: another call may still be using it.
|
|
336
|
+
const host = `${repository.root}/${prefix}-${globalThis.crypto.randomUUID()}`;
|
|
337
|
+
return yield* Effect.acquireUseRelease(Effect.succeed(host), () => Effect.gen(function* () {
|
|
338
|
+
yield* withShadow(repository, (shadow) => checkout(shadow, host, commit));
|
|
339
|
+
return yield* use(host);
|
|
340
|
+
}),
|
|
341
|
+
// A checkout left behind is a stale copy of the repository inside the
|
|
342
|
+
// workspace. Walks prune it, but the operator must still hear about it.
|
|
343
|
+
() => remove(host).pipe(Effect.catch((error) => Effect.logWarning("could not remove a scratch checkout").pipe(Effect.annotateLogs({ path: host, reason: error.message })))));
|
|
344
|
+
});
|
|
345
|
+
/**
|
|
346
|
+
* Internal Git operations used by both checkpoint and baseline leases.
|
|
347
|
+
*
|
|
348
|
+
* @category utilities
|
|
349
|
+
* @since 1.0.0
|
|
350
|
+
*/
|
|
351
|
+
export const GitWorktree = { config, git, open, resolveCommit, withDetachedWorktree, withShadow };
|
|
352
|
+
//# sourceMappingURL=GitWorktree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitWorktree.js","sourceRoot":"","sources":["../../../src/internal/GitWorktree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Detached checkouts shared by checkpoint reads and baseline test runs.\n *\n * ## Host git never reads a file the agent can write that names a program\n *\n * The repository is the workspace's, and an agent can write its `.git`: a\n * containerised agent writes it through the bind mount. Git reads programs out\n * of that directory in more places than any list of `-c` overrides can close.\n * Hooks and `core.fsmonitor` can be overridden, but a filter driver\n * (`filter.<name>.clean`/`.smudge` in `.git/config`, selected by\n * `.git/info/attributes`) cannot: git has no switch that ignores repository\n * config or `$GIT_DIR/info/attributes`, and overriding each driver by name\n * races an agent that keeps rewriting the file.\n *\n * So the git that records and checks out trees runs against a **shadow**\n * `GIT_DIR`: a bare repository this module creates under the host's temporary\n * directory for one operation and deletes afterwards. Its config, hooks and\n * `info/attributes` are the ones `git init --template=` writes, which is none.\n * `GIT_CONFIG_NOSYSTEM` and `GIT_CONFIG_GLOBAL=/dev/null` drop the host's own\n * config files too, so the only settings are the ones on the command line.\n * `GIT_OBJECT_DIRECTORY` points at the workspace's object store, because objects\n * are data: git hashes and inflates them and never runs anything they say.\n *\n * What still touches the workspace repository is plain data:\n *\n * - `rev-parse` in the workspace, which resolves refs and paths and runs no\n * hook, filter, fsmonitor or other configured program;\n * - `git config --file <workspace config>`, which reads or writes that one file\n * and follows no `include`;\n * - a copy of the workspace index into the shadow, so the recorded tree holds\n * what the agent staged without the harness writing the agent's index; and\n * - a handful of `core.*` settings that change how bytes are hashed\n * ({@link dataSettings}), each accepted only as a bare word.\n *\n * A materialized checkout gets its own standalone `.git`, written by this\n * module as files, so a container can still run git in it: `HEAD` names the\n * commit, `objects/info/alternates` points back at the workspace's objects by a\n * relative path, and `index` is the one the checkout was written from. Host git\n * never uses that directory; it is the container's.\n *\n * @since 1.0.0\n */\n\nimport type { ChildProcessSpawner } from \"@smthrs/kernel/ChildProcessSpawner\"\nimport { Effect } from \"effect\"\nimport * as StdError from \"../StdError.ts\"\nimport * as Exec from \"./Exec.ts\"\n\nconst failed = (message: string, code: StdError.Code = \"command_failed\") => new StdError.StdError({ code, message })\n\n/**\n * Settings that stop the workspace repository from naming a program for the\n * `rev-parse` this module runs in it. `rev-parse` runs none of them; these keep\n * that true if a later call is added beside it.\n */\nconst hostGitSettings = [\"-c\", \"core.hooksPath=/dev/null\", \"-c\", \"core.fsmonitor=false\"] as const\n\n/** Host config files git would otherwise read, removed from every shadow command. */\nconst isolated = { GIT_CONFIG_NOSYSTEM: \"1\", GIT_CONFIG_GLOBAL: \"/dev/null\" } as const\n\n/**\n * Workspace settings that change how a tree is hashed or compared, carried\n * onto the shadow so a checkpoint records what the agent's own git would.\n * None of them names a program.\n */\nconst dataSettings = /^core\\.(autocrlf|eol|safecrlf|filemode|symlinks|ignorecase|precomposeunicode)$/\n\n/** A setting value this module will repeat to git: a bare word, never a command. */\nconst bareWord = /^[A-Za-z0-9_-]+$/\n\nconst run = (command: string, args: ReadonlyArray<string>, env?: Readonly<Record<string, string>>) =>\n Exec.exec(command, { args, ...(env === undefined ? {} : { env }) }).pipe(\n Effect.mapError((error) => failed(`${command} could not run: ${error.message}`))\n )\n\n/**\n * Runs host git in the workspace at `root`, for `rev-parse` only.\n *\n * @category utilities\n * @since 1.0.0\n */\nconst git = (root: string, args: ReadonlyArray<string>) => run(\"git\", [...hostGitSettings, \"-C\", root, ...args])\n\nconst resolveCommit = (root: string, refs: ReadonlyArray<string>) =>\n Effect.gen(function*() {\n for (const ref of refs) {\n const answer = yield* git(root, [\"rev-parse\", \"--verify\", \"--quiet\", `${ref}^{commit}`])\n const commit = answer.stdout.trim()\n if (answer.exitCode === 0 && commit !== \"\") return { ref, commit }\n }\n return yield* Effect.fail(failed(`No commit resolves from ${refs.join(\" or \")} in ${root}.`, \"not_found\"))\n })\n\n/**\n * Where one workspace repository keeps what the shadow needs, as its own git\n * reports it.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Repository {\n /** The root the caller named, without a trailing slash. */\n readonly root: string\n /** The same directory, as git canonicalizes it. */\n readonly toplevel: string\n /** The common git directory, which holds config and objects. */\n readonly common: string\n /** The workspace index. */\n readonly index: string\n readonly objectFormat: string\n /** {@link dataSettings} as `-c` arguments. */\n readonly settings: ReadonlyArray<string>\n}\n\n/**\n * Reads or writes the workspace's config file as a file, never as a repository.\n *\n * `--git-dir=/dev/null` stops git discovering any repository around the host's\n * working directory, and `--file` reads the one file without `include`s.\n *\n * @category utilities\n * @since 1.0.0\n */\nconst config = (repository: Pick<Repository, \"common\">, args: ReadonlyArray<string>) =>\n run(\"git\", [\"--git-dir=/dev/null\", \"config\", \"--file\", `${repository.common}/config`, ...args], isolated)\n\nconst open = (root: string): Effect.Effect<Repository, StdError.StdError, ChildProcessSpawner> =>\n Effect.gen(function*() {\n const stripped = root.replace(/\\/+$/, \"\")\n const answer = yield* git(stripped, [\n \"rev-parse\",\n \"--path-format=absolute\",\n \"--show-toplevel\",\n \"--git-common-dir\",\n \"--git-path\",\n \"index\",\n \"--show-object-format\"\n ])\n const [toplevel, common, index, objectFormat] = answer.stdout.split(\"\\n\").map((line) => line.trim())\n if (\n answer.exitCode !== 0 || toplevel === undefined || toplevel === \"\" || common === undefined || common === \"\" ||\n index === undefined || index === \"\" || objectFormat === undefined || !bareWord.test(objectFormat)\n ) {\n return yield* Effect.fail(failed(`${stripped} is not a git work tree: ${answer.stderr.trim()}`))\n }\n const found = yield* config({ common }, [\"--get-regexp\", dataSettings.source])\n const settings = found.exitCode === 0\n ? found.stdout.split(\"\\n\").flatMap((line) => {\n const [key, value] = line.trim().split(/\\s+/)\n return key !== undefined && value !== undefined && dataSettings.test(key) && bareWord.test(value)\n ? [\"-c\", `${key}=${value}`]\n : []\n })\n : []\n return { root: stripped, toplevel, common, index, objectFormat, settings }\n })\n\nconst temporaryRoot = (): string => {\n const configured = globalThis.process?.env?.TMPDIR?.replace(/\\/+$/, \"\")\n return configured === undefined || configured === \"\" ? \"/tmp\" : configured\n}\n\nconst remove = (path: string) =>\n run(\"rm\", [\"-rf\", \"--\", path]).pipe(\n Effect.flatMap((removed) => removed.exitCode === 0 ? Effect.void : Effect.fail(failed(removed.stderr.trim())))\n )\n\n/**\n * A harness-owned `GIT_DIR` over one workspace's objects.\n *\n * @category models\n * @since 1.0.0\n */\nexport interface Shadow {\n readonly path: string\n readonly repository: Repository\n /** Runs host git with the shadow as `GIT_DIR`, and `workTree` as its work tree when given. */\n readonly git: (\n args: ReadonlyArray<string>,\n workTree?: string\n ) => Effect.Effect<Exec.ExecResult, StdError.StdError, ChildProcessSpawner>\n /**\n * Copies the workspace index into the shadow, with its modification time, so\n * the shadow never writes the agent's own.\n *\n * The time is part of what git reads. It trusts an entry's recorded stat\n * unless the entry is at least as new as the index file, in whole seconds;\n * a copy stamped at the moment of copying made every entry look older, and a\n * same-size edit from the second the index was written was recorded as the\n * committed bytes (#3431). The time is taken before the bytes are read, so\n * an index rewritten meanwhile leaves the copy looking older, never newer.\n */\n readonly adoptIndex: Effect.Effect<void, StdError.StdError, ChildProcessSpawner>\n}\n\n/** The `adoptIndex` script: `$1` is the workspace index, `$2` the shadow's. */\nconst adoptIndexScript = [\n \"set -C\",\n \"if [ -e \\\"$1\\\" ]\",\n \"then : > \\\"$2.at\\\" && touch -r \\\"$1\\\" -- \\\"$2.at\\\" && cat -- \\\"$1\\\" > \\\"$2\\\" && touch -r \\\"$2.at\\\" -- \\\"$2\\\" && rm -f -- \\\"$2.at\\\"\",\n \"fi\"\n].join(\"; \")\n\nconst shadowOf = (repository: Repository, path: string): Shadow => ({\n path,\n repository,\n git: (args, workTree) =>\n run(\n \"git\",\n [\n `--git-dir=${path}`,\n ...(workTree === undefined ? [] : [`--work-tree=${workTree}`]),\n ...hostGitSettings,\n ...repository.settings,\n ...args\n ],\n { ...isolated, GIT_OBJECT_DIRECTORY: `${repository.common}/objects` }\n ),\n adoptIndex: run(\"sh\", [\n \"-c\",\n adoptIndexScript,\n \"sh\",\n repository.index,\n `${path}/index`\n ]).pipe(\n Effect.flatMap((copied) =>\n copied.exitCode === 0\n ? Effect.void\n : Effect.fail(failed(`Could not read the workspace index: ${copied.stderr.trim()}`))\n )\n )\n})\n\n/**\n * Runs `use` with a fresh {@link Shadow} over the repository at `root`, and\n * deletes the shadow however `use` ends.\n *\n * @category utilities\n * @since 1.0.0\n */\nconst withShadow = <A, E, R>(\n root: string | Repository,\n use: (shadow: Shadow) => Effect.Effect<A, E, R>\n): Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner> =>\n Effect.gen(function*() {\n const repository = typeof root === \"string\" ? yield* open(root) : root\n const path = `${temporaryRoot()}/smithers-git-${globalThis.crypto.randomUUID()}`\n return yield* Effect.acquireUseRelease(\n Effect.succeed(path),\n () =>\n Effect.gen(function*() {\n const created = yield* run(\n \"git\",\n [\"init\", \"--quiet\", \"--bare\", \"--template=\", `--object-format=${repository.objectFormat}`, path],\n isolated\n )\n if (created.exitCode !== 0) {\n return yield* Effect.fail(failed(`Could not create a shadow repository: ${created.stderr.trim()}`))\n }\n return yield* use(shadowOf(repository, path))\n }),\n () =>\n remove(path).pipe(\n Effect.catch((error) =>\n Effect.logWarning(\"could not remove a shadow repository\").pipe(\n Effect.annotateLogs({ path, reason: error.message })\n )\n )\n )\n )\n })\n\n/** `to` relative to `from`, both absolute POSIX paths. */\nconst relative = (from: string, to: string): string => {\n const source = from.split(\"/\").filter((part) => part !== \"\")\n const target = to.split(\"/\").filter((part) => part !== \"\")\n let shared = 0\n while (shared < source.length && shared < target.length && source[shared] === target[shared]) shared++\n return [...source.slice(shared).map(() => \"..\"), ...target.slice(shared)].join(\"/\") || \".\"\n}\n\n/**\n * The config of a checkout's own `.git`, for the container's git.\n *\n * Only {@link dataSettings}, already restricted to bare words, reach it.\n */\nconst checkoutConfig = (repository: Repository): string => {\n const sha1 = repository.objectFormat === \"sha1\"\n const lines = [\n \"[core]\",\n `\\trepositoryformatversion = ${sha1 ? 0 : 1}`,\n \"\\tbare = false\",\n ...repository.settings.filter((_, index) => index % 2 === 1).map((setting) => {\n const [key, value] = setting.split(\"=\")\n return `\\t${key?.slice(\"core.\".length)} = ${value}`\n }),\n ...(sha1 ? [] : [\"[extensions]\", `\\tobjectformat = ${repository.objectFormat}`])\n ]\n return `${lines.join(\"\\n\")}\\n`\n}\n\n/** Fails with `message` and the command's stderr unless it exited 0. */\nconst succeeded = (result: Exec.ExecResult, message: string) =>\n result.exitCode === 0 ? Effect.void : Effect.fail(failed(`${message}: ${result.stderr.trim()}`))\n\n/**\n * Measures which staging directory shares the filesystem of the checkout's\n * parent `$1`: the shadow `$2`, the workspace root's parent `$3`, or the host\n * cache directory `$4`. Prints one line each for the parent, the shadow, the\n * root's parent (`unwritable` when the host user cannot create a stage there)\n * and the cache (empty unless both others missed and it could be created).\n * `stat -c` is GNU and BusyBox, `stat -f` is BSD; an empty line means neither\n * answered.\n */\nconst measure = [\n \"set -e\",\n \"mkdir -p -- \\\"$1\\\"\",\n \"dev() { stat -c %d -- \\\"$1\\\" 2>/dev/null || stat -f %d -- \\\"$1\\\" 2>/dev/null || echo; }\",\n \"t=$(dev \\\"$1\\\")\",\n \"s=$(dev \\\"$2\\\")\",\n \"if [ -w \\\"$3\\\" ]; then b=$(dev \\\"$3\\\"); else b=unwritable; fi\",\n \"c=\",\n \"if [ -n \\\"$t\\\" ] && [ \\\"$t\\\" != \\\"$s\\\" ] && [ \\\"$t\\\" != \\\"$b\\\" ] && [ -n \\\"$4\\\" ] && mkdir -p -m 700 -- \\\"$4\\\" 2>/dev/null; then c=$(dev \\\"$4\\\"); fi\",\n \"printf '%s\\\\n' \\\"$t\\\" \\\"$s\\\" \\\"$b\\\" \\\"$c\\\"\"\n].join(\"; \")\n\n/**\n * The host user's cache directory for checkout stages: `$XDG_CACHE_HOME`, or\n * `~/.cache`, under `smithers`. Empty when neither is an absolute path.\n */\nconst cacheRoot = (): string => {\n const env = globalThis.process?.env\n const xdg = env?.XDG_CACHE_HOME?.replace(/\\/+$/, \"\")\n if (xdg !== undefined && xdg.startsWith(\"/\")) return `${xdg}/smithers`\n const home = env?.HOME?.replace(/\\/+$/, \"\")\n return home !== undefined && home.startsWith(\"/\") ? `${home}/.cache/smithers` : \"\"\n}\n\n/**\n * Moves the staged checkout `$1` into the directory `$2` under the name `$3`\n * in one `rename`, then proves the directory there is the one that was staged.\n * The staging directory is on the same filesystem, so `mv` renames and never\n * copies.\n *\n * The shell first enters `$2` by its physical path and refuses unless that\n * lies under the real path of the workspace root `$4`. The rename then names\n * the target relative to that directory, so a parent the agent swaps for a\n * symlink, before or after the check, cannot carry the checkout out of the\n * workspace.\n */\nconst publish = [\n \"set -e\",\n \"root=$(cd -P -- \\\"$4\\\" && pwd -P)\",\n \"cd -P -- \\\"$2\\\"\",\n \"here=$(pwd -P)\",\n \"case \\\"$here\\\" in \\\"$root\\\"|\\\"$root\\\"/*) ;; *) echo \\\"$2 resolves to $here, outside the workspace $root\\\" >&2; exit 1 ;; esac\",\n \"if [ -e \\\"./$3\\\" ] || [ -L \\\"./$3\\\" ]; then echo \\\"$2/$3 already exists\\\" >&2; exit 1; fi\",\n \"staged=$(ls -di -- \\\"$1\\\" | awk '{print $1}')\",\n \"mv -- \\\"$1\\\" \\\"./$3\\\"\",\n \"if [ -L \\\"./$3\\\" ] || [ ! -d \\\"./$3\\\" ]; then echo \\\"$2/$3 was replaced while it was written\\\" >&2; exit 1; fi\",\n \"moved=$(ls -di -- \\\"./$3\\\" | awk '{print $1}')\",\n \"if [ \\\"$staged\\\" != \\\"$moved\\\" ]; then echo \\\"$2/$3 was replaced while it was written\\\" >&2; exit 1; fi\"\n].join(\"; \")\n\n/**\n * Checks `commit`'s tree out at the new directory `host`, with a standalone\n * `.git` the container's git can use.\n *\n * Host git never writes into an agent-writable directory. The tree and its\n * `.git` are written into a staging directory the agent cannot reach: inside\n * the shadow, or, when the host's temporary directory is another filesystem,\n * beside the workspace root or under the host user's cache directory. One\n * `rename` then gives the finished directory its name under the workspace. A\n * path the agent swaps for a symlink cannot redirect a write: a symlink at\n * `host` fails the call before the rename, and a parent that resolves outside\n * the workspace root fails it before the rename too.\n */\nconst checkout = (shadow: Shadow, host: string, commit: string) =>\n Effect.gen(function*() {\n const repository = shadow.repository\n const parent = host.slice(0, host.lastIndexOf(\"/\"))\n const name = host.slice(host.lastIndexOf(\"/\") + 1)\n const beside = repository.root.slice(0, repository.root.lastIndexOf(\"/\")) || \"/\"\n const cache = cacheRoot()\n const stage = `checkout-${globalThis.crypto.randomUUID()}`\n const besideStage = `${beside.replace(/\\/+$/, \"\")}/.smithers-${stage}`\n const cacheStage = `${cache}/${stage}`\n const measured = yield* run(\"sh\", [\"-c\", measure, \"sh\", parent, shadow.path, beside, cache])\n yield* succeeded(measured, `Could not check out ${commit}`)\n const [target, inShadow, besideRoot, inCache] = measured.stdout.split(\"\\n\").map((line) => line.trim())\n const scratch = target === undefined || target === \"\" || target === inShadow\n ? undefined\n : target === besideRoot\n ? besideStage\n : target === inCache\n ? cacheStage\n : undefined\n const base = target === undefined || target === \"\"\n ? undefined\n : target === inShadow\n ? shadow.path\n : scratch\n if (base === undefined) {\n const unwritable = besideRoot === \"unwritable\" ? \" (not writable by this user)\" : \"\"\n return yield* Effect.fail(\n failed(\n `Could not check out ${commit}: neither ${shadow.path} nor ${beside}${unwritable} nor ${\n cache === \"\" ? \"a cache directory\" : cache\n } is on the filesystem of ${parent}`\n )\n )\n }\n const staged = `${base}/${name}`\n const objects = relative(\n `${repository.toplevel}${host.slice(repository.root.length)}/.git/objects`,\n `${repository.common}/objects`\n )\n const write = Effect.gen(function*() {\n const prepared = yield* run(\"sh\", [\n \"-c\",\n [\n \"set -eC\",\n ...(scratch !== undefined ? [\"mkdir -m 700 -- \\\"$1\\\"\"] : []),\n \"mkdir -- \\\"$2\\\" \\\"$2/.git\\\" \\\"$2/.git/objects\\\" \\\"$2/.git/objects/info\\\" \\\"$2/.git/refs\\\"\",\n \"printf '%s\\\\n' \\\"$3\\\" > \\\"$2/.git/HEAD\\\"\",\n \"printf '%s\\\\n' \\\"$4\\\" > \\\"$2/.git/objects/info/alternates\\\"\",\n \"printf '%s' \\\"$5\\\" > \\\"$2/.git/config\\\"\"\n ].join(\"; \"),\n \"sh\",\n base,\n staged,\n commit,\n objects,\n checkoutConfig(repository)\n ])\n yield* succeeded(prepared, `Could not check out ${commit}`)\n const written = yield* shadow.git([\"read-tree\", \"--reset\", \"-u\", commit], staged)\n yield* succeeded(written, `Could not check out ${commit}`)\n const indexed = yield* run(\"sh\", [\n \"-c\",\n \"set -C; cat -- \\\"$1\\\" > \\\"$2\\\"\",\n \"sh\",\n `${shadow.path}/index`,\n `${staged}/.git/index`\n ])\n yield* succeeded(indexed, `Could not check out ${commit}`)\n const moved = yield* run(\"sh\", [\"-c\", publish, \"sh\", staged, parent, name, repository.root])\n yield* succeeded(moved, `Could not check out ${commit}`)\n })\n return yield* scratch !== undefined\n ? write.pipe(Effect.ensuring(remove(scratch).pipe(Effect.ignore)))\n : write\n })\n\nconst withDetachedWorktree = <A, E, R>(\n repository: Repository,\n prefix: string,\n commit: string,\n use: (host: string) => Effect.Effect<A, E, R>\n): Effect.Effect<A, E | StdError.StdError, R | ChildProcessSpawner> =>\n Effect.gen(function*() {\n // Allocate on execution, including when the same Effect is run twice.\n // Never remove an existing checkout: another call may still be using it.\n const host = `${repository.root}/${prefix}-${globalThis.crypto.randomUUID()}`\n return yield* Effect.acquireUseRelease(\n Effect.succeed(host),\n () =>\n Effect.gen(function*() {\n yield* withShadow(repository, (shadow) => checkout(shadow, host, commit))\n return yield* use(host)\n }),\n // A checkout left behind is a stale copy of the repository inside the\n // workspace. Walks prune it, but the operator must still hear about it.\n () =>\n remove(host).pipe(\n Effect.catch((error) =>\n Effect.logWarning(\"could not remove a scratch checkout\").pipe(\n Effect.annotateLogs({ path: host, reason: error.message })\n )\n )\n )\n )\n })\n\n/**\n * Internal Git operations used by both checkpoint and baseline leases.\n *\n * @category utilities\n * @since 1.0.0\n */\nexport const GitWorktree = { config, git, open, resolveCommit, withDetachedWorktree, withShadow }\n"]}
|