Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"scripts": {
"dev": "concurrently --kill-others \"npm run server\" \"npm run client\"",
"server": "node server/index.js",
"client": "vite --host",
"client": "vite",
"build": "vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit -p tsconfig.json",
Expand Down
63 changes: 47 additions & 16 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,35 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =

const PORT = process.env.PORT || 3001;

async function listenWithBestAvailableHost(port) {
return new Promise((resolve, reject) => {
const tryListen = (listenOptions, fallbackOptions = null) => {
const handleError = (error) => {
server.off('error', handleError);

if (fallbackOptions && (error.code === 'EAFNOSUPPORT' || error.code === 'EINVAL')) {
console.warn(`${c.warn('[WARN]')} IPv6 bind unavailable, falling back to IPv4`);
tryListen(fallbackOptions, null);
return;
}

reject(error);
};

server.once('error', handleError);
server.listen(listenOptions, () => {
server.off('error', handleError);
resolve(listenOptions);
});
};

tryListen(
{ port, host: '::', ipv6Only: false },
{ port, host: '0.0.0.0' }
);
});
}

// Initialize database and start server
async function startServer() {
try {
Expand All @@ -1905,22 +1934,24 @@ async function startServer() {
console.log(`${c.warn('[WARN]')} Note: Requests will be proxied to Vite dev server at ${c.dim('http://localhost:' + (process.env.VITE_PORT || 5173))}`);
}

server.listen(PORT, '0.0.0.0', async () => {
const appInstallPath = path.join(__dirname, '..');

console.log('');
console.log(c.dim('═'.repeat(63)));
console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
console.log(c.dim('═'.repeat(63)));
console.log('');
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://0.0.0.0:' + PORT)}`);
console.log(`${c.info('[INFO]')} Installed at: ${c.dim(appInstallPath)}`);
console.log(`${c.tip('[TIP]')} Run "cloudcli status" for full configuration details`);
console.log('');

// Start watching the projects folder for changes
await setupProjectsWatcher();
});
const listenOptions = await listenWithBestAvailableHost(PORT);
const appInstallPath = path.join(__dirname, '..');
const listenHostDisplay = listenOptions.host.includes(':')
? `[${listenOptions.host}]`
: listenOptions.host;

console.log('');
console.log(c.dim('═'.repeat(63)));
console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
console.log(c.dim('═'.repeat(63)));
console.log('');
console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + listenHostDisplay + ':' + PORT)}`);
console.log(`${c.info('[INFO]')} Installed at: ${c.dim(appInstallPath)}`);
console.log(`${c.tip('[TIP]')} Run "cloudcli status" for full configuration details`);
console.log('');

// Start watching the projects folder for changes
await setupProjectsWatcher();
} catch (error) {
console.error('[ERROR] Failed to start server:', error);
process.exit(1);
Expand Down
1 change: 1 addition & 0 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default defineConfig(({ command, mode }) => {
return {
plugins: [react()],
server: {
host: env.VITE_HOST || '::',
port: parseInt(env.VITE_PORT) || 5173,
proxy: {
'/api': `http://localhost:${env.PORT || 3001}`,
Expand Down