@@ -47,6 +47,7 @@ type fetchBuildMsg *stainless.Build
4747type fetchDiagnosticsMsg []stainless.BuildDiagnostic
4848type errorMsg error
4949type downloadMsg stainless.Target
50+ type fileChangeMsg struct {}
5051
5152func NewBuildModel (cc * apiCommandContext , ctx context.Context , branch string , fn func () (* stainless.Build , error )) BuildModel {
5253 return BuildModel {
@@ -160,6 +161,10 @@ func (m BuildModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
160161 case errorMsg :
161162 m .err = msg
162163 cmds = append (cmds , tea .Quit )
164+
165+ case fileChangeMsg :
166+ // File change detected, exit with success
167+ cmds = append (cmds , tea .Quit )
163168 }
164169 return m , tea .Sequence (cmds ... )
165170}
@@ -367,6 +372,9 @@ func runPreview(ctx context.Context, cmd *cli.Command) error {
367372 if hasBlockingDiagnostic (diagnostics ) {
368373 fmt .Println ("\n Diagnostic checks will re-run once you edit your configuration files..." )
369374 if err := waitTillConfigChanges (ctx , cmd , cc ); err != nil {
375+ if errors .Is (err , ErrUserCancelled ) {
376+ return nil
377+ }
370378 return err
371379 }
372380 continue
@@ -400,32 +408,46 @@ func waitTillConfigChanges(ctx context.Context, cmd *cli.Command, cc *apiCommand
400408 stainlessConfigPath = cmd .String ("stainless-config" )
401409 }
402410
403- files := []string {openapiSpecPath , stainlessConfigPath }
404- lastModified := make (map [string ]time.Time )
405- for _ , file := range files {
406- if stat , err := os .Stat (file ); err == nil {
407- lastModified [file ] = stat .ModTime ()
408- }
411+ // Get initial file modification times
412+ openapiSpecInfo , err := os .Stat (openapiSpecPath )
413+ if err != nil {
414+ return fmt .Errorf ("failed to get file info for %s: %v" , openapiSpecPath , err )
415+ }
416+ openapiSpecModTime := openapiSpecInfo .ModTime ()
417+
418+ stainlessConfigInfo , err := os .Stat (stainlessConfigPath )
419+ if err != nil {
420+ return fmt .Errorf ("failed to get file info for %s: %v" , stainlessConfigPath , err )
409421 }
422+ stainlessConfigModTime := stainlessConfigInfo .ModTime ()
423+
424+ fmt .Println ("Waiting for file changes..." )
425+
426+ // Poll for file changes every 250ms
427+ ticker := time .NewTicker (250 * time .Millisecond )
428+ defer ticker .Stop ()
410429
411430 for {
412- time .Sleep (500 * time .Millisecond )
431+ select {
432+ case <- ticker .C :
433+ // Check OpenAPI spec file
434+ if info , err := os .Stat (openapiSpecPath ); err == nil {
435+ if info .ModTime ().After (openapiSpecModTime ) {
436+ return nil
437+ }
438+ }
413439
414- for _ , file := range files {
415- if stat , err := os .Stat (file ); err == nil {
416- if stat .ModTime ().After (lastModified [ file ] ) {
440+ // Check Stainless config file
441+ if info , err := os .Stat (stainlessConfigPath ); err == nil {
442+ if info .ModTime ().After (stainlessConfigModTime ) {
417443 return nil
418444 }
419445 }
420- }
421- // Check for cancellation
422- select {
446+
423447 case <- ctx .Done ():
424448 return ctx .Err ()
425- default :
426449 }
427450 }
428- return nil
429451}
430452
431453func runDevBuild (ctx context.Context , cc * apiCommandContext , cmd * cli.Command , branch string , languages []stainless.Target ) error {
@@ -496,6 +518,15 @@ func getCurrentGitBranch() (string, error) {
496518 return branch , nil
497519}
498520
521+ type GenerateSpecParams struct {
522+ Project string `json:"project"`
523+ Source struct {
524+ Type string `json:"type"`
525+ OpenAPISpec string `json:"openapi_spec"`
526+ StainlessConfig string `json:"stainless_config"`
527+ } `json:"source"`
528+ }
529+
499530func getDiagnostics (ctx context.Context , cmd * cli.Command , cc * apiCommandContext ) ([]stainless.BuildDiagnostic , error ) {
500531 var specParams GenerateSpecParams
501532 if cmd .IsSet ("project" ) {
0 commit comments