@cloudcli-ai/cloudcli 1.28.0 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/server/index.js CHANGED
@@ -435,13 +435,20 @@ app.post('/api/system/update', authenticateToken, async (req, res) => {
435
435
 
436
436
  console.log('Starting system update from directory:', projectRoot);
437
437
 
438
- // Run the update command based on install mode
439
- const updateCommand = installMode === 'git'
440
- ? 'git checkout main && git pull && npm install'
441
- : 'npm install -g @cloudcli-ai/cloudcli@latest';
438
+ // Platform deployments use their own update workflow from the project root.
439
+ const updateCommand = IS_PLATFORM
440
+ // In platform, husky and dev dependencies are not needed
441
+ ? 'npm run update:platform'
442
+ : installMode === 'git'
443
+ ? 'git checkout main && git pull && npm install'
444
+ : 'npm install -g @cloudcli-ai/cloudcli@latest';
445
+
446
+ const updateCwd = IS_PLATFORM || installMode === 'git'
447
+ ? projectRoot
448
+ : os.homedir();
442
449
 
443
450
  const child = spawn('sh', ['-c', updateCommand], {
444
- cwd: installMode === 'git' ? projectRoot : os.homedir(),
451
+ cwd: updateCwd,
445
452
  env: process.env
446
453
  });
447
454
 
@@ -812,7 +819,7 @@ app.get('/api/projects/:projectName/file', authenticateToken, async (req, res) =
812
819
  }
813
820
  });
814
821
 
