@@ -385,24 +385,33 @@ export const CREDENTIAL_PROVIDERS: readonly CredentialProviderCard[] = [
385385 ...SECONDARY_CREDENTIAL_PROVIDERS ,
386386] ;
387387
388- const CredentialSeeded = type ( {
389- kind : "'seeded'" ,
388+ /** What every provisioning-aware onboarding route answers with
389+ * (CL-6457). `ready` means the bench's agents are all live;
390+ * `provisioning` means connecting succeeded and the agents are still
391+ * coming online in the background — both are success, and the wizard
392+ * moves the person forward either way. */
393+ const CredentialConnected = type ( {
394+ kind : "'ready' | 'provisioning'" ,
390395 "tenantId?" : "string" ,
391396 tenantSlug : "string" ,
392- workflows : "string[]" ,
397+ deployed : "string[]" ,
398+ pending : "string[]" ,
393399} ) ;
394400
395401export type CredentialOutcome =
396402 | {
397- readonly kind : "seeded " ;
403+ readonly kind : "connected " ;
398404 /** Absent only for a response older than this field existing --
399405 * every current `/complete` response carries it. The wizard itself
400406 * no longer branches on it (CL-6104 dropped the optional "Connect
401407 * your tools" phase this once fed) — it stays parsed because the
402408 * server response carries it regardless. */
403409 readonly tenantId ?: string ;
404410 readonly tenantSlug : string ;
405- readonly workflows : string [ ] ;
411+ /** Whether this account's agents still have deploying left to do.
412+ * The wizard does not wait on it — it decides whether the next
413+ * screen shows the warm "getting your agents ready" state. */
414+ readonly agentsPending : boolean ;
406415 }
407416 | {
408417 readonly kind : "rejected" ;
@@ -484,41 +493,44 @@ export async function submitCredential(
484493 ? { kind : "error" , message }
485494 : { kind : "error" , message, refId } ;
486495 }
487- const parsed = CredentialSeeded ( body ) ;
496+ const parsed = CredentialConnected ( body ) ;
488497 if ( parsed instanceof type . errors ) {
489498 return { kind : "error" , message : FALLBACK_ERROR_MESSAGE } ;
490499 }
500+ const agentsPending = parsed . pending . length > 0 ;
491501 return parsed . tenantId === undefined
492502 ? {
493- kind : "seeded " ,
503+ kind : "connected " ,
494504 tenantSlug : parsed . tenantSlug ,
495- workflows : parsed . workflows ,
505+ agentsPending ,
496506 }
497507 : {
498- kind : "seeded " ,
508+ kind : "connected " ,
499509 tenantId : parsed . tenantId ,
500510 tenantSlug : parsed . tenantSlug ,
501- workflows : parsed . workflows ,
511+ agentsPending ,
502512 } ;
503513 } catch {
504514 return { kind : "error" , message : FALLBACK_ERROR_MESSAGE } ;
505515 }
506516}
507517
508518const CompleteSetupResult = type ( {
509- kind : "'seeded ' | 'unseeded'" ,
519+ kind : "'ready' | 'provisioning ' | 'unseeded'" ,
510520 "tenantId?" : "string" ,
511521 "tenantSlug?" : "string" ,
512- "workflows?" : "string[]" ,
522+ "deployed?" : "string[]" ,
523+ "pending?" : "string[]" ,
513524} ) ;
514525
515526export type CompleteSetupOutcome =
516527 | {
517- readonly kind : "seeded " ;
528+ readonly kind : "connected " ;
518529 /** See `CredentialOutcome`'s own note on this field. */
519530 readonly tenantId ?: string ;
520531 readonly tenantSlug : string ;
521- readonly workflows : string [ ] ;
532+ /** See `CredentialOutcome.agentsPending`. */
533+ readonly agentsPending : boolean ;
522534 }
523535 | { readonly kind : "unseeded" }
524536 | {
@@ -554,22 +566,64 @@ export async function completeSetup(): Promise<CompleteSetupOutcome> {
554566 return { kind : "error" , message : FALLBACK_ERROR_MESSAGE } ;
555567 }
556568 if ( parsed . kind === "unseeded" ) return { kind : "unseeded" } ;
557- if ( parsed . tenantSlug === undefined || parsed . workflows === undefined ) {
569+ if ( parsed . tenantSlug === undefined || parsed . pending === undefined ) {
558570 return { kind : "error" , message : FALLBACK_ERROR_MESSAGE } ;
559571 }
572+ const agentsPending = parsed . pending . length > 0 ;
560573 return parsed . tenantId === undefined
561574 ? {
562- kind : "seeded " ,
575+ kind : "connected " ,
563576 tenantSlug : parsed . tenantSlug ,
564- workflows : parsed . workflows ,
577+ agentsPending ,
565578 }
566579 : {
567- kind : "seeded " ,
580+ kind : "connected " ,
568581 tenantId : parsed . tenantId ,
569582 tenantSlug : parsed . tenantSlug ,
570- workflows : parsed . workflows ,
583+ agentsPending ,
571584 } ;
572585 } catch {
573586 return { kind : "error" , message : FALLBACK_ERROR_MESSAGE } ;
574587 }
575588}
589+
590+ const ProvisioningStatus = type ( {
591+ kind : "'ready' | 'provisioning'" ,
592+ deployed : "string[]" ,
593+ pending : "string[]" ,
594+ } ) ;
595+
596+ export type ProvisioningProgress = {
597+ readonly ready : boolean ;
598+ /** How many of this bench's agents are live, and how many there are in
599+ * total — the numbers a waiting surface shows so the wait reads as
600+ * progress rather than a frozen label. */
601+ readonly live : number ;
602+ readonly total : number ;
603+ } ;
604+
605+ /**
606+ * Where this account's agents stand right now. Cheap and read-only, so a
607+ * surface that has to wait may poll it on a short interval. An
608+ * unreachable or unparseable answer reports "not ready yet" rather than
609+ * throwing: a hiccup in a progress check must never turn into an error
610+ * screen over work that is, in fact, still progressing fine.
611+ */
612+ export async function fetchProvisioningProgress ( ) : Promise < ProvisioningProgress > {
613+ try {
614+ const response = await fetch ( "/api/onboarding/provisioning-status" ) ;
615+ const body : unknown = await response . json ( ) . catch ( ( ) => null ) ;
616+ if ( ! response . ok ) return { ready : false , live : 0 , total : 0 } ;
617+ const parsed = ProvisioningStatus ( body ) ;
618+ if ( parsed instanceof type . errors ) {
619+ return { ready : false , live : 0 , total : 0 } ;
620+ }
621+ return {
622+ ready : parsed . kind === "ready" ,
623+ live : parsed . deployed . length ,
624+ total : parsed . deployed . length + parsed . pending . length ,
625+ } ;
626+ } catch {
627+ return { ready : false , live : 0 , total : 0 } ;
628+ }
629+ }
0 commit comments