diff --git a/package-lock.json b/package-lock.json index 9fc5868..9a527b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@siteboon/claude-code-ui", - "version": "1.10.3", + "version": "1.10.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@siteboon/claude-code-ui", - "version": "1.10.3", + "version": "1.10.4", "license": "MIT", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.29", diff --git a/server/index.js b/server/index.js index 8ab26d7..9a39a5d 100755 --- a/server/index.js +++ b/server/index.js @@ -237,6 +237,71 @@ app.get('/api/config', authenticateToken, (req, res) => { }); }); +// System update endpoint +app.post('/api/system/update', authenticateToken, async (req, res) => { + try { + // Get the project root directory (parent of server directory) + const projectRoot = path.join(__dirname, '..'); + + console.log('Starting system update from directory:', projectRoot); + + // Run the update command + const updateCommand = 'git checkout main && git pull && npm install'; + + const child = spawn('sh', ['-c', updateCommand], { + cwd: projectRoot, + env: process.env + }); + + let output = ''; + let errorOutput = ''; + + child.stdout.on('data', (data) => { + const text = data.toString(); + output += text; + console.log('Update output:', text); + }); + + child.stderr.on('data', (data) => { + const text = data.toString(); + errorOutput += text; + console.error('Update error:', text); + }); + + child.on('close', (code) => { + if (code === 0) { + res.json({ + success: true, + output: output || 'Update completed successfully', + message: 'Update completed. Please restart the server to apply changes.' + }); + } else { + res.status(500).json({ + success: false, + error: 'Update command failed', + output: output, + errorOutput: errorOutput + }); + } + }); + + child.on('error', (error) => { + console.error('Update process error:', error); + res.status(500).json({ + success: false, + error: error.message + }); + }); + + } catch (error) { + console.error('System update error:', error); + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + app.get('/api/projects', authenticateToken, async (req, res) => { try { const projects = await getProjects(); diff --git a/src/App.jsx b/src/App.jsx index d6aac09..c018dc3 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -42,7 +42,7 @@ function AppContent() { const navigate = useNavigate(); const { sessionId } = useParams(); - const { updateAvailable, latestVersion, currentVersion } = useVersionCheck('siteboon', 'claudecodeui'); + const { updateAvailable, latestVersion, currentVersion, releaseInfo } = useVersionCheck('siteboon', 'claudecodeui'); const [showVersionModal, setShowVersionModal] = useState(false); const [projects, setProjects] = useState([]); @@ -536,8 +536,60 @@ function AppContent() { // Version Upgrade Modal Component const VersionUpgradeModal = () => { + const [isUpdating, setIsUpdating] = useState(false); + const [updateOutput, setUpdateOutput] = useState(''); + const [updateError, setUpdateError] = useState(''); + if (!showVersionModal) return null; + // Clean up changelog by removing GitHub-specific metadata + const cleanChangelog = (body) => { + if (!body) return ''; + + return body + // Remove full commit hashes (40 character hex strings) + .replace(/\b[0-9a-f]{40}\b/gi, '') + // Remove short commit hashes (7-10 character hex strings at start of line or after dash/space) + .replace(/(?:^|\s|-)([0-9a-f]{7,10})\b/gi, '') + // Remove "Full Changelog" links + .replace(/\*\*Full Changelog\*\*:.*$/gim, '') + // Remove compare links (e.g., https://github.com/.../compare/v1.0.0...v1.0.1) + .replace(/https?:\/\/github\.com\/[^\/]+\/[^\/]+\/compare\/[^\s)]+/gi, '') + // Clean up multiple consecutive empty lines + .replace(/\n\s*\n\s*\n/g, '\n\n') + // Trim whitespace + .trim(); + }; + + const handleUpdateNow = async () => { + setIsUpdating(true); + setUpdateOutput('Starting update...\n'); + setUpdateError(''); + + try { + // Call the backend API to run the update command + const response = await authenticatedFetch('/api/system/update', { + method: 'POST', + }); + + const data = await response.json(); + + if (response.ok) { + setUpdateOutput(prev => prev + data.output + '\n'); + setUpdateOutput(prev => prev + '\n✅ Update completed successfully!\n'); + setUpdateOutput(prev => prev + 'Please restart the server to apply changes.\n'); + } else { + setUpdateError(data.error || 'Update failed'); + setUpdateOutput(prev => prev + '\n❌ Update failed: ' + (data.error || 'Unknown error') + '\n'); + } + } catch (error) { + setUpdateError(error.message); + setUpdateOutput(prev => prev + '\n❌ Update failed: ' + error.message + '\n'); + } finally { + setIsUpdating(false); + } + }; + return (
A new version is ready
++ {releaseInfo?.title || 'A new version is ready'} +
- git checkout main && git pull && npm install
-
+ {/* Changelog */}
+ {releaseInfo?.body && (
+ - Run this command in your Claude Code UI directory to update to the latest version. -
-{updateOutput}
+
+ git checkout main && git pull && npm install
+
+ + Or click "Update Now" to run the update automatically. +
+