ciRefusalMessage static method
Pure — no I/O — so a unit test on this function alone proves the
refusal decision (CI, no --key → refuse) without a subprocess.
It does not by itself prove run() consults it before constructing
a Dio; that ordering is run()'s first statement, before either
_loginWithKey or _loginWithPassword — the only two places a Dio
gets built — are ever reached.
Implementation
static String? ciRefusalMessage({
required bool isCI,
required bool hasKeyArg,
}) {
if (!isCI || hasKeyArg) return null;
return 'CI detected — refusing to prompt for a password.\n'
' Use `appflight login --key <key>` with a CI-scoped key '
'(see `keys create`) or set APPFLIGHT_API_KEY instead.';
}