99 *
1010 * Retry policy:
1111 * - If the process produced any output (hasOutput) and exits with a non-zero code, the
12- * session is considered partially executed. The driver retries with --resume so the
12+ * session is considered partially executed. The driver retries with --continue so the
1313 * Copilot CLI can continue from where it left off.
1414 * - CAPIError 400 is a well-known transient failure mode and is logged explicitly, but
1515 * any partial-execution failure is retried — not just CAPIError 400.
1616 * - If the process produced no output (failed to start / auth error before any work), the
1717 * driver does not retry because there is nothing to resume.
18+ * - "No authentication information found" errors are non-retryable: the absent token will
19+ * remain absent on every subsequent attempt, so all further retries will also fail.
1820 * - Retries use exponential backoff: 5s → 10s → 20s (capped at 60s).
1921 * - Maximum 3 retry attempts after the initial run.
2022 *
@@ -43,6 +45,11 @@ const CAPI_ERROR_400_PATTERN = /CAPIError:\s*400/;
4345// This is a persistent policy configuration error — retrying will not help.
4446const MCP_POLICY_BLOCKED_PATTERN = / M C P s e r v e r s w e r e b l o c k e d b y p o l i c y : / ;
4547
48+ // Pattern to detect missing authentication credentials.
49+ // This error means no auth token is available in the environment; retrying will not help
50+ // because the missing token will still be absent on every subsequent attempt.
51+ const NO_AUTH_INFO_PATTERN = / N o a u t h e n t i c a t i o n i n f o r m a t i o n f o u n d / ;
52+
4653/**
4754 * Emit a timestamped diagnostic log line to stderr.
4855 * All driver messages are prefixed with "[copilot-driver]" so they are easy to
@@ -73,6 +80,17 @@ function isMCPPolicyError(output) {
7380 return MCP_POLICY_BLOCKED_PATTERN . test ( output ) ;
7481}
7582
83+ /**
84+ * Determines if the collected output contains a "No authentication information found" error.
85+ * This means no auth token (COPILOT_GITHUB_TOKEN, GH_TOKEN, or GITHUB_TOKEN) is available
86+ * in the environment. Retrying will not help because the absent token will remain absent.
87+ * @param {string } output - Collected stdout+stderr from the process
88+ * @returns {boolean }
89+ */
90+ function isNoAuthInfoError ( output ) {
91+ return NO_AUTH_INFO_PATTERN . test ( output ) ;
92+ }
93+
7694/**
7795 * Sleep for a specified duration
7896 * @param {number } ms - Duration in milliseconds
@@ -221,11 +239,11 @@ async function main() {
221239 const driverStartTime = Date . now ( ) ;
222240
223241 for ( let attempt = 0 ; attempt <= MAX_RETRIES ; attempt ++ ) {
224- // Add --resume flag on retries so the copilot session resumes from where it left off
225- const currentArgs = attempt > 0 ? [ ...args , "--resume " ] : args ;
242+ // Add --continue flag on retries so the copilot session continues from where it left off
243+ const currentArgs = attempt > 0 ? [ ...args , "--continue " ] : args ;
226244
227245 if ( attempt > 0 ) {
228- log ( `retry ${ attempt } /${ MAX_RETRIES } : sleeping ${ delay } ms before next attempt with --resume ` ) ;
246+ log ( `retry ${ attempt } /${ MAX_RETRIES } : sleeping ${ delay } ms before next attempt with --continue ` ) ;
229247 await sleep ( delay ) ;
230248 delay = Math . min ( delay * BACKOFF_MULTIPLIER , MAX_DELAY_MS ) ;
231249 log ( `retry ${ attempt } /${ MAX_RETRIES } : woke up, next delay cap will be ${ Math . min ( delay * BACKOFF_MULTIPLIER , MAX_DELAY_MS ) } ms` ) ;
@@ -241,23 +259,40 @@ async function main() {
241259 }
242260
243261 // Determine whether to retry.
244- // Retry whenever the session was partially executed (hasOutput), using --resume so that
262+ // Retry whenever the session was partially executed (hasOutput), using --continue so that
245263 // the Copilot CLI can continue from where it left off. CAPIError 400 is the well-known
246- // transient case, but any partial-execution failure is eligible for a resume retry.
247- // Exception : MCP policy errors are persistent configuration issues — never retry.
264+ // transient case, but any partial-execution failure is eligible for a continue retry.
265+ // Exceptions : MCP policy errors and auth errors are persistent — never retry.
248266 const isCAPIError = isTransientCAPIError ( result . output ) ;
249267 const isMCPPolicy = isMCPPolicyError ( result . output ) ;
250- log ( `attempt ${ attempt + 1 } failed:` + ` exitCode=${ result . exitCode } ` + ` isCAPIError400=${ isCAPIError } ` + ` isMCPPolicyError=${ isMCPPolicy } ` + ` hasOutput=${ result . hasOutput } ` + ` retriesRemaining=${ MAX_RETRIES - attempt } ` ) ;
268+ const isAuthErr = isNoAuthInfoError ( result . output ) ;
269+ log (
270+ `attempt ${ attempt + 1 } failed:` +
271+ ` exitCode=${ result . exitCode } ` +
272+ ` isCAPIError400=${ isCAPIError } ` +
273+ ` isMCPPolicyError=${ isMCPPolicy } ` +
274+ ` isAuthError=${ isAuthErr } ` +
275+ ` hasOutput=${ result . hasOutput } ` +
276+ ` retriesRemaining=${ MAX_RETRIES - attempt } `
277+ ) ;
251278
252279 // MCP policy errors are persistent — retrying will not help.
253280 if ( isMCPPolicy ) {
254281 log ( `attempt ${ attempt + 1 } : MCP servers blocked by policy — not retrying (this is a policy configuration issue, not a transient error)` ) ;
255282 break ;
256283 }
257284
285+ // Auth errors are persistent for the duration of the job — retrying will not help.
286+ // "No authentication information found" means COPILOT_GITHUB_TOKEN / GH_TOKEN / GITHUB_TOKEN
287+ // are all absent or invalid. Retrying with --continue will produce the same auth failure.
288+ if ( isAuthErr ) {
289+ log ( `attempt ${ attempt + 1 } : no authentication information found — not retrying (COPILOT_GITHUB_TOKEN, GH_TOKEN, and GITHUB_TOKEN are all absent or invalid)` ) ;
290+ break ;
291+ }
292+
258293 if ( attempt < MAX_RETRIES && result . hasOutput ) {
259294 const reason = isCAPIError ? "CAPIError 400 (transient)" : "partial execution" ;
260- log ( `attempt ${ attempt + 1 } : ${ reason } — will retry with --resume (attempt ${ attempt + 2 } /${ MAX_RETRIES + 1 } )` ) ;
295+ log ( `attempt ${ attempt + 1 } : ${ reason } — will retry with --continue (attempt ${ attempt + 2 } /${ MAX_RETRIES + 1 } )` ) ;
261296 continue ;
262297 }
263298
0 commit comments