@@ -7,6 +7,8 @@ import { NamedError } from "@opencode-ai/util/error"
77import { lazy } from "../util/lazy"
88import { $ } from "bun"
99import { Filesystem } from "../util/filesystem"
10+ import { Process } from "../util/process"
11+ import { text } from "node:stream/consumers"
1012
1113import { ZipReader , BlobReader , BlobWriter } from "@zip.js/zip.js"
1214import { Log } from "@/util/log"
@@ -153,17 +155,19 @@ export namespace Ripgrep {
153155 if ( platformKey . endsWith ( "-darwin" ) ) args . push ( "--include=*/rg" )
154156 if ( platformKey . endsWith ( "-linux" ) ) args . push ( "--wildcards" , "*/rg" )
155157
156- const proc = Bun . spawn ( args , {
158+ const proc = Process . spawn ( args , {
157159 cwd : Global . Path . bin ,
158160 stderr : "pipe" ,
159161 stdout : "pipe" ,
160162 } )
161- await proc . exited
162- if ( proc . exitCode !== 0 )
163+ const exit = await proc . exited
164+ if ( exit !== 0 ) {
165+ const stderr = proc . stderr ? await text ( proc . stderr ) : ""
163166 throw new ExtractionFailedError ( {
164167 filepath,
165- stderr : await Bun . readableStreamToText ( proc . stderr ) ,
168+ stderr,
166169 } )
170+ }
167171 }
168172 if ( config . extension === "zip" ) {
169173 const zipFileReader = new ZipReader ( new BlobReader ( new Blob ( [ arrayBuffer ] ) ) )
@@ -227,8 +231,7 @@ export namespace Ripgrep {
227231 }
228232 }
229233
230- // Bun.spawn should throw this, but it incorrectly reports that the executable does not exist.
231- // See https://github.com/oven-sh/bun/issues/24012
234+ // Guard against invalid cwd to provide a consistent ENOENT error.
232235 if ( ! ( await fs . stat ( input . cwd ) . catch ( ( ) => undefined ) ) ?. isDirectory ( ) ) {
233236 throw Object . assign ( new Error ( `No such file or directory: '${ input . cwd } '` ) , {
234237 code : "ENOENT" ,
@@ -237,41 +240,35 @@ export namespace Ripgrep {
237240 } )
238241 }
239242
240- const proc = Bun . spawn ( args , {
243+ const proc = Process . spawn ( args , {
241244 cwd : input . cwd ,
242245 stdout : "pipe" ,
243246 stderr : "ignore" ,
244- maxBuffer : 1024 * 1024 * 20 ,
245- signal : input . signal ,
247+ abort : input . signal ,
246248 } )
247249
248- const reader = proc . stdout . getReader ( )
249- const decoder = new TextDecoder ( )
250- let buffer = ""
251-
252- try {
253- while ( true ) {
254- input . signal ?. throwIfAborted ( )
250+ if ( ! proc . stdout ) {
251+ throw new Error ( "Process output not available" )
252+ }
255253
256- const { done, value } = await reader . read ( )
257- if ( done ) break
254+ let buffer = ""
255+ const stream = proc . stdout as AsyncIterable < Buffer | string >
256+ for await ( const chunk of stream ) {
257+ input . signal ?. throwIfAborted ( )
258258
259- buffer += decoder . decode ( value , { stream : true } )
260- // Handle both Unix (\n) and Windows (\r\n) line endings
261- const lines = buffer . split ( / \r ? \n / )
262- buffer = lines . pop ( ) || ""
259+ buffer += typeof chunk === "string" ? chunk : chunk . toString ( )
260+ // Handle both Unix (\n) and Windows (\r\n) line endings
261+ const lines = buffer . split ( / \r ? \n / )
262+ buffer = lines . pop ( ) || ""
263263
264- for ( const line of lines ) {
265- if ( line ) yield line
266- }
264+ for ( const line of lines ) {
265+ if ( line ) yield line
267266 }
268-
269- if ( buffer ) yield buffer
270- } finally {
271- reader . releaseLock ( )
272- await proc . exited
273267 }
274268
269+ if ( buffer ) yield buffer
270+ await proc . exited
271+
275272 input . signal ?. throwIfAborted ( )
276273 }
277274
0 commit comments