@@ -16,7 +16,7 @@ import * as Schema from "effect/Schema";
1616import * as Sink from "effect/Sink" ;
1717import * as Stream from "effect/Stream" ;
1818import { HttpClient , HttpClientResponse } from "effect/unstable/http" ;
19- import { ChildProcessSpawner } from "effect/unstable/process" ;
19+ import { ChildProcess , ChildProcessSpawner } from "effect/unstable/process" ;
2020
2121import { ProviderRegistry , type ProviderRegistryShape } from "./Services/ProviderRegistry.ts" ;
2222import * as ProviderMaintenanceRunner from "./providerMaintenanceRunner.ts" ;
@@ -125,6 +125,7 @@ function mockSpawnerLayer(
125125 handler : (
126126 command : string ,
127127 args : ReadonlyArray < string > ,
128+ options : ChildProcess . CommandOptions ,
128129 ) => {
129130 readonly stdout ?: string ;
130131 readonly stderr ?: string ;
@@ -138,9 +139,32 @@ function mockSpawnerLayer(
138139 const childProcess = command as unknown as {
139140 readonly command : string ;
140141 readonly args : ReadonlyArray < string > ;
142+ readonly options : ChildProcess . CommandOptions ;
141143 } ;
142- return Effect . succeed ( mockHandle ( handler ( childProcess . command , childProcess . args ) ) ) ;
144+ return Effect . succeed (
145+ mockHandle ( handler ( childProcess . command , childProcess . args , childProcess . options ) ) ,
146+ ) ;
147+ } ) ,
148+ ) ;
149+ }
150+
151+ function withProcessPlatform < A , E , R > (
152+ platform : NodeJS . Platform ,
153+ effect : Effect . Effect < A , E , R > ,
154+ ) : Effect . Effect < A , E , R > {
155+ return Effect . acquireUseRelease (
156+ Effect . sync ( ( ) => {
157+ const descriptor = Object . getOwnPropertyDescriptor ( process , "platform" ) ;
158+ Object . defineProperty ( process , "platform" , { value : platform } ) ;
159+ return descriptor ;
143160 } ) ,
161+ ( ) => effect ,
162+ ( descriptor ) =>
163+ Effect . sync ( ( ) => {
164+ if ( descriptor ) {
165+ Object . defineProperty ( process , "platform" , descriptor ) ;
166+ }
167+ } ) ,
144168 ) ;
145169}
146170
@@ -319,6 +343,42 @@ describe("providerMaintenanceRunner", () => {
319343 } ,
320344 ) ;
321345
346+ it . effect ( "runs provider update commands through a shell on Windows" , ( ) => {
347+ const calls : Array < {
348+ command : string ;
349+ args : ReadonlyArray < string > ;
350+ shell : ChildProcess . CommandOptions [ "shell" ] ;
351+ } > = [ ] ;
352+ return withProcessPlatform (
353+ "win32" ,
354+ Effect . gen ( function * ( ) {
355+ const { registry } = yield * makeRegistry ( baseProvider ) ;
356+ const runner = yield * makeTestRunner ( registry ) ;
357+
358+ const result = yield * runner . updateProvider ( CODEX_DRIVER ) ;
359+
360+ assert . deepStrictEqual ( calls , [
361+ {
362+ command : "npm" ,
363+ args : [ "install" , "-g" , "@openai/codex@latest" ] ,
364+ shell : true ,
365+ } ,
366+ ] ) ;
367+ assert . strictEqual ( result . providers [ 0 ] ?. updateState ?. status , "succeeded" ) ;
368+ } ) ,
369+ ) . pipe (
370+ Effect . provide (
371+ Layer . mergeAll (
372+ latestVersionHttpClient ( "0.0.0" ) ,
373+ mockSpawnerLayer ( ( command , args , options ) => {
374+ calls . push ( { command, args, shell : options . shell } ) ;
375+ return { stdout : "updated" } ;
376+ } ) ,
377+ ) ,
378+ ) ,
379+ ) ;
380+ } ) ;
381+
322382 it . effect ( "updates a single provider instance without touching sibling instances" , ( ) => {
323383 const calls : Array < { command : string ; args : ReadonlyArray < string > } > = [ ] ;
324384 return Effect . gen ( function * ( ) {
0 commit comments