@nanocollective/nanocoder
Version:
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
70 lines • 3.44 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Box, Text, useInput } from 'ink';
import Spinner from 'ink-spinner';
import { useEffect, useState } from 'react';
import { runCopilotLoginFlow } from '../auth/github-copilot.js';
import { getColors } from '../config/index.js';
const DEFAULT_PROVIDER_NAME = 'GitHub Copilot';
export function CopilotLogin({ providerName = DEFAULT_PROVIDER_NAME, onDone, }) {
const colors = getColors();
const [status, setStatus] = useState('starting');
const [verificationUri, setVerificationUri] = useState('');
const [userCode, setUserCode] = useState('');
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
(async () => {
try {
await runCopilotLoginFlow(providerName, {
onShowCode(uri, code) {
if (cancelled)
return;
setVerificationUri(uri);
setUserCode(code);
setStatus('visit');
},
onPollingStart() {
if (!cancelled)
setStatus('polling');
},
delayBeforePollMs: 500,
});
if (!cancelled) {
setStatus('done');
}
}
catch (err) {
if (!cancelled) {
setError(err instanceof Error ? err.message : String(err));
setStatus('error');
}
}
})();
return () => {
cancelled = true;
};
}, [providerName]);
// Allow user to dismiss with Enter when done or on error
useInput((_input, key) => {
if (key.return && status === 'done') {
onDone?.({ success: true });
}
else if (key.return && status === 'error') {
onDone?.({ success: false, error: error ?? undefined });
}
});
if (status === 'starting') {
return (_jsx(Box, { flexDirection: "column", paddingY: 1, children: _jsxs(Text, { color: colors.primary, children: [_jsx(Spinner, { type: "dots" }), " Starting GitHub Copilot login\u2026"] }) }));
}
if (status === 'visit' || status === 'polling') {
return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Text, { bold: true, children: "Visit this URL and enter the code:" }), _jsx(Text, { color: colors.primary, children: verificationUri }), _jsxs(Text, { bold: true, children: ["Code: ", userCode] }), status === 'polling' && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.primary, children: [_jsx(Spinner, { type: "dots" }), " Waiting for you to complete login\u2026"] }) }))] }));
}
if (status === 'done') {
return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsxs(Text, { color: "green", children: ["Logged in. Credential saved for \"", providerName, "\"."] }), _jsx(Text, { dimColor: true, children: "Press Enter to continue." })] }));
}
if (status === 'error') {
return (_jsxs(Box, { flexDirection: "column", paddingY: 1, children: [_jsx(Text, { color: "red", children: error }), _jsx(Text, { dimColor: true, children: "Press Enter to continue." })] }));
}
return null;
}
//# sourceMappingURL=copilot-login.js.map