mirror of
https://github.com/siteboon/claudecodeui.git
synced 2025-12-10 11:09:38 +00:00
- Upgrading to Vite 7
- Refactor to use es modules - Added permission mode - Switched to better sqlite3 - several UX enhancements
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
const { spawn } = require('child_process');
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
let activeClaudeProcesses = new Map(); // Track active processes by session ID
|
||||
|
||||
async function spawnClaude(command, options = {}, ws) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { sessionId, projectPath, cwd, resume, toolsSettings } = options;
|
||||
const { sessionId, projectPath, cwd, resume, toolsSettings, permissionMode } = options;
|
||||
let capturedSessionId = sessionId; // Track session ID throughout the process
|
||||
let sessionCreatedSent = false; // Track if we've already sent session-created event
|
||||
|
||||
@@ -36,15 +36,38 @@ async function spawnClaude(command, options = {}, ws) {
|
||||
args.push('--model', 'sonnet');
|
||||
}
|
||||
|
||||
// Add permission mode if specified (works for both new and resumed sessions)
|
||||
if (permissionMode && permissionMode !== 'default') {
|
||||
args.push('--permission-mode', permissionMode);
|
||||
console.log('🔒 Using permission mode:', permissionMode);
|
||||
}
|
||||
|
||||
// Add tools settings flags
|
||||
if (settings.skipPermissions) {
|
||||
// Don't use --dangerously-skip-permissions when in plan mode
|
||||
if (settings.skipPermissions && permissionMode !== 'plan') {
|
||||
args.push('--dangerously-skip-permissions');
|
||||
console.log('⚠️ Using --dangerously-skip-permissions (skipping other tool settings)');
|
||||
} else {
|
||||
// Only add allowed/disallowed tools if not skipping permissions
|
||||
|
||||
// Collect all allowed tools, including plan mode defaults
|
||||
let allowedTools = [...(settings.allowedTools || [])];
|
||||
|
||||
// Add plan mode specific tools
|
||||
if (permissionMode === 'plan') {
|
||||
const planModeTools = ['Read', 'Task', 'exit_plan_mode', 'TodoRead', 'TodoWrite'];
|
||||
// Add plan mode tools that aren't already in the allowed list
|
||||
for (const tool of planModeTools) {
|
||||
if (!allowedTools.includes(tool)) {
|
||||
allowedTools.push(tool);
|
||||
}
|
||||
}
|
||||
console.log('📝 Plan mode: Added default allowed tools:', planModeTools);
|
||||
}
|
||||
|
||||
// Add allowed tools
|
||||
if (settings.allowedTools && settings.allowedTools.length > 0) {
|
||||
for (const tool of settings.allowedTools) {
|
||||
if (allowedTools.length > 0) {
|
||||
for (const tool of allowedTools) {
|
||||
args.push('--allowedTools', tool);
|
||||
console.log('✅ Allowing tool:', tool);
|
||||
}
|
||||
@@ -57,6 +80,11 @@ async function spawnClaude(command, options = {}, ws) {
|
||||
console.log('❌ Disallowing tool:', tool);
|
||||
}
|
||||
}
|
||||
|
||||
// Log when skip permissions is disabled due to plan mode
|
||||
if (settings.skipPermissions && permissionMode === 'plan') {
|
||||
console.log('📝 Skip permissions disabled due to plan mode');
|
||||
}
|
||||
}
|
||||
|
||||
// Use cwd (actual project directory) instead of projectPath (Claude's metadata directory)
|
||||
@@ -201,7 +229,7 @@ function abortClaudeSession(sessionId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
spawnClaude,
|
||||
abortClaudeSession
|
||||
};
|
||||
@@ -1,99 +1,85 @@
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
import Database from 'better-sqlite3';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const DB_PATH = path.join(__dirname, 'auth.db');
|
||||
const INIT_SQL_PATH = path.join(__dirname, 'init.sql');
|
||||
|
||||
// Create database connection
|
||||
const db = new sqlite3.Database(DB_PATH, (err) => {
|
||||
if (err) {
|
||||
console.error('Error opening database:', err.message);
|
||||
} else {
|
||||
console.log('Connected to SQLite database');
|
||||
}
|
||||
});
|
||||
const db = new Database(DB_PATH);
|
||||
console.log('Connected to SQLite database');
|
||||
|
||||
// Initialize database with schema
|
||||
const initializeDatabase = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const initSQL = fs.readFileSync(INIT_SQL_PATH, 'utf8');
|
||||
db.exec(initSQL, (err) => {
|
||||
if (err) {
|
||||
console.error('Error initializing database:', err.message);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log('Database initialized successfully');
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error reading init SQL file:', error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
try {
|
||||
const initSQL = fs.readFileSync(INIT_SQL_PATH, 'utf8');
|
||||
db.exec(initSQL);
|
||||
console.log('Database initialized successfully');
|
||||
} catch (error) {
|
||||
console.error('Error initializing database:', error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// User database operations
|
||||
const userDb = {
|
||||
// Check if any users exist
|
||||
hasUsers: () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get('SELECT COUNT(*) as count FROM users', (err, row) => {
|
||||
if (err) reject(err);
|
||||
else resolve(row.count > 0);
|
||||
});
|
||||
});
|
||||
try {
|
||||
const row = db.prepare('SELECT COUNT(*) as count FROM users').get();
|
||||
return row.count > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Create a new user
|
||||
createUser: (username, passwordHash) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const stmt = db.prepare('INSERT INTO users (username, password_hash) VALUES (?, ?)');
|
||||
stmt.run(username, passwordHash, function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({ id: this.lastID, username });
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
});
|
||||
const result = stmt.run(username, passwordHash);
|
||||
return { id: result.lastInsertRowid, username };
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Get user by username
|
||||
getUserByUsername: (username) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get('SELECT * FROM users WHERE username = ? AND is_active = 1', [username], (err, row) => {
|
||||
if (err) reject(err);
|
||||
else resolve(row);
|
||||
});
|
||||
});
|
||||
try {
|
||||
const row = db.prepare('SELECT * FROM users WHERE username = ? AND is_active = 1').get(username);
|
||||
return row;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Update last login time
|
||||
updateLastLogin: (userId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?', [userId], (err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
try {
|
||||
db.prepare('UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?').run(userId);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Get user by ID
|
||||
getUserById: (userId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.get('SELECT id, username, created_at, last_login FROM users WHERE id = ? AND is_active = 1', [userId], (err, row) => {
|
||||
if (err) reject(err);
|
||||
else resolve(row);
|
||||
});
|
||||
});
|
||||
try {
|
||||
const row = db.prepare('SELECT id, username, created_at, last_login FROM users WHERE id = ? AND is_active = 1').get(userId);
|
||||
return row;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
db,
|
||||
initializeDatabase,
|
||||
userDb
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
// Load environment variables from .env file
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
try {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const envPath = path.join(__dirname, '../.env');
|
||||
const envFile = fs.readFileSync(envPath, 'utf8');
|
||||
envFile.split('\n').forEach(line => {
|
||||
@@ -19,31 +25,31 @@ try {
|
||||
|
||||
console.log('PORT from env:', process.env.PORT);
|
||||
|
||||
const express = require('express');
|
||||
const { WebSocketServer } = require('ws');
|
||||
const http = require('http');
|
||||
const path = require('path');
|
||||
const cors = require('cors');
|
||||
const fs = require('fs').promises;
|
||||
const { spawn } = require('child_process');
|
||||
const os = require('os');
|
||||
const pty = require('node-pty');
|
||||
const fetch = require('node-fetch');
|
||||
import express from 'express';
|
||||
import { WebSocketServer } from 'ws';
|
||||
import http from 'http';
|
||||
import cors from 'cors';
|
||||
import { promises as fsPromises } from 'fs';
|
||||
import { spawn } from 'child_process';
|
||||
import os from 'os';
|
||||
import pty from 'node-pty';
|
||||
import fetch from 'node-fetch';
|
||||
import mime from 'mime-types';
|
||||
|
||||
const { getProjects, getSessions, getSessionMessages, renameProject, deleteSession, deleteProject, addProjectManually, extractProjectDirectory, clearProjectDirectoryCache } = require('./projects');
|
||||
const { spawnClaude, abortClaudeSession } = require('./claude-cli');
|
||||
const gitRoutes = require('./routes/git');
|
||||
const authRoutes = require('./routes/auth');
|
||||
const { initializeDatabase } = require('./database/db');
|
||||
const { validateApiKey, authenticateToken, authenticateWebSocket } = require('./middleware/auth');
|
||||
import { getProjects, getSessions, getSessionMessages, renameProject, deleteSession, deleteProject, addProjectManually, extractProjectDirectory, clearProjectDirectoryCache } from './projects.js';
|
||||
import { spawnClaude, abortClaudeSession } from './claude-cli.js';
|
||||
import gitRoutes from './routes/git.js';
|
||||
import authRoutes from './routes/auth.js';
|
||||
import { initializeDatabase } from './database/db.js';
|
||||
import { validateApiKey, authenticateToken, authenticateWebSocket } from './middleware/auth.js';
|
||||
|
||||
// File system watcher for projects folder
|
||||
let projectsWatcher = null;
|
||||
const connectedClients = new Set();
|
||||
|
||||
// Setup file system watcher for Claude projects folder using chokidar
|
||||
function setupProjectsWatcher() {
|
||||
const chokidar = require('chokidar');
|
||||
async function setupProjectsWatcher() {
|
||||
const chokidar = (await import('chokidar')).default;
|
||||
const claudeProjectsPath = path.join(process.env.HOME, '.claude', 'projects');
|
||||
|
||||
if (projectsWatcher) {
|
||||
@@ -283,14 +289,14 @@ app.get('/api/projects/:projectName/file', authenticateToken, async (req, res) =
|
||||
|
||||
console.log('📄 File read request:', projectName, filePath);
|
||||
|
||||
const fs = require('fs').promises;
|
||||
// Using fsPromises from import
|
||||
|
||||
// Security check - ensure the path is safe and absolute
|
||||
if (!filePath || !path.isAbsolute(filePath)) {
|
||||
return res.status(400).json({ error: 'Invalid file path' });
|
||||
}
|
||||
|
||||
const content = await fs.readFile(filePath, 'utf8');
|
||||
const content = await fsPromises.readFile(filePath, 'utf8');
|
||||
res.json({ content, path: filePath });
|
||||
} catch (error) {
|
||||
console.error('Error reading file:', error);
|
||||
@@ -312,8 +318,8 @@ app.get('/api/projects/:projectName/files/content', authenticateToken, async (re
|
||||
|
||||
console.log('🖼️ Binary file serve request:', projectName, filePath);
|
||||
|
||||
const fs = require('fs');
|
||||
const mime = require('mime-types');
|
||||
// Using fs from import
|
||||
// Using mime from import
|
||||
|
||||
// Security check - ensure the path is safe and absolute
|
||||
if (!filePath || !path.isAbsolute(filePath)) {
|
||||
@@ -322,7 +328,7 @@ app.get('/api/projects/:projectName/files/content', authenticateToken, async (re
|
||||
|
||||
// Check if file exists
|
||||
try {
|
||||
await fs.promises.access(filePath);
|
||||
await fsPromises.access(filePath);
|
||||
} catch (error) {
|
||||
return res.status(404).json({ error: 'File not found' });
|
||||
}
|
||||
@@ -358,7 +364,7 @@ app.put('/api/projects/:projectName/file', authenticateToken, async (req, res) =
|
||||
|
||||
console.log('💾 File save request:', projectName, filePath);
|
||||
|
||||
const fs = require('fs').promises;
|
||||
// Using fsPromises from import
|
||||
|
||||
// Security check - ensure the path is safe and absolute
|
||||
if (!filePath || !path.isAbsolute(filePath)) {
|
||||
@@ -372,14 +378,14 @@ app.put('/api/projects/:projectName/file', authenticateToken, async (req, res) =
|
||||
// Create backup of original file
|
||||
try {
|
||||
const backupPath = filePath + '.backup.' + Date.now();
|
||||
await fs.copyFile(filePath, backupPath);
|
||||
await fsPromises.copyFile(filePath, backupPath);
|
||||
console.log('📋 Created backup:', backupPath);
|
||||
} catch (backupError) {
|
||||
console.warn('Could not create backup:', backupError.message);
|
||||
}
|
||||
|
||||
// Write the new content
|
||||
await fs.writeFile(filePath, content, 'utf8');
|
||||
await fsPromises.writeFile(filePath, content, 'utf8');
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
@@ -401,7 +407,7 @@ app.put('/api/projects/:projectName/file', authenticateToken, async (req, res) =
|
||||
app.get('/api/projects/:projectName/files', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
|
||||
const fs = require('fs').promises;
|
||||
// Using fsPromises from import
|
||||
|
||||
// Use extractProjectDirectory to get the actual project path
|
||||
let actualPath;
|
||||
@@ -415,7 +421,7 @@ app.get('/api/projects/:projectName/files', authenticateToken, async (req, res)
|
||||
|
||||
// Check if path exists
|
||||
try {
|
||||
await fs.access(actualPath);
|
||||
await fsPromises.access(actualPath);
|
||||
} catch (e) {
|
||||
return res.status(404).json({ error: `Project path not found: ${actualPath}` });
|
||||
}
|
||||
@@ -662,7 +668,7 @@ function handleShellConnection(ws) {
|
||||
// Audio transcription endpoint
|
||||
app.post('/api/transcribe', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
const multer = require('multer');
|
||||
const multer = (await import('multer')).default;
|
||||
const upload = multer({ storage: multer.memoryStorage() });
|
||||
|
||||
// Handle multipart form data
|
||||
@@ -682,7 +688,7 @@ app.post('/api/transcribe', authenticateToken, async (req, res) => {
|
||||
|
||||
try {
|
||||
// Create form data for OpenAI
|
||||
const FormData = require('form-data');
|
||||
const FormData = (await import('form-data')).default;
|
||||
const formData = new FormData();
|
||||
formData.append('file', req.file.buffer, {
|
||||
filename: req.file.originalname,
|
||||
@@ -725,7 +731,7 @@ app.post('/api/transcribe', authenticateToken, async (req, res) => {
|
||||
|
||||
// Handle different enhancement modes
|
||||
try {
|
||||
const OpenAI = require('openai');
|
||||
const OpenAI = (await import('openai')).default;
|
||||
const openai = new OpenAI({ apiKey });
|
||||
|
||||
let prompt, systemMessage, temperature = 0.7, maxTokens = 800;
|
||||
@@ -815,11 +821,11 @@ app.get('*', (req, res) => {
|
||||
});
|
||||
|
||||
async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden = true) {
|
||||
const fs = require('fs').promises;
|
||||
// Using fsPromises from import
|
||||
const items = [];
|
||||
|
||||
try {
|
||||
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
||||
const entries = await fsPromises.readdir(dirPath, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
// Debug: log all entries including hidden files
|
||||
@@ -840,7 +846,7 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
|
||||
// Recursively get subdirectories but limit depth
|
||||
try {
|
||||
// Check if we can access the directory before trying to read it
|
||||
await fs.access(item.path, fs.constants.R_OK);
|
||||
await fsPromises.access(item.path, fs.constants.R_OK);
|
||||
item.children = await getFileTree(item.path, maxDepth, currentDepth + 1, showHidden);
|
||||
} catch (e) {
|
||||
// Silently skip directories we can't access (permission denied, etc.)
|
||||
@@ -872,13 +878,13 @@ async function startServer() {
|
||||
try {
|
||||
// Initialize authentication database
|
||||
await initializeDatabase();
|
||||
console.log('✅ Database initialized successfully');
|
||||
console.log('✅ Database initialization skipped (testing)');
|
||||
|
||||
server.listen(PORT, '0.0.0.0', () => {
|
||||
server.listen(PORT, '0.0.0.0', async () => {
|
||||
console.log(`Claude Code UI server running on http://0.0.0.0:${PORT}`);
|
||||
|
||||
// Start watching the projects folder for changes
|
||||
setupProjectsWatcher();
|
||||
await setupProjectsWatcher(); // Re-enabled with better-sqlite3
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to start server:', error);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { userDb } = require('../database/db');
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { userDb } from '../database/db.js';
|
||||
|
||||
// Get JWT secret from environment or use default (for development)
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'claude-ui-dev-secret-change-in-production';
|
||||
@@ -31,7 +31,7 @@ const authenticateToken = async (req, res, next) => {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
|
||||
// Verify user still exists and is active
|
||||
const user = await userDb.getUserById(decoded.userId);
|
||||
const user = userDb.getUserById(decoded.userId);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid token. User not found.' });
|
||||
}
|
||||
@@ -71,7 +71,7 @@ const authenticateWebSocket = (token) => {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
validateApiKey,
|
||||
authenticateToken,
|
||||
generateToken,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const readline = require('readline');
|
||||
import { promises as fs } from 'fs';
|
||||
import fsSync from 'fs';
|
||||
import path from 'path';
|
||||
import readline from 'readline';
|
||||
|
||||
// Cache for extracted project directories
|
||||
const projectDirectoryCache = new Map();
|
||||
@@ -91,7 +92,7 @@ async function extractProjectDirectory(projectName) {
|
||||
// Process all JSONL files to collect cwd values
|
||||
for (const file of jsonlFiles) {
|
||||
const jsonlFile = path.join(projectDir, file);
|
||||
const fileStream = require('fs').createReadStream(jsonlFile);
|
||||
const fileStream = fsSync.createReadStream(jsonlFile);
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity
|
||||
@@ -325,7 +326,7 @@ async function parseJsonlSessions(filePath) {
|
||||
const sessions = new Map();
|
||||
|
||||
try {
|
||||
const fileStream = require('fs').createReadStream(filePath);
|
||||
const fileStream = fsSync.createReadStream(filePath);
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity
|
||||
@@ -409,7 +410,7 @@ async function getSessionMessages(projectName, sessionId) {
|
||||
// Process all JSONL files to find messages for this session
|
||||
for (const file of jsonlFiles) {
|
||||
const jsonlFile = path.join(projectDir, file);
|
||||
const fileStream = require('fs').createReadStream(jsonlFile);
|
||||
const fileStream = fsSync.createReadStream(jsonlFile);
|
||||
const rl = readline.createInterface({
|
||||
input: fileStream,
|
||||
crlfDelay: Infinity
|
||||
@@ -601,7 +602,7 @@ async function addProjectManually(projectPath, displayName = null) {
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
getProjects,
|
||||
getSessions,
|
||||
getSessionMessages,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const express = require('express');
|
||||
const bcrypt = require('bcrypt');
|
||||
const { userDb } = require('../database/db');
|
||||
const { generateToken, authenticateToken } = require('../middleware/auth');
|
||||
import express from 'express';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { userDb } from '../database/db.js';
|
||||
import { generateToken, authenticateToken } from '../middleware/auth.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -34,7 +34,7 @@ router.post('/register', async (req, res) => {
|
||||
}
|
||||
|
||||
// Check if users already exist (only allow one user)
|
||||
const hasUsers = await userDb.hasUsers();
|
||||
const hasUsers = userDb.hasUsers();
|
||||
if (hasUsers) {
|
||||
return res.status(403).json({ error: 'User already exists. This is a single-user system.' });
|
||||
}
|
||||
@@ -44,13 +44,13 @@ router.post('/register', async (req, res) => {
|
||||
const passwordHash = await bcrypt.hash(password, saltRounds);
|
||||
|
||||
// Create user
|
||||
const user = await userDb.createUser(username, passwordHash);
|
||||
const user = userDb.createUser(username, passwordHash);
|
||||
|
||||
// Generate token
|
||||
const token = generateToken(user);
|
||||
|
||||
// Update last login
|
||||
await userDb.updateLastLogin(user.id);
|
||||
userDb.updateLastLogin(user.id);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
@@ -79,7 +79,7 @@ router.post('/login', async (req, res) => {
|
||||
}
|
||||
|
||||
// Get user from database
|
||||
const user = await userDb.getUserByUsername(username);
|
||||
const user = userDb.getUserByUsername(username);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid username or password' });
|
||||
}
|
||||
@@ -94,7 +94,7 @@ router.post('/login', async (req, res) => {
|
||||
const token = generateToken(user);
|
||||
|
||||
// Update last login
|
||||
await userDb.updateLastLogin(user.id);
|
||||
userDb.updateLastLogin(user.id);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
@@ -122,4 +122,4 @@ router.post('/logout', authenticateToken, (req, res) => {
|
||||
res.json({ success: true, message: 'Logged out successfully' });
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
export default router;
|
||||
@@ -1,9 +1,9 @@
|
||||
const express = require('express');
|
||||
const { exec } = require('child_process');
|
||||
const { promisify } = require('util');
|
||||
const path = require('path');
|
||||
const fs = require('fs').promises;
|
||||
const { extractProjectDirectory } = require('../projects');
|
||||
import express from 'express';
|
||||
import { exec } from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import path from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { extractProjectDirectory } from '../projects.js';
|
||||
|
||||
const router = express.Router();
|
||||
const execAsync = promisify(exec);
|
||||
@@ -420,4 +420,4 @@ function generateSimpleCommitMessage(files, diff) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = router;
|
||||
export default router;
|
||||
Reference in New Issue
Block a user