#!/usr/bin/env node
import React, { useState, useEffect } from "react";
import { render, Box, Text, useInput } from "ink";
import { startAuthServer, getAccessToken } from "./auth-server.js";
import open from "open";
import TerminalInterface from "./TerminalInterface.js";
const GITHUB_LOGIN_URL =
process.env.GITHUB_LOGIN_URL || "http://localhost:3000/api/auth/github/login";
const CustomInput: React.FC<{ onSubmit: () => void }> = ({ onSubmit }) => {
const [input, setInput] = useState("");
const [isSubmitted, setIsSubmitted] = useState(false);
useInput((inputChar, key) => {
if (isSubmitted) return;
if (key.return) {
setIsSubmitted(true);
onSubmit();
} else if (key.backspace || key.delete) {
setInput((prev) => prev.slice(0, -1));
} else if (inputChar) {
setInput((prev) => prev + inputChar);
}
});
if (isSubmitted) return null;
return (
> {input}
);
};
const App: React.FC = () => {
const [authPrompt, setAuthPrompt] = useState(null);
const [authInput, setAuthInput] = useState("");
const [message, setMessage] = useState(null);
const [exit, setExit] = useState(false);
const [authStarted, setAuthStarted] = useState(false);
const [isLoggedIn, setIsLoggedIn] = useState(false);
// On mount, check for existing token
useEffect(() => {
const token = getAccessToken();
if (token) {
setIsLoggedIn(true);
}
}, []);
// Poll for token after auth flow starts
useEffect(() => {
if (authStarted && !isLoggedIn) {
const interval = setInterval(() => {
const token = getAccessToken();
if (token) {
setIsLoggedIn(true);
clearInterval(interval);
}
}, 1000);
return () => clearInterval(interval);
}
}, [authStarted, isLoggedIn]);
// Handle yes/no input for auth prompt
useInput((input, key) => {
if (authPrompt === null && !isLoggedIn) {
if (key.return) {
if (authInput.toLowerCase() === "y") {
setAuthPrompt(true);
} else if (authInput.toLowerCase() === "n") {
setAuthPrompt(false);
setExit(true);
}
} else if (key.backspace || key.delete) {
setAuthInput((prev) => prev.slice(0, -1));
} else if (input && authInput.length < 1) {
// Only allow a single character (y/n)
setAuthInput(input);
}
}
});
// Exit the process safely after render
useEffect(() => {
if (exit) {
process.exit(0);
}
}, [exit]);
// Start auth server and open browser when user says yes
useEffect(() => {
if (authPrompt === true && !authStarted) {
setAuthStarted(true);
startAuthServer();
open(GITHUB_LOGIN_URL);
}
}, [authPrompt, authStarted]);
if (isLoggedIn) {
return (
setMessage(null)}
CustomInput={CustomInput}
/>
logged in
);
}
if (authPrompt === null) {
return (
LangChain Open SWE CLI
Do you want to start the GitHub authentication flow? (y/n){" "}
{authInput}
);
}
return (
LangChain Open SWE CLI
{!message && setMessage(null)} />}
{message && (
You typed: {message}
)}
);
};
render();