@smthrs/std 0.0.0-stage → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -0
- package/LICENSE +21 -0
- package/README.md +152 -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 +380 -0
- package/dist/cjs/Bash.d.ts.map +1 -0
- package/dist/cjs/Bash.js +332 -0
- package/dist/cjs/Bash.js.map +7 -0
- package/dist/cjs/Checkpoints.d.ts +279 -0
- package/dist/cjs/Checkpoints.d.ts.map +1 -0
- package/dist/cjs/Checkpoints.js +145 -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 +24 -0
- package/dist/cjs/PortableSearch.d.ts.map +1 -0
- package/dist/cjs/PortableSearch.js +233 -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/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 +127 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +99 -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 +67 -0
- package/dist/cjs/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/cjs/internal/EnvelopePrecheck.js +124 -0
- package/dist/cjs/internal/EnvelopePrecheck.js.map +7 -0
- package/dist/cjs/internal/Exec.d.ts +139 -0
- package/dist/cjs/internal/Exec.d.ts.map +1 -0
- package/dist/cjs/internal/Exec.js +158 -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/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/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 +114 -0
- package/dist/cjs/internal/Text.d.ts.map +1 -0
- package/dist/cjs/internal/Text.js +82 -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 +380 -0
- package/dist/esm/Bash.d.ts.map +1 -0
- package/dist/esm/Bash.js +505 -0
- package/dist/esm/Bash.js.map +1 -0
- package/dist/esm/Checkpoints.d.ts +279 -0
- package/dist/esm/Checkpoints.d.ts.map +1 -0
- package/dist/esm/Checkpoints.js +298 -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 +24 -0
- package/dist/esm/PortableSearch.d.ts.map +1 -0
- package/dist/esm/PortableSearch.js +240 -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/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 +127 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +127 -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 +67 -0
- package/dist/esm/internal/EnvelopePrecheck.d.ts.map +1 -0
- package/dist/esm/internal/EnvelopePrecheck.js +167 -0
- package/dist/esm/internal/EnvelopePrecheck.js.map +1 -0
- package/dist/esm/internal/Exec.d.ts +139 -0
- package/dist/esm/internal/Exec.d.ts.map +1 -0
- package/dist/esm/internal/Exec.js +193 -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/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/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 +114 -0
- package/dist/esm/internal/Text.d.ts.map +1 -0
- package/dist/esm/internal/Text.js +130 -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 +117 -0
- package/docs/api.md +472 -0
- package/docs/concepts/effects-and-capabilities.md +136 -0
- package/docs/concepts/flows-and-handlers.md +115 -0
- package/docs/concepts/limits-and-disclosure.md +102 -0
- package/docs/concepts/search-contract.md +182 -0
- package/docs/guides/bind-the-standard-flows.md +114 -0
- package/docs/guides/implement-a-search-peer.md +133 -0
- package/docs/guides/pin-a-checkpoint.md +141 -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 +215 -0
- package/docs/guides/run-the-test-suite.md +154 -0
- package/docs/guides/search-a-workspace.md +148 -0
- package/docs/installation.md +111 -0
- package/docs/quickstart.md +125 -0
- package/docs/reference/flows.md +556 -0
- package/docs/troubleshooting.md +322 -0
- package/package.json +439 -3
- package/src/ApplyPatch.ts +458 -0
- package/src/Bash.ts +607 -0
- package/src/Checkpoints.ts +422 -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 +264 -0
- package/src/Probe.ts +284 -0
- package/src/Read.ts +359 -0
- package/src/Relocate.ts +166 -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 +154 -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 +233 -0
- package/src/internal/Exec.ts +314 -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/SearchContract.ts +77 -0
- package/src/internal/Symbols.ts +88 -0
- package/src/internal/TestReport.ts +194 -0
- package/src/internal/Text.ts +170 -0
- package/src/internal/Url.ts +23 -0
- package/src/internal/Walk.ts +176 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Flows and handlers"
|
|
3
|
+
description: "Every tool in this package is a portable declaration plus a separately supplied handler, and the Manifest registries are how a host reaches both halves by name."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
A tool in this package is two halves that ship apart.
|
|
9
|
+
|
|
10
|
+
The **declaration** is data. It carries `name`, `description`, `Input`,
|
|
11
|
+
`Output`, `capabilities`, and `effects`, and it reaches nothing: no filesystem,
|
|
12
|
+
no process, no network. That is what makes it safe to hand to a model, safe to
|
|
13
|
+
put in a registry, and safe to plan against before a single call runs.
|
|
14
|
+
|
|
15
|
+
The **handler** is the executable half. It is an ordinary Effect whose
|
|
16
|
+
requirement names the host services it needs, so the host decides what `read`
|
|
17
|
+
actually reads from.
|
|
18
|
+
|
|
19
|
+
## The module shape
|
|
20
|
+
|
|
21
|
+
Every flow module exports the same names, which is what lets a host treat all 17
|
|
22
|
+
uniformly:
|
|
23
|
+
|
|
24
|
+
| Export | What it is |
|
|
25
|
+
| -------------- | -------------------------------------------------------------- |
|
|
26
|
+
| `name` | The registry name, such as `"read"`. |
|
|
27
|
+
| `description` | The one line the model sees. |
|
|
28
|
+
| `Input` | The input schema. |
|
|
29
|
+
| `Output` | The output schema. |
|
|
30
|
+
| `effects` | The declared effect envelope, before any input is known. |
|
|
31
|
+
| `effectsFor` | The same envelope narrowed to one decoded input. |
|
|
32
|
+
| `capabilities` | The authority the flow requires, as `action:resource` strings. |
|
|
33
|
+
| `flow` | The declaration itself, built by `Flow.make`. |
|
|
34
|
+
| `run` | The handler. |
|
|
35
|
+
|
|
36
|
+
`Explore` is the one exception: it has no `run`, because it is a dynamic flow
|
|
37
|
+
composed from other flows rather than a handler.
|
|
38
|
+
|
|
39
|
+
## Naming a declaration from another flow
|
|
40
|
+
|
|
41
|
+
Because the declaration is data, a larger flow can name it and inherit both its
|
|
42
|
+
capabilities and its effect envelope, without importing the handler at all:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import * as Read from "@smthrs/std/Read"
|
|
46
|
+
import * as Schema from "effect/Schema"
|
|
47
|
+
|
|
48
|
+
/** A step that reads a file. It declares what `read` declares. */
|
|
49
|
+
export const ReadTarget = {
|
|
50
|
+
name: "read-target",
|
|
51
|
+
input: Schema.Struct({ path: Schema.String }),
|
|
52
|
+
output: Read.Output,
|
|
53
|
+
capabilities: Read.capabilities,
|
|
54
|
+
effects: Read.effects,
|
|
55
|
+
flows: [Read.flow]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
A planner reading `ReadTarget` can see that the step reads and does not write,
|
|
60
|
+
before anything runs. That is the same property a review gate or an approval
|
|
61
|
+
prompt needs.
|
|
62
|
+
|
|
63
|
+
## The registries
|
|
64
|
+
|
|
65
|
+
`Manifest` is the whole library keyed by name, so a host binds all of it without
|
|
66
|
+
writing 17 imports:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import * as Manifest from "@smthrs/std/Manifest"
|
|
70
|
+
|
|
71
|
+
Manifest.names // the 17 names, in registry order
|
|
72
|
+
Manifest.flows // name -> declaration, all 17
|
|
73
|
+
Manifest.handlers // name -> handler, the 16 that have one
|
|
74
|
+
Manifest.effectsFor // name -> narrowing function, all 17
|
|
75
|
+
Manifest.readOnly // the 8 names a read-only tool surface may see
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Every registry is frozen. `Manifest.handlers` omits `explore` because a dynamic
|
|
79
|
+
flow has no handler; `Manifest.effectsFor` includes it, because a model can
|
|
80
|
+
still be offered the declaration and its envelope still narrows.
|
|
81
|
+
|
|
82
|
+
`Manifest.readOnly` is `read`, `ls`, `glob`, `grep`, `fetch`, `explore`,
|
|
83
|
+
`webfetch`, and `lsp`. `websearch` is deliberately absent: its provider contract
|
|
84
|
+
requires `net:post` authority, which is mutating under the kernel capability
|
|
85
|
+
taxonomy, so it cannot ride in a read-only tool surface.
|
|
86
|
+
|
|
87
|
+
## The services a host binds
|
|
88
|
+
|
|
89
|
+
Most handlers ask only for platform services such as `FileSystem` or
|
|
90
|
+
`ChildProcessSpawner`. Six ask for a service this package defines, because the
|
|
91
|
+
answer is a host decision rather than a platform one:
|
|
92
|
+
|
|
93
|
+
| Service | The flows that need it | What it decides |
|
|
94
|
+
| ---------------- | ----------------------- | -------------------------------------------------- |
|
|
95
|
+
| `Search` | `grep`, `glob` | Whether searching runs in process or through `rg`. |
|
|
96
|
+
| `Container` | `bash`, `test` | How a command reaches a named container. |
|
|
97
|
+
| `TestRunner` | `test` | How the project under test runs its suite. |
|
|
98
|
+
| `Checkpoints` | agent-side tree pinning | Where a pinned tree is recorded and checked out. |
|
|
99
|
+
| `WebSearch` | `websearch` | Which search provider answers. |
|
|
100
|
+
| `LanguageServer` | `lsp` | Which language server answers. |
|
|
101
|
+
|
|
102
|
+
Each one ships a refusal implementation, and binding it is the honest way to say
|
|
103
|
+
"this host cannot do that". A `makeNoop` service fails the call with
|
|
104
|
+
`provider_unavailable` and a message naming what to do instead. Refusing loudly
|
|
105
|
+
is the contract: a flow that appears to work while doing nothing costs a model
|
|
106
|
+
the frames it takes to notice.
|
|
107
|
+
|
|
108
|
+
## What stays in the success channel
|
|
109
|
+
|
|
110
|
+
A handler fails only when a model must see a failure. A non-zero exit code, an
|
|
111
|
+
empty match set, and an HTTP 500 are all ordinary values, returned in the
|
|
112
|
+
success channel with the fields that describe them. `StdError` carries the rest,
|
|
113
|
+
under a closed list of codes. See
|
|
114
|
+
[Failures](../reference/flows.md#failures) for the list and
|
|
115
|
+
[Troubleshooting](../troubleshooting.md) for what each one means in practice.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Limits are disclosed, never silent"
|
|
3
|
+
description: "Every cap in this package is a display budget the result declares, plus the truncation flags the harness reads to refuse writing a fragment back to a file."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Every limit here is a display budget, not a policy limit. Exceeding one is
|
|
9
|
+
always stated in the result, because a silent cut is how a caller comes to
|
|
10
|
+
believe it has seen a whole file, a whole listing, or a whole match set when it
|
|
11
|
+
has not.
|
|
12
|
+
|
|
13
|
+
Three disclosure shapes cover the library:
|
|
14
|
+
|
|
15
|
+
- `truncated` plus an optional `notice` string, on the paged and HTTP flows.
|
|
16
|
+
The notice reads `Showing 3 of 40 lines; output was truncated.`, or
|
|
17
|
+
`Showing 60000 of 1048576 bytes; output was truncated.` on the HTTP flows.
|
|
18
|
+
- `<stream>Truncated` plus `<stream>DroppedBytes`, on the flows that capture a
|
|
19
|
+
process.
|
|
20
|
+
- A typed refusal, where handing back a fragment would be worse than answering
|
|
21
|
+
nothing. `webfetch` and `fetch` refuse a response past 5 MiB with
|
|
22
|
+
`response_too_large`; `NativeSearch` refuses an `rg` stream past its capture
|
|
23
|
+
bound rather than risk disagreeing with the in-process peer.
|
|
24
|
+
|
|
25
|
+
## The caps
|
|
26
|
+
|
|
27
|
+
These values are fixed in the package and are not exported. They are what the
|
|
28
|
+
handlers apply:
|
|
29
|
+
|
|
30
|
+
| Cap | Value | Applies to |
|
|
31
|
+
| --------------------- | --------------------------- | ---------------------------------------------------------- |
|
|
32
|
+
| Default `read` page | 2,000 lines | one `read` call with no `limit` |
|
|
33
|
+
| Displayed line | 2,000 Unicode scalar values | one line of a `read` page |
|
|
34
|
+
| Entries per page | 1,000 | one `ls` or `glob` page |
|
|
35
|
+
| Matches per call | 200 | one `grep` call |
|
|
36
|
+
| Match line preview | 500 characters | one `grep` match or context line |
|
|
37
|
+
| Rendered text payload | 60,000 bytes | one `read` page, `fetch`/`http-post` body, `webfetch` page |
|
|
38
|
+
| Shell stream capture | 30,000 bytes | each captured `bash` stream |
|
|
39
|
+
| HTTP response body | 5 MiB | `fetch`, `http-post`, and `webfetch`, refused past the cap |
|
|
40
|
+
| Redirects | 10 | one `webfetch` call |
|
|
41
|
+
| Language-server frame | 8 MiB body, 8 KiB header | one JSON-RPC frame |
|
|
42
|
+
|
|
43
|
+
These are exported constants, so a host can read them and a caller can raise or
|
|
44
|
+
lower what it passes:
|
|
45
|
+
|
|
46
|
+
| Constant | Value | Applies to |
|
|
47
|
+
| ----------------------------------------- | ---------- | ----------------------------------------------------------- |
|
|
48
|
+
| `Bash.DEFAULT_TIMEOUT_MS` | 600,000 | one `bash` call with no `timeoutMs` |
|
|
49
|
+
| `TestRun.DEFAULT_TIMEOUT_MS` | 600,000 | one `test` call with no `timeoutMs` |
|
|
50
|
+
| `TestRun.MAX_CAPTURE_BYTES` | 8,000,000 | runner output one `test` call holds in memory |
|
|
51
|
+
| `ShellCommand.DEFAULT_TIMEOUT_MS` | 10,000 | one `shell_command` call with no `timeout_ms` |
|
|
52
|
+
| `ShellCommand.MAX_CAPTURE_BYTES` | 8,000,000 | command output one `shell_command` call holds in memory |
|
|
53
|
+
| `ShellCommand.DEFAULT_MAX_OUTPUT_TOKENS` | 10,000 | the Codex token budget the output is shaped to |
|
|
54
|
+
| `ShellCommand.TIMEOUT_EXIT_CODE` | 124 | the exit code a timed-out `shell_command` reports |
|
|
55
|
+
| `NativeSearch.MAX_CAPTURE_BYTES` | 67,108,864 | one `rg` invocation's captured output, refused past the cap |
|
|
56
|
+
| `NodeLanguageServer.MAX_QUEUED_FRAMES` | 256 | frames buffered for one server's standard input |
|
|
57
|
+
| `NodeLanguageServer.MAX_PENDING_REQUESTS` | 512 | concurrent in-flight requests to one server |
|
|
58
|
+
|
|
59
|
+
## A page ends on a whole line
|
|
60
|
+
|
|
61
|
+
A byte budget cuts mid-line, and a partial line reads like an anchor and is not
|
|
62
|
+
one. So a `read` page truncated by bytes ends at the last whole line it could
|
|
63
|
+
afford, and `endLine` counts only the lines it actually returned. A line clipped
|
|
64
|
+
by the 2,000-character display cap is called out in the notice by name, because
|
|
65
|
+
such a line cannot be used as an `edit` anchor either.
|
|
66
|
+
|
|
67
|
+
## A limit counts matches, not rows
|
|
68
|
+
|
|
69
|
+
`grep` returns match-centric results, which is how `rg --json` groups its own
|
|
70
|
+
output. `limit` counts matches, each match carries the context lines that belong
|
|
71
|
+
to it, and every context line belongs to exactly one match. A budget that
|
|
72
|
+
counted rows could spend itself on context and drop the hit, which is a result
|
|
73
|
+
that shows the lines around a match and not the match.
|
|
74
|
+
|
|
75
|
+
## A listing is ordered before it is paged
|
|
76
|
+
|
|
77
|
+
`ls` describes every entry before it cuts the page, because the order it
|
|
78
|
+
promises is directories first and a kind costs a stat. Ordering inside the page
|
|
79
|
+
instead would make `offset` address a different listing at every page size, so a
|
|
80
|
+
caller paging a large directory could see one entry twice and another never.
|
|
81
|
+
|
|
82
|
+
## Truncation flags are a wire contract
|
|
83
|
+
|
|
84
|
+
`stdoutTruncated`, `stderrTruncated`, and `tailTruncated` are not display
|
|
85
|
+
details. A truncated capture is a fragment of what the process printed, and
|
|
86
|
+
[`@smthrs/harness`](/api/harness) reads these flags to refuse a later write of
|
|
87
|
+
those exact bytes: writing a captured tail over a file replaces the file with
|
|
88
|
+
the end of a log. Read the flag before writing captured output anywhere, and set
|
|
89
|
+
it in your own handler whenever you cut a capture: a consumer that cannot tell a
|
|
90
|
+
fragment from the whole writes the fragment.
|
|
91
|
+
|
|
92
|
+
`stdoutDroppedBytes`, `stderrDroppedBytes`, and `tailDroppedBytes` count what
|
|
93
|
+
the process actually produced beyond the capture. Capture is bounded where the
|
|
94
|
+
stream is read rather than after it is read, so a command that prints gigabytes
|
|
95
|
+
costs the bound instead of the whole of what it printed. `bash` keeps the tail
|
|
96
|
+
of each stream, because a failing command prints its verdict last; `read`,
|
|
97
|
+
`fetch`, and `http-post` keep the head.
|
|
98
|
+
|
|
99
|
+
Every caller-supplied command (`bash`, `test`, `shell_command`) passes a capture
|
|
100
|
+
bound. The internal `git` plumbing behind `Checkpoints` and `TestRun`'s baseline
|
|
101
|
+
does not, because a listing read for its content is useless with its head
|
|
102
|
+
missing.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "The search contract"
|
|
3
|
+
description: "Smithers Ripgrep Subset v1: what grep and glob support, how patterns and globs are read relative to the search root, and how two peer implementations are held to one answer."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`grep` and `glob` are two projections of one contract, Smithers Ripgrep Subset
|
|
9
|
+
v1. The contract exists because the package ships two implementations of it, and
|
|
10
|
+
a caller must not be able to tell which one answered.
|
|
11
|
+
|
|
12
|
+
- `PortableSearch` walks the injected `FileSystem` in process. It needs no
|
|
13
|
+
external binary, so it is the peer a browser host and a test host use.
|
|
14
|
+
- `NativeSearch` drives the `rg` executable through the permission-aware
|
|
15
|
+
spawner.
|
|
16
|
+
|
|
17
|
+
Both are bound to the `Search` service, and `Grep.run` and `Glob.run` call
|
|
18
|
+
whichever one the host provided. Neither module knows which peer is in play.
|
|
19
|
+
|
|
20
|
+
## What v1 supports
|
|
21
|
+
|
|
22
|
+
`grep` corresponds to a bounded subset of ripgrep's flags:
|
|
23
|
+
|
|
24
|
+
| Input field | Ripgrep flag |
|
|
25
|
+
| ------------------------------------------ | ----------------------------------------- |
|
|
26
|
+
| `fixedStrings` | `-F` |
|
|
27
|
+
| `ignoreCase` | `-i` |
|
|
28
|
+
| `smartCase` | `-S` |
|
|
29
|
+
| `globs` | ordered `-g` include and exclude patterns |
|
|
30
|
+
| `beforeContext`, `afterContext`, `context` | `-B`, `-A`, `-C` |
|
|
31
|
+
| `maxCount` | `--max-count`, per file |
|
|
32
|
+
| `filesWithMatches` | `--files-with-matches` |
|
|
33
|
+
| `hidden` | `--hidden` |
|
|
34
|
+
| `noIgnore` | `--no-ignore` |
|
|
35
|
+
| `limit` | the global result budget, capped at 200 |
|
|
36
|
+
|
|
37
|
+
`glob` corresponds to `rg --files -g <pattern>`.
|
|
38
|
+
|
|
39
|
+
`noIgnore` is an optional boolean defaulting to `false`. Both flows apply
|
|
40
|
+
`.gitignore` rules from the search root and nested directories, even outside
|
|
41
|
+
Git repositories. Set `noIgnore: true` to include ignored paths. Parent and
|
|
42
|
+
global ignore rules, `.ignore`, `.rgignore`, and `.git/info/exclude` do not
|
|
43
|
+
participate. Hidden-file and fixed directory skips still apply.
|
|
44
|
+
|
|
45
|
+
File-type registries are not supported, so there is no `types` field to pass.
|
|
46
|
+
`-i` and `-S` together, and `-C` combined with `-A` or `-B`, are `invalid_input`,
|
|
47
|
+
because ripgrep's own precedence for those combinations is not a thing two peers
|
|
48
|
+
should each guess at.
|
|
49
|
+
|
|
50
|
+
## The pattern grammar
|
|
51
|
+
|
|
52
|
+
Smithers Ripgrep ASCII v1 is deliberately the intersection of Rust's regex crate
|
|
53
|
+
and JavaScript's `RegExp`, so both peers compile the same pattern to the same
|
|
54
|
+
meaning. A pattern is rejected with `invalid_pattern` when it:
|
|
55
|
+
|
|
56
|
+
- contains anything outside printable ASCII, or exceeds 4,096 bytes;
|
|
57
|
+
- opens a special group with `(?`, which covers lookaround and named groups;
|
|
58
|
+
- escapes an alphanumeric, which covers backreferences, shorthand classes such
|
|
59
|
+
as `\d`, and encoded escapes;
|
|
60
|
+
- nests a character class, leaves one empty, or uses a class set operation
|
|
61
|
+
(`&&`, `--`, `~~`);
|
|
62
|
+
- names a counted repetition above 1,000;
|
|
63
|
+
- exceeds 128 nested groups or 8,192 compiled states after repetition expansion;
|
|
64
|
+
- fails to compile as a JavaScript regular expression.
|
|
65
|
+
|
|
66
|
+
`fixedStrings: true` skips the grammar entirely except for the ASCII and length
|
|
67
|
+
checks, because a literal is escaped rather than compiled.
|
|
68
|
+
|
|
69
|
+
Inside the shared compiler, `.` matches any character except a newline and `$`
|
|
70
|
+
anchors at the end of the whole input, which is what makes a line-oriented
|
|
71
|
+
search behave the same in both peers.
|
|
72
|
+
|
|
73
|
+
Portable grep evaluates this grammar with a Thompson state machine. Matching
|
|
74
|
+
work is linear in line length times the bounded state count, including nested
|
|
75
|
+
quantifiers and ambiguous alternatives. It yields every 4,096 state visits so
|
|
76
|
+
host timers and Effect interruption can run during a long match. JavaScript
|
|
77
|
+
regular expressions are used only for individual character predicates.
|
|
78
|
+
|
|
79
|
+
The portable scan reads files in chunks and counts overflow without retaining
|
|
80
|
+
all hits. It keeps the first `limit` hits and their context, plus one boundary
|
|
81
|
+
hit to preserve context ownership at truncation. Symbol source is loaded only
|
|
82
|
+
for files with returned hits and released after annotating each file. Memory
|
|
83
|
+
still includes the current line and, with `symbols: true`, one retained hit's
|
|
84
|
+
source file; `limit` is a result budget, not a byte limit on that source.
|
|
85
|
+
|
|
86
|
+
## Globs are relative to the root, never absolute
|
|
87
|
+
|
|
88
|
+
This is the rule that most often surprises a caller, and getting it wrong is
|
|
89
|
+
silent: an absolute pattern matches nothing at all, forever.
|
|
90
|
+
|
|
91
|
+
A candidate is matched by the path it has **relative to the search root**. Three
|
|
92
|
+
consequences, and both peers implement all three identically:
|
|
93
|
+
|
|
94
|
+
- A pattern with no `/` matches the **basename** at any depth. `*.py` finds
|
|
95
|
+
every Python file in the subtree.
|
|
96
|
+
- A pattern containing `/` is matched against the root-relative path and is
|
|
97
|
+
anchored at the root. `tests/*.py` matches `<root>/tests/a.py` and not
|
|
98
|
+
`<root>/src/tests/a.py`.
|
|
99
|
+
- A leading `/` is that same anchor spelled explicitly, not a filesystem
|
|
100
|
+
absolute path. `/a.py` matches only `<root>/a.py`, where bare `a.py` would
|
|
101
|
+
match any `a.py` in the subtree. A leading `./` means the same anchor.
|
|
102
|
+
|
|
103
|
+
`**` crosses directory boundaries; `*` and `?` stay inside one segment; `?`
|
|
104
|
+
consumes one UTF-8 byte. Brace alternatives expand, up to 256 patterns. Glob
|
|
105
|
+
escapes and character classes are not supported. Trailing spaces are not part of
|
|
106
|
+
a pattern, because `rg` reads `-g` by gitignore's rules and drops them, and a
|
|
107
|
+
pattern left blank by that is rejected rather than read as no filter at all.
|
|
108
|
+
|
|
109
|
+
Ordered include and exclude globs work like ripgrep's: with no positive glob
|
|
110
|
+
everything is included, and the last pattern to match a candidate decides, with
|
|
111
|
+
`!` marking an exclusion.
|
|
112
|
+
|
|
113
|
+
So `/home/repo/tests/**` passed against a root of `/home/repo` is read as the
|
|
114
|
+
root-relative path `home/repo/tests/**`, which nothing under that root can
|
|
115
|
+
match. That answer is never silent: a positive glob no file under the root could
|
|
116
|
+
match is explained through `notice`, naming the reason (a missing directory, a
|
|
117
|
+
skipped directory, a hidden path with `hidden` left false) and, where it applies,
|
|
118
|
+
the root-relative pattern the caller probably meant.
|
|
119
|
+
|
|
120
|
+
A `root` that names one file is that file. It is reported whatever the pattern
|
|
121
|
+
says, because `rg` searches a path given on its command line without consulting
|
|
122
|
+
`-g`.
|
|
123
|
+
|
|
124
|
+
## What a walk skips
|
|
125
|
+
|
|
126
|
+
Repository internals, dependency trees, caches, and worktrees are never
|
|
127
|
+
descended into. This includes `.artifacts`, `.backend-go-modcache`,
|
|
128
|
+
`.pnpm-store`, `.worktrees`, and `worktrees`. Skipping applies to descent and
|
|
129
|
+
never to what the caller named, so naming one of them as the `root` still
|
|
130
|
+
searches it.
|
|
131
|
+
|
|
132
|
+
A walk also skips what it cannot read: a dangling symlink, a link cycle, a
|
|
133
|
+
directory the process may not list. One unreadable entry never fails the call,
|
|
134
|
+
which is what `rg --no-messages` does with the same tree. Only the root the
|
|
135
|
+
caller named can fail the walk.
|
|
136
|
+
|
|
137
|
+
Files with a NUL byte are skipped and counted in `skippedBinary`. Invalid UTF-8
|
|
138
|
+
in a searched file is replacement-decoded rather than refused.
|
|
139
|
+
|
|
140
|
+
## Two properties that belong to the contract, not to a peer
|
|
141
|
+
|
|
142
|
+
Both are computed in shared code, so neither peer can drift on them:
|
|
143
|
+
|
|
144
|
+
- **Each hit carries its enclosing definition.** A line number is not a read
|
|
145
|
+
window. When a file's shape says plainly which definition a hit sits in, the
|
|
146
|
+
match carries `symbol` with that definition's `kind`, `name`, `startLine`, and
|
|
147
|
+
`endLine`, so the follow-up `read` is a fact rather than a guess. The
|
|
148
|
+
heuristic answers nothing rather than guessing when the shape is not plain.
|
|
149
|
+
- **A metacharacter pattern that finds nothing is retried literally.** If a
|
|
150
|
+
pattern containing regex metacharacters produces no matches and no files, the
|
|
151
|
+
search runs again with `fixedStrings: true`. When that finds something, the
|
|
152
|
+
result carries `retriedAsLiteral: true` and says so in `notice`. A search that
|
|
153
|
+
found nothing because the caller wrote a literal containing `(` is the most
|
|
154
|
+
common way a search lies.
|
|
155
|
+
|
|
156
|
+
## Proving a third peer
|
|
157
|
+
|
|
158
|
+
`Search` is a public seam: a host may bind its own implementation. Two modules
|
|
159
|
+
exist so that a new peer can be held to the same contract as the shipped ones.
|
|
160
|
+
|
|
161
|
+
`SearchContract` exports the matcher both peers build on, so a third peer reuses
|
|
162
|
+
the meaning of a pattern instead of reimplementing it:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import * as SearchContract from "@smthrs/std/SearchContract"
|
|
166
|
+
|
|
167
|
+
SearchContract.validatePattern("foo.*bar", false) // undefined, or a StdError
|
|
168
|
+
SearchContract.validateGlob("src/**/*.ts") // undefined, or a StdError
|
|
169
|
+
SearchContract.canonicalGlob("./src/**/*.ts ") // "/src/**/*.ts"
|
|
170
|
+
SearchContract.matchesGlob("*.ts", "src/widen.ts", "widen.ts") // true
|
|
171
|
+
SearchContract.includedByGlobs(["**/*.ts", "!**/*.d.ts"], "src/a.d.ts", "a.d.ts") // false
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`SearchConformance` is the differential kit: it generates a tree and a batch of
|
|
175
|
+
calls from a seed, runs them through two implementations, and reports every
|
|
176
|
+
answer that differs. It knows nothing about which peer is right; a divergence is
|
|
177
|
+
the finding. It found two real drifts between the peers shipped here, one in how
|
|
178
|
+
`maxCount` interacts with context lines and one in how `ignoreCase` and
|
|
179
|
+
`smartCase` combine.
|
|
180
|
+
|
|
181
|
+
The walkthrough is
|
|
182
|
+
[Implement your own search peer](../guides/implement-a-search-peer.md).
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Bind the standard flows into a host"
|
|
3
|
+
description: "Compose the platform and service layers the handlers require, offer the declarations to a model, and use the read-only projection for a restricted tool surface."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
A host does two things with this package: it offers declarations to a model, and
|
|
9
|
+
it runs the matching handlers when a call arrives. This guide covers the
|
|
10
|
+
composition both halves need.
|
|
11
|
+
|
|
12
|
+
## Compose the host layer
|
|
13
|
+
|
|
14
|
+
Start with a platform layer, then add one layer per service a flow needs:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { NodeServices } from "@effect/platform-node"
|
|
18
|
+
import * as Container from "@smthrs/std/Container"
|
|
19
|
+
import * as NativeSearch from "@smthrs/std/NativeSearch"
|
|
20
|
+
import * as TestRunner from "@smthrs/std/TestRunner"
|
|
21
|
+
import * as Layer from "effect/Layer"
|
|
22
|
+
|
|
23
|
+
/** FileSystem, Path, and ChildProcessSpawner. */
|
|
24
|
+
const platform = NodeServices.layer
|
|
25
|
+
|
|
26
|
+
const host = Layer.mergeAll(
|
|
27
|
+
platform,
|
|
28
|
+
// grep and glob, through the rg executable.
|
|
29
|
+
NativeSearch.layer.pipe(Layer.provide(platform)),
|
|
30
|
+
// bash and test, when a call names a container.
|
|
31
|
+
Container.layerCommand({ program: "docker" }),
|
|
32
|
+
// test: how the project under test runs its suite.
|
|
33
|
+
TestRunner.layer({ command: "pnpm vitest run", cwd: "/workspace" })
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Swap `NativeSearch.layer` for `PortableSearch.layer` to search in process with
|
|
38
|
+
no external binary. Both satisfy the same `Search` service, and nothing above
|
|
39
|
+
the layer changes.
|
|
40
|
+
|
|
41
|
+
A host that cannot serve a service binds its refusal layer instead of leaving it
|
|
42
|
+
out, so the failure names the missing service rather than a missing context:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import * as Checkpoints from "@smthrs/std/Checkpoints"
|
|
46
|
+
import * as LanguageServer from "@smthrs/std/LanguageServer"
|
|
47
|
+
import * as WebSearch from "@smthrs/std/WebSearch"
|
|
48
|
+
|
|
49
|
+
const unavailable = Layer.mergeAll(
|
|
50
|
+
WebSearch.layerNoop, // websearch fails with provider_unavailable
|
|
51
|
+
LanguageServer.layerNoop, // lsp fails with unsupported
|
|
52
|
+
Checkpoints.layerNoop // pinning fails with provider_unavailable
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Run one handler
|
|
57
|
+
|
|
58
|
+
A handler is an ordinary Effect. Provide the composed host and run it:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import * as Grep from "@smthrs/std/Grep"
|
|
62
|
+
import * as Effect from "effect/Effect"
|
|
63
|
+
|
|
64
|
+
const hits = Effect.provide(
|
|
65
|
+
Grep.run({ pattern: "TODO", root: "/workspace", globs: ["*.ts"] }),
|
|
66
|
+
host
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Offer the declarations
|
|
71
|
+
|
|
72
|
+
`Manifest.flows` is the declaration registry, keyed by the same names a model
|
|
73
|
+
calls. Offering all 17 is one expression:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import * as Manifest from "@smthrs/std/Manifest"
|
|
77
|
+
|
|
78
|
+
const offered = Manifest.names.map((name) => Manifest.flows[name])
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For a tool surface that must not change anything, use the read-only projection
|
|
82
|
+
instead of filtering by hand:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const readOnly = Manifest.readOnly.map((name) => Manifest.flows[name])
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`Manifest.readOnly` is `read`, `ls`, `glob`, `grep`, `fetch`, `explore`,
|
|
89
|
+
`webfetch`, and `lsp`. `websearch` is not in it: its provider contract requires
|
|
90
|
+
`net:post` authority, which is mutating under the kernel capability taxonomy.
|
|
91
|
+
|
|
92
|
+
## Narrow the envelope for one call
|
|
93
|
+
|
|
94
|
+
When a call arrives, narrow its declared envelope to what that input actually
|
|
95
|
+
touches before scheduling it. `Manifest.effectsFor` reaches the narrowing by
|
|
96
|
+
name:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const narrowed = Manifest.effectsFor["read"]({ path: "/workspace/notes.md" })
|
|
100
|
+
// reads: ["/workspace/notes.md"], instead of the declared ["/**"]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Without this, two reads of two different files serialize against each other. See
|
|
104
|
+
[Effects and capabilities](../concepts/effects-and-capabilities.md).
|
|
105
|
+
|
|
106
|
+
## The production path
|
|
107
|
+
|
|
108
|
+
[`@smthrs/agent`](/api/agent) already does all of this. Its `StandardFlows`
|
|
109
|
+
module pairs each declaration with its handler through
|
|
110
|
+
[`@smthrs/harness`](/api/harness)'s `FlowBinding` contract, and groups them by
|
|
111
|
+
the slice of host services they need: `filesystem` binds `read`, `write`,
|
|
112
|
+
`edit`, `apply_patch`, `ls`, `glob`, and `grep`; `shell` binds `bash`; `tests`
|
|
113
|
+
binds `test`. If you are building an agent rather than a tool host, start there:
|
|
114
|
+
[Give a run capabilities](/pkg/agent/guides/capabilities).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Implement your own search peer"
|
|
3
|
+
description: "Bind a third implementation of the Search service using the shared matcher, then prove it agrees with a reference peer using the differential conformance kit."
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 9
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`Search` is a public extension seam. A host binds its own implementation and
|
|
9
|
+
every `grep` and `glob` call in the package goes through it, so an index server,
|
|
10
|
+
a remote service, or a virtual filesystem can back the search flows. This guide
|
|
11
|
+
is about filling that seam without drifting from what a pattern means.
|
|
12
|
+
|
|
13
|
+
## The interface
|
|
14
|
+
|
|
15
|
+
Two methods, both taking normalized input:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import * as Search from "@smthrs/std/Search"
|
|
19
|
+
import * as Effect from "effect/Effect"
|
|
20
|
+
import * as Layer from "effect/Layer"
|
|
21
|
+
|
|
22
|
+
const peer = Search.make({
|
|
23
|
+
grep: (input) =>
|
|
24
|
+
Effect.succeed({
|
|
25
|
+
matches: [],
|
|
26
|
+
files: [],
|
|
27
|
+
filesSearched: 0,
|
|
28
|
+
skippedBinary: 0,
|
|
29
|
+
truncated: false
|
|
30
|
+
}),
|
|
31
|
+
glob: (input) => Effect.succeed({ paths: [], total: 0, truncated: false })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const layer = Layer.succeed(Search.Search, peer)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`Grep.run` and `Glob.run` do the validation and defaulting before they call you,
|
|
38
|
+
so `GrepInput` and `GlobInput` arrive complete: `root` is resolved, `globs` is an
|
|
39
|
+
array, the context fields are numbers, and `limit` is already capped. Your
|
|
40
|
+
implementation never sees an undefined option.
|
|
41
|
+
|
|
42
|
+
The error channel is `StdError`, and the codes a peer produces are `not_found`
|
|
43
|
+
for a missing root, `invalid_pattern` for a pattern it cannot compile, and
|
|
44
|
+
`command_failed` for a host failure of its own.
|
|
45
|
+
|
|
46
|
+
## Reuse the shared matcher
|
|
47
|
+
|
|
48
|
+
Do not reimplement pattern or glob semantics. `SearchContract` exports exactly
|
|
49
|
+
the functions both shipped peers build on:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import * as SearchContract from "@smthrs/std/SearchContract"
|
|
53
|
+
|
|
54
|
+
SearchContract.validatePattern(pattern, fixedStrings) // StdError | undefined
|
|
55
|
+
SearchContract.validateGlob(glob) // StdError | undefined
|
|
56
|
+
SearchContract.canonicalGlob("./src/**/*.ts ") // "/src/**/*.ts"
|
|
57
|
+
SearchContract.expression(pattern, fixedStrings, insensitive) // a RegExp
|
|
58
|
+
SearchContract.matchesGlob("*.ts", "src/widen.ts", "widen.ts") // true
|
|
59
|
+
SearchContract.includedByGlobs(globs, relative, basename) // ordered include and exclude
|
|
60
|
+
SearchContract.unsatisfiableNotice({ fileSystem, path, root, globs, hidden })
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`matchesGlob` and `includedByGlobs` take a candidate's path **relative to the
|
|
64
|
+
root** and its basename, which is the whole of the root-relative rule described
|
|
65
|
+
in [The search contract](../concepts/search-contract.md).
|
|
66
|
+
|
|
67
|
+
`unsatisfiableNotice` is what keeps an empty answer honest: attach its result to
|
|
68
|
+
`notice` when your peer produced no entries, so "the tree holds no match" and
|
|
69
|
+
"this pattern can never match" stay distinguishable.
|
|
70
|
+
|
|
71
|
+
## Prove it agrees
|
|
72
|
+
|
|
73
|
+
`SearchConformance` generates a tree and a batch of calls from a seed, runs them
|
|
74
|
+
through two implementations, and reports every answer that differs. It knows
|
|
75
|
+
nothing about which peer is right: a divergence is the finding.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { NodeServices } from "@effect/platform-node"
|
|
79
|
+
import type * as KernelPath from "@smthrs/kernel/Path"
|
|
80
|
+
import * as PortableSearch from "@smthrs/std/PortableSearch"
|
|
81
|
+
import type * as Search from "@smthrs/std/Search"
|
|
82
|
+
import * as SearchConformance from "@smthrs/std/SearchConformance"
|
|
83
|
+
import * as Effect from "effect/Effect"
|
|
84
|
+
import type * as FileSystem from "effect/FileSystem"
|
|
85
|
+
|
|
86
|
+
const check = (subject: Search.Search) =>
|
|
87
|
+
Effect.gen(function*() {
|
|
88
|
+
const plan = SearchConformance.plan({
|
|
89
|
+
seed: 1234,
|
|
90
|
+
root: "/tmp/conformance",
|
|
91
|
+
files: 24,
|
|
92
|
+
calls: 40
|
|
93
|
+
})
|
|
94
|
+
yield* SearchConformance.materialize(plan)
|
|
95
|
+
|
|
96
|
+
const services = yield* Effect.context<FileSystem.FileSystem | KernelPath.Path>()
|
|
97
|
+
const divergences = yield* SearchConformance.compare({
|
|
98
|
+
plan,
|
|
99
|
+
subject,
|
|
100
|
+
reference: PortableSearch.make(services)
|
|
101
|
+
})
|
|
102
|
+
return SearchConformance.report(divergences)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const report = await Effect.runPromise(Effect.provide(check(peer), NodeServices.layer))
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| Export | What it does |
|
|
109
|
+
| ------------- | --------------------------------------------------------------------- |
|
|
110
|
+
| `plan` | Builds a reproducible tree and call batch from a seed. |
|
|
111
|
+
| `materialize` | Writes that plan's tree under its root. |
|
|
112
|
+
| `compare` | Runs every call through both peers and returns the `Divergence` list. |
|
|
113
|
+
| `report` | Renders divergences as the text a failing run should print. |
|
|
114
|
+
|
|
115
|
+
The same seed and root always produce the same plan, so a divergence a run
|
|
116
|
+
reports replays exactly by rerunning that seed. A failure is compared like any
|
|
117
|
+
other answer: two peers that refuse the same call with the same code agree, and
|
|
118
|
+
one that refuses where the other answers has diverged.
|
|
119
|
+
|
|
120
|
+
`PortableSearch` is the obvious reference, because it needs no external binary.
|
|
121
|
+
|
|
122
|
+
## What the generator will not tell you
|
|
123
|
+
|
|
124
|
+
The generator deliberately stays inside the ground both peers claim to share: no
|
|
125
|
+
symlinks, no unreadable directories, no CRLF, no NUL bytes, no filename a shell
|
|
126
|
+
would have to quote. Those cases have an intended behavior rather than merely an
|
|
127
|
+
agreed one, and a generator can only say that two peers disagree, never which is
|
|
128
|
+
right. Pin them with hand-written cases alongside the conformance run.
|
|
129
|
+
|
|
130
|
+
The kit earns its place on the cases nobody thought to write down. A literal `?`
|
|
131
|
+
matched `fo` in one shipped peer and `foo?` in the other for as long as nobody
|
|
132
|
+
wrote that case; the generator found it, along with a `maxCount` interaction with
|
|
133
|
+
context lines and a disagreement between `ignoreCase` and `smartCase`.
|