815
- // Serve binary file content endpoint (for images, etc.)
822
+ // Serve raw file bytes for previews and downloads.
816
823
  app.get('/api/projects/:projectName/files/content', authenticateToken, async (req, res) => {
817
824
  try {
818
825
  const { projectName } = req.params;
@@ -829,7 +836,11 @@ app.get('/api/projects/:projectName/files/content', authenticateToken, async (re
829
836
  return res.status(404).json({ error: 'Project not found' });
830
837
  }
831
838
 
832
- const resolved = path.resolve(filePath);
839
+ // Match the text reader endpoint so callers can pass either project-relative
840
+ // or absolute paths without changing how the bytes are served.
841
+ const resolved = path.isAbsolute(filePath)
842
+ ? path.resolve(filePath)
843
+ : path.resolve(projectRoot, filePath);
833
844
  const normalizedRoot = path.resolve(projectRoot) + path.sep;
834
845
  if (!resolved.startsWith(normalizedRoot)) {
835
846
  return res.status(403).json({ error: 'Path must be under project root' });
@@ -1980,155 +1991,6 @@ function handleShellConnection(ws) {
1980
1991
  console.error('[ERROR] Shell WebSocket error:', error);
1981
1992
  });
1982
1993
  }
1983
- // Audio transcription endpoint
1984
- app.post('/api/transcribe', authenticateToken, async (req, res) => {
1985
- try {
1986
- const multer = (await import('multer')).default;
1987
- const upload = multer({ storage: multer.memoryStorage() });
1988
-
1989
- // Handle multipart form data
1990
- upload.single('audio')(req, res, async (err) => {
1991
- if (err) {
1992
- return res.status(400).json({ error: 'Failed to process audio file' });
1993
- }
1994
-
1995
- if (!req.file) {
1996
- return res.status(400).json({ error: 'No audio file provided' });
1997
- }
1998
-
1999
- const apiKey = process.env.OPENAI_API_KEY;
2000
- if (!apiKey) {
2001
- return res.status(500).json({ error: 'OpenAI API key not configured. Please set OPENAI_API_KEY in server environment.' });
2002
- }
2003
-
2004
- try {
2005
- // Create form data for OpenAI
2006
- const FormData = (await import('form-data')).default;
2007
- const formData = new FormData();
2008
- formData.append('file', req.file.buffer, {
2009
- filename: req.file.originalname,
2010
- contentType: req.file.mimetype
2011
- });
2012
- formData.append('model', 'whisper-1');
2013
- formData.append('response_format', 'json');
2014
- formData.append('language', 'en');
2015
-
2016
- // Make request to OpenAI
2017
- const response = await fetch('https://api.openai.com/v1/audio/transcriptions', {
2018
- method: 'POST',
2019
- headers: {
2020
- 'Authorization': `Bearer ${apiKey}`,
2021
- ...formData.getHeaders()
2022
- },
2023
- body: formData
2024
- });
2025
-
2026
- if (!response.ok) {
2027
- const errorData = await response.json().catch(() => ({}));
2028
- throw new Error(errorData.error?.message || `Whisper API error: ${response.status}`);
2029
- }
2030
-
2031
- const data = await response.json();
2032
- let transcribedText = data.text || '';
2033
-
2034
- // Check if enhancement mode is enabled
2035
- const mode = req.body.mode || 'default';
2036
-
2037
- // If no transcribed text, return empty
2038
- if (!transcribedText) {
2039
- return res.json({ text: '' });
2040
- }
2041
-
2042
- // If default mode, return transcribed text without enhancement
2043
- if (mode === 'default') {
2044
- return res.json({ text: transcribedText });
2045
- }
2046
-
2047
- // Handle different enhancement modes
2048
- try {
2049
- const OpenAI = (await import('openai')).default;
2050
- const openai = new OpenAI({ apiKey });
2051
-
2052
- let prompt, systemMessage, temperature = 0.7, maxTokens = 800;
2053
-
2054
- switch (mode) {
2055
- case 'prompt':
2056
- systemMessage = 'You are an expert prompt engineer who creates clear, detailed, and effective prompts.';
2057
- prompt = `You are an expert prompt engineer. Transform the following rough instruction into a clear, detailed, and context-aware AI prompt.
2058
-
2059
- Your enhanced prompt should:
2060
- 1. Be specific and unambiguous
2061
- 2. Include relevant context and constraints
2062
- 3. Specify the desired output format
2063
- 4. Use clear, actionable language
2064
- 5. Include examples where helpful
2065
- 6. Consider edge cases and potential ambiguities
2066
-
2067
- Transform this rough instruction into a well-crafted prompt:
2068
- "${transcribedText}"
2069
-
2070
- Enhanced prompt:`;
2071
- break;
2072
-
2073
- case 'vibe':
2074
- case 'instructions':
2075
- case 'architect':
2076
- systemMessage = 'You are a helpful assistant that formats ideas into clear, actionable instructions for AI agents.';
2077
- temperature = 0.5; // Lower temperature for more controlled output
2078
- prompt = `Transform the following idea into clear, well-structured instructions that an AI agent can easily understand and execute.
2079
-
2080
- IMPORTANT RULES:
2081
- - Format as clear, step-by-step instructions
2082
- - Add reasonable implementation details based on common patterns
2083
- - Only include details directly related to what was asked
2084
- - Do NOT add features or functionality not mentioned
2085
- - Keep the original intent and scope intact
2086
- - Use clear, actionable language an agent can follow
2087
-
2088
- Transform this idea into agent-friendly instructions:
2089
- "${transcribedText}"
2090
-
2091
- Agent instructions:`;
2092
- break;
2093
-
2094
- default:
2095
- // No enhancement needed
2096
- break;
2097
- }
2098
-
2099
- // Only make GPT call if we have a prompt
2100
- if (prompt) {
2101
- const completion = await openai.chat.completions.create({
2102
- model: 'gpt-4o-mini',
2103
- messages: [
2104
- { role: 'system', content: systemMessage },
2105
- { role: 'user', content: prompt }
2106
- ],
2107
- temperature: temperature,
2108
- max_tokens: maxTokens
2109
- });
2110
-
2111
- transcribedText = completion.choices[0].message.content || transcribedText;
2112
- }
2113
-
2114
- } catch (gptError) {
2115
- console.error('GPT processing error:', gptError);
2116
- // Fall back to original transcription if GPT fails
2117
- }
2118
-
2119
- res.json({ text: transcribedText });
2120
-
2121
- } catch (error) {
2122
- console.error('Transcription error:', error);
2123
- res.status(500).json({ error: error.message });
2124
- }
2125
- });
2126
- } catch (error) {
2127
- console.error('Endpoint error:', error);
2128
- res.status(500).json({ error: 'Internal server error' });
2129
- }
2130
- });
2131
-
2132
1994
  // Image upload endpoint
2133
1995
  app.post('/api/projects/:projectName/upload-images', authenticateToken, async (req, res) => {
2134
1996
  try {
@@ -2544,7 +2406,7 @@ async function startServer() {
2544
2406
 
2545
2407
  console.log('');
2546
2408
  console.log(c.dim('═'.repeat(63)));
2547
- console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
2409
+ console.log(` ${c.bright('CloudCLI Server - Ready')}`);
2548
2410
  console.log(c.dim('═'.repeat(63)));
2549
2411
  console.log('');
2550
2412
  console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + SERVER_PORT)}`);
@@ -1125,7 +1125,7 @@ router.post('/', validateExternalApiKey, async (req, res) => {
1125
1125
  } else {
1126
1126
  prBody += `Agent task: ${message}`;
1127
1127
  }
1128
- prBody += '\n\n---\n*This pull request was automatically created by Claude Code UI Agent.*';
1128
+ prBody += '\n\n---\n*This pull request was automatically created by CloudCLI.ai Agent.*';
1129
1129
 
1130
1130
  console.log(`📝 PR Title: ${prTitle}`);
1131
1131
 
@@ -125,7 +125,7 @@ function buildPushBody(event) {
125
125
  const message = CODE_MAP[event.code] || 'You have a new notification';
126
126
 
127
127
  return {
128
- title: sessionName || 'Claude Code UI',
128
+ title: sessionName || 'CloudCLI',
129
129
  body: `${providerLabel}: ${message}`,
130
130
  data: {
131
131
  sessionId: event.sessionId || null,