({ onDone }: { onDone: LocalJSXCommandOnDone })
| 69 | type Step = { name: 'checking' } | { name: 'confirm'; token: RedactedGithubToken } | { name: 'uploading' }; |
| 70 | |
| 71 | function Web({ onDone }: { onDone: LocalJSXCommandOnDone }) { |
| 72 | const [step, setStep] = useState<Step>({ name: 'checking' }); |
| 73 | |
| 74 | useEffect(() => { |
| 75 | logEvent('tengu_remote_setup_started', {}); |
| 76 | void checkLoginState().then(async result => { |
| 77 | switch (result.status) { |
| 78 | case 'not_signed_in': |
| 79 | logEvent('tengu_remote_setup_result', { |
| 80 | result: 'not_signed_in' as SafeString, |
| 81 | }); |
| 82 | onDone('Not signed in to Claude. Run /login first.'); |
| 83 | return; |
| 84 | case 'gh_not_installed': |
| 85 | case 'gh_not_authenticated': { |
| 86 | const url = `${getCodeWebUrl()}/onboarding?step=alt-auth`; |
| 87 | await openBrowser(url); |
| 88 | logEvent('tengu_remote_setup_result', { |
| 89 | result: result.status as SafeString, |
| 90 | }); |
| 91 | onDone( |
| 92 | result.status === 'gh_not_installed' |
| 93 | ? `GitHub CLI not found. Install it via https://cli.github.com/, then run \`gh auth login\`, or connect GitHub on the web: ${url}` |
| 94 | : `GitHub CLI not authenticated. Run \`gh auth login\` and try again, or connect GitHub on the web: ${url}`, |
| 95 | ); |
| 96 | return; |
| 97 | } |
| 98 | case 'has_gh_token': |
| 99 | setStep({ name: 'confirm', token: result.token }); |
| 100 | } |
| 101 | }); |
| 102 | // onDone is stable across renders; intentionally not in deps. |
| 103 | // eslint-disable-next-line react-hooks/exhaustive-deps |
| 104 | }, []); |
| 105 | |
| 106 | const handleCancel = () => { |
| 107 | logEvent('tengu_remote_setup_result', { |
| 108 | result: 'cancelled' as SafeString, |
| 109 | }); |
| 110 | onDone(); |
| 111 | }; |
| 112 | |
| 113 | const handleConfirm = async (token: RedactedGithubToken) => { |
| 114 | setStep({ name: 'uploading' }); |
| 115 | |
| 116 | const result = await importGithubToken(token); |
| 117 | if (!result.ok) { |
| 118 | const err = (result as { ok: false; error: ImportTokenError }).error; |
| 119 | logEvent('tengu_remote_setup_result', { |
| 120 | result: 'import_failed' as SafeString, |
| 121 | error_kind: err.kind as SafeString, |
| 122 | }); |
| 123 | onDone(errorMessage(err, getCodeWebUrl())); |
| 124 | return; |
| 125 | } |
| 126 | |
| 127 | // Token import succeeded. Environment creation is best-effort — if it |
| 128 | // fails, the web state machine routes to env-setup on landing, which is |
nothing calls this directly
no test coverage detected