@siteboon/claude-code-ui 1.18.2 → 1.19.1

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
@@ -1886,6 +1886,9 @@ async function getFileTree(dirPath, maxDepth = 3, currentDepth = 0, showHidden =
1886
1886
  }
1887
1887
 
1888
1888
  const PORT = process.env.PORT || 3001;
1889
+ const HOST = process.env.HOST || '0.0.0.0';
1890
+ // Show localhost in URL when binding to all interfaces (0.0.0.0 isn't a connectable address)
1891
+ const DISPLAY_HOST = HOST === '0.0.0.0' ? 'localhost' : HOST;
1889
1892
 
1890
1893
  // Initialize database and start server
1891
1894
  async function startServer() {
@@ -1905,7 +1908,7 @@ async function startServer() {
1905
1908
  console.log(`${c.warn('[WARN]')} Note: Requests will be proxied to Vite dev server at ${c.dim('http://localhost:' + (process.env.VITE_PORT || 5173))}`);
1906
1909
  }
1907
1910
 
1908
- server.listen(PORT, '0.0.0.0', async () => {
1911
+ server.listen(PORT, HOST, async () => {
1909
1912
  const appInstallPath = path.join(__dirname, '..');
1910
1913
 
1911
1914
  console.log('');
@@ -1913,7 +1916,7 @@ async function startServer() {
1913
1916
  console.log(` ${c.bright('Claude Code UI Server - Ready')}`);
1914
1917
  console.log(c.dim('═'.repeat(63)));
1915
1918
  console.log('');
1916
- console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://0.0.0.0:' + PORT)}`);
1919
+ console.log(`${c.info('[INFO]')} Server URL: ${c.bright('http://' + DISPLAY_HOST + ':' + PORT)}`);
1917
1920
  console.log(`${c.info('[INFO]')} Installed at: ${c.dim(appInstallPath)}`);
1918
1921
  console.log(`${c.tip('[TIP]')} Run "cloudcli status" for full configuration details`);
1919
1922
  console.log('');
@@ -889,22 +889,81 @@ async function parseJsonlSessions(filePath) {
889
889
  }
890
890
  }
891
891
 
892
+ // Parse an agent JSONL file and extract tool uses
893
+ async function parseAgentTools(filePath) {
894
+ const tools = [];
895
+
896
+ try {
897
+ const fileStream = fsSync.createReadStream(filePath);
898
+ const rl = readline.createInterface({
899
+ input: fileStream,
900
+ crlfDelay: Infinity
901
+ });
902
+
903
+ for await (const line of rl) {
904
+ if (line.trim()) {
905
+ try {
906
+ const entry = JSON.parse(line);
907
+ // Look for assistant messages with tool_use
908
+ if (entry.message?.role === 'assistant' && Array.isArray(entry.message?.content)) {
909
+ for (const part of entry.message.content) {
910
+ if (part.type === 'tool_use') {
911
+ tools.push({
912
+ toolId: part.id,
913
+ toolName: part.name,
914
+ toolInput: part.input,
915
+ timestamp: entry.timestamp
916
+ });
917
+ }
918
+ }
919
+ }
920
+ // Look for tool results
921
+ if (entry.message?.role === 'user' && Array.isArray(entry.message?.content)) {
922
+ for (const part of entry.message.content) {
923
+ if (part.type === 'tool_result') {
924
+ // Find the matching tool and add result
925
+ const tool = tools.find(t => t.toolId === part.tool_use_id);
926
+ if (tool) {
927
+ tool.toolResult = {
928
+ content: typeof part.content === 'string' ? part.content :
929
+ Array.isArray(part.content) ? part.content.map(c => c.text || '').join('\n') :
930
+ JSON.stringify(part.content),
931
+ isError: Boolean(part.is_error)
932
+ };
933
+ }
934
+ }
935
+ }
936
+ }
937
+ } catch (parseError) {
938
+ // Skip malformed lines
939
+ }
940
+ }
941
+ }
942
+ } catch (error) {
943
+ console.warn(`Error parsing agent file ${filePath}:`, error.message);
944
+ }
945
+
946
+ return tools;
947
+ }
948
+
892
949
  // Get messages for a specific session with pagination support
893
950
  async function getSessionMessages(projectName, sessionId, limit = null, offset = 0) {
894
951
  const projectDir = path.join(os.homedir(), '.claude', 'projects', projectName);
895
952
 
896
953
  try {
897
954
  const files = await fs.readdir(projectDir);
898
- // agent-*.jsonl files contain session start data at this point. This needs to be revisited
899
- // periodically to make sure only accurate data is there and no new functionality is added there
955
+ // agent-*.jsonl files contain subagent tool history - we'll process them separately
900
956
  const jsonlFiles = files.filter(file => file.endsWith('.jsonl') && !file.startsWith('agent-'));
901
-
957
+ const agentFiles = files.filter(file => file.endsWith('.jsonl') && file.startsWith('agent-'));
958
+
902
959
  if (jsonlFiles.length === 0) {
903
960
  return { messages: [], total: 0, hasMore: false };
904
961
  }
905
-
962
+
906
963
  const messages = [];
907
-
964
+ // Map of agentId -> tools for subagent tool grouping
965
+ const agentToolsCache = new Map();
966
+
908
967
  // Process all JSONL files to find messages for this session
909
968
  for (const file of jsonlFiles) {
910
969
  const jsonlFile = path.join(projectDir, file);
@@ -913,7 +972,7 @@ async function getSessionMessages(projectName, sessionId, limit = null, offset =
913
972
  input: fileStream,
914
973
  crlfDelay: Infinity
915
974
  });
916
-
975
+
917
976
  for await (const line of rl) {
918
977
  if (line.trim()) {
919
978
  try {
@@ -927,26 +986,55 @@ async function getSessionMessages(projectName, sessionId, limit = null, offset =
927
986
  }
928
987
  }
929
988
  }
930
-
989
+
990
+ // Collect agentIds from Task tool results
991
+ const agentIds = new Set();
992
+ for (const message of messages) {
993
+ if (message.toolUseResult?.agentId) {
994
+ agentIds.add(message.toolUseResult.agentId);
995
+ }
996
+ }
997
+
998
+ // Load agent tools for each agentId found
999
+ for (const agentId of agentIds) {
1000
+ const agentFileName = `agent-${agentId}.jsonl`;
1001
+ if (agentFiles.includes(agentFileName)) {
1002
+ const agentFilePath = path.join(projectDir, agentFileName);
1003
+ const tools = await parseAgentTools(agentFilePath);
1004
+ agentToolsCache.set(agentId, tools);
1005
+ }
1006
+ }
1007
+
1008
+ // Attach agent tools to their parent Task messages
1009
+ for (const message of messages) {
1010
+ if (message.toolUseResult?.agentId) {
1011
+ const agentId = message.toolUseResult.agentId;
1012
+ const agentTools = agentToolsCache.get(agentId);
1013
+ if (agentTools && agentTools.length > 0) {
1014
+ message.subagentTools = agentTools;
1015
+ }
1016
+ }
1017
+ }
1018
+
931
1019
  // Sort messages by timestamp
932
- const sortedMessages = messages.sort((a, b) =>
1020
+ const sortedMessages = messages.sort((a, b) =>
933
1021
  new Date(a.timestamp || 0) - new Date(b.timestamp || 0)
934
1022
  );
935
-
1023
+
936
1024
  const total = sortedMessages.length;
937
-
1025
+
938
1026
  // If no limit is specified, return all messages (backward compatibility)
939
1027
  if (limit === null) {
940
1028
  return sortedMessages;
941
1029
  }
942
-
1030
+
943
1031
  // Apply pagination - for recent messages, we need to slice from the end
944
1032
  // offset 0 should give us the most recent messages
945
1033
  const startIndex = Math.max(0, total - offset - limit);
946
1034
  const endIndex = total - offset;
947
1035
  const paginatedMessages = sortedMessages.slice(startIndex, endIndex);
948
1036
  const hasMore = startIndex > 0;
949
-
1037
+
950
1038
  return {
951
1039
  messages: paginatedMessages,
952
1040
  total,
@@ -63,5 +63,5 @@ export const CODEX_MODELS = {
63
63
  { value: 'o4-mini', label: 'O4-mini' }
64
64
  ],
65
65
 
66
- DEFAULT: 'gpt-5.2'
66
+ DEFAULT: 'gpt-5.3-codex'
67
67
  };